2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
5 local lpeg
= require("lpeg")
7 local pairs
, ipairs
= pairs
, ipairs
8 local tonumber = tonumber
9 local string_char
= string.char
12 local setmetatable
= setmetatable
14 module("json.decode.util")
16 -- 09, 0A, 0B, 0C, 0D, 20
17 ascii_space
= lpeg
.S("\t\n\v\f\r ")
19 local chr
= string_char
20 local u_space
= ascii_space
22 u_space
= u_space
+ lpeg
.P(chr(0xC2)) * lpeg
.S(chr(0x85) .. chr(0xA0))
24 u_space
= u_space
+ lpeg
.P(chr(0xE1)) * (lpeg
.P(chr(0x9A, 0x80)) + chr(0xA0, 0x8E))
25 -- \u2000 - \u200A, also 200B
26 local spacing_end
= ""
28 spacing_end
= spacing_end
.. chr(i
)
30 -- \u2028 \u2029 \u202F
31 spacing_end
= spacing_end
.. chr(0xA8) .. chr(0xA9) .. chr(0xAF)
32 u_space
= u_space
+ lpeg
.P(chr(0xE2, 0x80)) * lpeg
.S(spacing_end
)
34 u_space
= u_space
+ lpeg
.P(chr(0xE2, 0x81, 0x9F))
36 u_space
= u_space
+ lpeg
.P(chr(0xE3, 0x80, 0x80))
38 u_space
= u_space
+ lpeg
.P(chr(0xEF, 0xBB, 0xBF))
39 _M
.unicode_space
= u_space
42 identifier
= lpeg
.R("AZ","az","__") * lpeg
.R("AZ","az", "__", "09") ^
0
44 hex
= lpeg
.R("09","AF","af")
48 cpp
= lpeg
.P("//") * (1 - lpeg
.P("\n"))^
0 * lpeg
.P("\n"),
49 c
= lpeg
.P("/*") * (1 - lpeg
.P("*/"))^
0 * lpeg
.P("*/")
52 comment
= comments
.cpp
+ comments
.c
54 ascii_ignored
= (ascii_space
+ comment
)^
0
56 unicode_ignored
= (unicode_space
+ comment
)^
0
58 local types
= setmetatable({false}, {
59 __index
= function(self
, k
)
60 error("Unknown type: " .. k
)
64 function register_type(name
)
65 types
[#types
+ 1] = name
72 function append_grammar_item(grammar
, name
, capture
)
73 local id
= types
[name
]
74 local original
= grammar
[id
]
76 grammar
[id
] = original
+ capture
82 -- Parse the lpeg version skipping patch-values
83 -- LPEG <= 0.7 have no version value... so 0.7 is value
84 DecimalLpegVersion
= lpeg
.version
and tonumber(lpeg
.version():match("^(%d+%.%d+)")) or 0.7
86 function get_invalid_character_info(input
, index
)
87 local parsed
= input
:sub(1, index
)
88 local bad_character
= input
:sub(index
, index
)
89 local _
, line_number
= parsed
:gsub('\n',{})
90 local last_line
= parsed
:match("\n([^\n]+.)$") or parsed
91 return line_number
, #last_line
, bad_character
, last_line