|
diff --git a/stdlib/json.lua b/stdlib/json.lua
|
| ... |
| 31 |
local encode |
31 |
local encode |
| 32 |
|
32 |
|
| 33 |
local escape_char_map = { |
33 |
local escape_char_map = { |
| 34 |
[ "\\" ] = "\\", |
34 |
[ "\\" ] = "\\", |
| 35 |
[ "\"" ] = "\"", |
35 |
[ "\"" ] = "\"", |
| 36 |
[ "\b" ] = "b", |
36 |
[ "\b" ] = "b", |
| 37 |
[ "\f" ] = "f", |
37 |
[ "\f" ] = "f", |
| 38 |
[ "\n" ] = "n", |
38 |
[ "\n" ] = "n", |
| 39 |
[ "\r" ] = "r", |
39 |
[ "\r" ] = "r", |
| 40 |
[ "\t" ] = "t", |
40 |
[ "\t" ] = "t", |
| 41 |
} |
41 |
} |
| 42 |
|
42 |
|
| 43 |
local escape_char_map_inv = { [ "/" ] = "/" } |
43 |
local escape_char_map_inv = { [ "/" ] = "/" } |
| 44 |
for k, v in pairs(escape_char_map) do |
44 |
for k, v in pairs(escape_char_map) do |
| 45 |
escape_char_map_inv[v] = k |
45 |
escape_char_map_inv[v] = k |
| 46 |
end |
46 |
end |
| 47 |
|
47 |
|
| 48 |
|
|
|
| 49 |
local function escape_char(c) |
48 |
local function escape_char(c) |
| 50 |
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) |
49 |
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) |
| 51 |
end |
50 |
end |
| 52 |
|
|
|
| 53 |
|
51 |
|
| 54 |
local function encode_nil(val) |
52 |
local function encode_nil(val) |
| 55 |
return "null" |
53 |
return "null" |
| 56 |
end |
54 |
end |
| 57 |
|
55 |
|
| 58 |
|
|
|
| 59 |
local function encode_table(val, stack) |
56 |
local function encode_table(val, stack) |
| 60 |
local res = {} |
57 |
local res = {} |
| 61 |
stack = stack or {} |
58 |
stack = stack or {} |
| 62 |
|
59 |
|
| 63 |
-- Circular reference? |
60 |
-- Circular reference? |
| 64 |
if stack[val] then error("circular reference") end |
61 |
if stack[val] then error("circular reference") end |
| 65 |
|
62 |
|
| 66 |
stack[val] = true |
63 |
stack[val] = true |
| 67 |
|
64 |
|
| 68 |
if rawget(val, 1) ~= nil or next(val) == nil then |
65 |
if rawget(val, 1) ~= nil or next(val) == nil then |
| 69 |
-- Treat as array -- check keys are valid and it is not sparse |
66 |
-- Treat as array -- check keys are valid and it is not sparse |
| 70 |
local n = 0 |
67 |
local n = 0 |
| 71 |
for k in pairs(val) do |
68 |
for k in pairs(val) do |
| 72 |
if type(k) ~= "number" then |
69 |
if type(k) ~= "number" then |
| 73 |
error("invalid table: mixed or invalid key types") |
70 |
error("invalid table: mixed or invalid key types") |
| 74 |
end |
71 |
end |
| 75 |
n = n + 1 |
72 |
n = n + 1 |
| 76 |
end |
73 |
end |
| 77 |
if n ~= #val then |
74 |
if n ~= #val then |
| 78 |
error("invalid table: sparse array") |
75 |
error("invalid table: sparse array") |
| 79 |
end |
76 |
end |
| 80 |
-- Encode |
77 |
-- Encode |
| 81 |
for i, v in ipairs(val) do |
78 |
for i, v in ipairs(val) do |
| 82 |
table.insert(res, encode(v, stack)) |
79 |
table.insert(res, encode(v, stack)) |
| 83 |
end |
80 |
end |
| 84 |
stack[val] = nil |
81 |
stack[val] = nil |
| 85 |
return "[" .. table.concat(res, ",") .. "]" |
82 |
return "[" .. table.concat(res, ",") .. "]" |
| 86 |
|
83 |
|
| 87 |
else |
84 |
else |
| 88 |
-- Treat as an object |
85 |
-- Treat as an object |
| 89 |
for k, v in pairs(val) do |
86 |
for k, v in pairs(val) do |
| 90 |
if type(k) ~= "string" then |
87 |
if type(k) ~= "string" then |
| 91 |
error("invalid table: mixed or invalid key types") |
88 |
error("invalid table: mixed or invalid key types") |
| 92 |
end |
89 |
end |
| 93 |
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) |
90 |
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) |
| 94 |
end |
91 |
end |
| 95 |
stack[val] = nil |
92 |
stack[val] = nil |
| 96 |
return "{" .. table.concat(res, ",") .. "}" |
93 |
return "{" .. table.concat(res, ",") .. "}" |
| 97 |
end |
94 |
end |
| 98 |
end |
95 |
end |
| 99 |
|
96 |
|
| 100 |
|
|
|
| 101 |
local function encode_string(val) |
97 |
local function encode_string(val) |
| 102 |
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' |
98 |
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' |
| 103 |
end |
99 |
end |
| 104 |
|
100 |
|
| 105 |
|
|
|
| 106 |
local function encode_number(val) |
101 |
local function encode_number(val) |
| 107 |
-- Check for NaN, -inf and inf |
102 |
-- Check for NaN, -inf and inf |
| 108 |
if val ~= val or val <= -math.huge or val >= math.huge then |
103 |
if val ~= val or val <= -math.huge or val >= math.huge then |
| 109 |
error("unexpected number value '" .. tostring(val) .. "'") |
104 |
error("unexpected number value '" .. tostring(val) .. "'") |
| 110 |
end |
105 |
end |
| 111 |
return string.format("%.14g", val) |
106 |
return string.format("%.14g", val) |
| 112 |
end |
107 |
end |
| 113 |
|
|
|
| 114 |
|
108 |
|
| 115 |
local type_func_map = { |
109 |
local type_func_map = { |
| 116 |
[ "nil" ] = encode_nil, |
110 |
[ "nil" ] = encode_nil, |
| 117 |
[ "table" ] = encode_table, |
111 |
[ "table" ] = encode_table, |
| 118 |
[ "string" ] = encode_string, |
112 |
[ "string" ] = encode_string, |
| 119 |
[ "number" ] = encode_number, |
113 |
[ "number" ] = encode_number, |
| 120 |
[ "boolean" ] = tostring, |
114 |
[ "boolean" ] = tostring, |
| 121 |
} |
115 |
} |
| 122 |
|
116 |
|
| 123 |
|
|
|
| 124 |
encode = function(val, stack) |
117 |
encode = function(val, stack) |
| 125 |
local t = type(val) |
118 |
local t = type(val) |
| 126 |
local f = type_func_map[t] |
119 |
local f = type_func_map[t] |
| 127 |
if f then |
120 |
if f then |
| 128 |
return f(val, stack) |
121 |
return f(val, stack) |
| 129 |
end |
122 |
end |
| 130 |
error("unexpected type '" .. t .. "'") |
123 |
error("unexpected type '" .. t .. "'") |
| 131 |
end |
124 |
end |
| 132 |
|
125 |
|
| 133 |
|
|
|
| 134 |
function json.encode(val) |
126 |
function json.encode(val) |
| 135 |
return ( encode(val) ) |
127 |
return ( encode(val) ) |
| 136 |
end |
128 |
end |
| 137 |
|
|
|
| 138 |
|
129 |
|
| 139 |
------------------------------------------------------------------------------- |
130 |
------------------------------------------------------------------------------- |
| 140 |
-- Decode |
131 |
-- Decode |
| ... |
| 143 |
local parse |
134 |
local parse |
| 144 |
|
135 |
|
| 145 |
local function create_set(...) |
136 |
local function create_set(...) |
| 146 |
local res = {} |
137 |
local res = {} |
| 147 |
for i = 1, select("#", ...) do |
138 |
for i = 1, select("#", ...) do |
| 148 |
res[ select(i, ...) ] = true |
139 |
res[ select(i, ...) ] = true |
| 149 |
end |
140 |
end |
| 150 |
return res |
141 |
return res |
| 151 |
end |
142 |
end |
| 152 |
|
143 |
|
| 153 |
local space_chars = create_set(" ", "\t", "\r", "\n") |
144 |
local space_chars = create_set(" ", "\t", "\r", "\n") |
| ... |
| 156 |
local literals = create_set("true", "false", "null") |
147 |
local literals = create_set("true", "false", "null") |
| 157 |
|
148 |
|
| 158 |
local literal_map = { |
149 |
local literal_map = { |
| 159 |
[ "true" ] = true, |
150 |
[ "true" ] = true, |
| 160 |
[ "false" ] = false, |
151 |
[ "false" ] = false, |
| 161 |
[ "null" ] = nil, |
152 |
[ "null" ] = nil, |
| 162 |
} |
153 |
} |
| 163 |
|
154 |
|
| 164 |
|
|
|
| 165 |
local function next_char(str, idx, set, negate) |
155 |
local function next_char(str, idx, set, negate) |
| 166 |
for i = idx, #str do |
156 |
for i = idx, #str do |
| 167 |
if set[str:sub(i, i)] ~= negate then |
157 |
if set[str:sub(i, i)] ~= negate then |
| 168 |
return i |
158 |
return i |
| 169 |
end |
159 |
end |
| 170 |
end |
160 |
end |
| 171 |
return #str + 1 |
161 |
return #str + 1 |
| 172 |
end |
162 |
end |
| 173 |
|
|
|
| 174 |
|
163 |
|
| 175 |
local function decode_error(str, idx, msg) |
164 |
local function decode_error(str, idx, msg) |
| 176 |
local line_count = 1 |
165 |
local line_count = 1 |
| 177 |
local col_count = 1 |
166 |
local col_count = 1 |
| 178 |
for i = 1, idx - 1 do |
167 |
for i = 1, idx - 1 do |
| 179 |
col_count = col_count + 1 |
168 |
col_count = col_count + 1 |
| 180 |
if str:sub(i, i) == "\n" then |
169 |
if str:sub(i, i) == "\n" then |
| 181 |
line_count = line_count + 1 |
170 |
line_count = line_count + 1 |
| 182 |
col_count = 1 |
171 |
col_count = 1 |
| 183 |
end |
172 |
end |
| 184 |
end |
173 |
end |
| 185 |
error( string.format("%s at line %d col %d", msg, line_count, col_count) ) |
174 |
error( string.format("%s at line %d col %d", msg, line_count, col_count) ) |
| 186 |
end |
175 |
end |
| 187 |
|
176 |
|
| 188 |
|
|
|
| 189 |
local function codepoint_to_utf8(n) |
177 |
local function codepoint_to_utf8(n) |
| 190 |
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa |
178 |
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa |
| 191 |
local f = math.floor |
179 |
local f = math.floor |
| 192 |
if n <= 0x7f then |
180 |
if n <= 0x7f then |
| 193 |
return string.char(n) |
181 |
return string.char(n) |
| 194 |
elseif n <= 0x7ff then |
182 |
elseif n <= 0x7ff then |
| 195 |
return string.char(f(n / 64) + 192, n % 64 + 128) |
183 |
return string.char(f(n / 64) + 192, n % 64 + 128) |
| 196 |
elseif n <= 0xffff then |
184 |
elseif n <= 0xffff then |
| 197 |
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) |
185 |
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) |
| 198 |
elseif n <= 0x10ffff then |
186 |
elseif n <= 0x10ffff then |
| 199 |
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, |
187 |
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, |
| 200 |
f(n % 4096 / 64) + 128, n % 64 + 128) |
188 |
f(n % 4096 / 64) + 128, n % 64 + 128) |
| 201 |
end |
189 |
end |
| 202 |
error( string.format("invalid unicode codepoint '%x'", n) ) |
190 |
error( string.format("invalid unicode codepoint '%x'", n) ) |
| 203 |
end |
191 |
end |
| 204 |
|
192 |
|
| 205 |
|
|
|
| 206 |
local function parse_unicode_escape(s) |
193 |
local function parse_unicode_escape(s) |
| 207 |
local n1 = tonumber( s:sub(1, 4), 16 ) |
194 |
local n1 = tonumber( s:sub(1, 4), 16 ) |
| 208 |
local n2 = tonumber( s:sub(7, 10), 16 ) |
195 |
local n2 = tonumber( s:sub(7, 10), 16 ) |
| 209 |
-- Surrogate pair? |
196 |
-- Surrogate pair? |
| 210 |
if n2 then |
197 |
if n2 then |
| 211 |
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) |
198 |
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) |
| 212 |
else |
199 |
else |
| 213 |
return codepoint_to_utf8(n1) |
200 |
return codepoint_to_utf8(n1) |
| 214 |
end |
201 |
end |
| 215 |
end |
202 |
end |
| 216 |
|
203 |
|
| 217 |
|
|
|
| 218 |
local function parse_string(str, i) |
204 |
local function parse_string(str, i) |
| 219 |
local res = "" |
205 |
local res = "" |
| 220 |
local j = i + 1 |
206 |
local j = i + 1 |
| 221 |
local k = j |
207 |
local k = j |
| 222 |
|
208 |
|
| 223 |
while j <= #str do |
209 |
while j <= #str do |
| 224 |
local x = str:byte(j) |
210 |
local x = str:byte(j) |
| 225 |
|
211 |
|
| 226 |
if x < 32 then |
212 |
if x < 32 then |
| 227 |
decode_error(str, j, "control character in string") |
213 |
decode_error(str, j, "control character in string") |
| 228 |
|
214 |
|
| 229 |
elseif x == 92 then -- `\`: Escape |
215 |
elseif x == 92 then -- `\`: Escape |
| 230 |
res = res .. str:sub(k, j - 1) |
216 |
res = res .. str:sub(k, j - 1) |
| 231 |
j = j + 1 |
217 |
j = j + 1 |
| 232 |
local c = str:sub(j, j) |
218 |
local c = str:sub(j, j) |
| 233 |
if c == "u" then |
219 |
if c == "u" then |
| 234 |
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) |
220 |
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) |
| 235 |
or str:match("^%x%x%x%x", j + 1) |
221 |
or str:match("^%x%x%x%x", j + 1) |
| 236 |
or decode_error(str, j - 1, "invalid unicode escape in string") |
222 |
or decode_error(str, j - 1, "invalid unicode escape in string") |
| 237 |
res = res .. parse_unicode_escape(hex) |
223 |
res = res .. parse_unicode_escape(hex) |
| 238 |
j = j + #hex |
224 |
j = j + #hex |
| 239 |
else |
225 |
else |
| 240 |
if not escape_chars[c] then |
226 |
if not escape_chars[c] then |
| 241 |
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") |
227 |
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") |
| 242 |
end |
228 |
end |
| 243 |
res = res .. escape_char_map_inv[c] |
229 |
res = res .. escape_char_map_inv[c] |
| 244 |
end |
230 |
end |
| 245 |
k = j + 1 |
231 |
k = j + 1 |
| 246 |
|
232 |
|
| 247 |
elseif x == 34 then -- `"`: End of string |
233 |
elseif x == 34 then -- `"`: End of string |
| 248 |
res = res .. str:sub(k, j - 1) |
234 |
res = res .. str:sub(k, j - 1) |
| 249 |
return res, j + 1 |
235 |
return res, j + 1 |
| 250 |
end |
236 |
end |
| 251 |
|
237 |
|
| 252 |
j = j + 1 |
238 |
j = j + 1 |
| 253 |
end |
239 |
end |
| 254 |
|
240 |
|
| 255 |
decode_error(str, i, "expected closing quote for string") |
241 |
decode_error(str, i, "expected closing quote for string") |
| 256 |
end |
242 |
end |
| 257 |
|
243 |
|
| 258 |
|
|
|
| 259 |
local function parse_number(str, i) |
244 |
local function parse_number(str, i) |
| 260 |
local x = next_char(str, i, delim_chars) |
245 |
local x = next_char(str, i, delim_chars) |
| 261 |
local s = str:sub(i, x - 1) |
246 |
local s = str:sub(i, x - 1) |
| 262 |
local n = tonumber(s) |
247 |
local n = tonumber(s) |
| 263 |
if not n then |
248 |
if not n then |
| 264 |
decode_error(str, i, "invalid number '" .. s .. "'") |
249 |
decode_error(str, i, "invalid number '" .. s .. "'") |
| 265 |
end |
250 |
end |
| 266 |
return n, x |
251 |
return n, x |
| 267 |
end |
252 |
end |
| 268 |
|
|
|
| 269 |
|
253 |
|
| 270 |
local function parse_literal(str, i) |
254 |
local function parse_literal(str, i) |
| 271 |
local x = next_char(str, i, delim_chars) |
255 |
local x = next_char(str, i, delim_chars) |
| 272 |
local word = str:sub(i, x - 1) |
256 |
local word = str:sub(i, x - 1) |
| 273 |
if not literals[word] then |
257 |
if not literals[word] then |
| 274 |
decode_error(str, i, "invalid literal '" .. word .. "'") |
258 |
decode_error(str, i, "invalid literal '" .. word .. "'") |
| 275 |
end |
259 |
end |
| 276 |
return literal_map[word], x |
260 |
return literal_map[word], x |
| 277 |
end |
261 |
end |
| 278 |
|
|
|
| 279 |
|
262 |
|
| 280 |
local function parse_array(str, i) |
263 |
local function parse_array(str, i) |
| 281 |
local res = {} |
264 |
local res = {} |
| 282 |
local n = 1 |
265 |
local n = 1 |
| 283 |
i = i + 1 |
266 |
i = i + 1 |
| 284 |
while 1 do |
267 |
while 1 do |
| 285 |
local x |
268 |
local x |
| 286 |
i = next_char(str, i, space_chars, true) |
269 |
i = next_char(str, i, space_chars, true) |
| 287 |
-- Empty / end of array? |
270 |
-- Empty / end of array? |
| 288 |
if str:sub(i, i) == "]" then |
271 |
if str:sub(i, i) == "]" then |
| 289 |
i = i + 1 |
272 |
i = i + 1 |
| 290 |
break |
273 |
break |
| 291 |
end |
274 |
end |
| 292 |
-- Read token |
275 |
-- Read token |
| 293 |
x, i = parse(str, i) |
276 |
x, i = parse(str, i) |
| 294 |
res[n] = x |
277 |
res[n] = x |
| 295 |
n = n + 1 |
278 |
n = n + 1 |
| 296 |
-- Next token |
279 |
-- Next token |
| 297 |
i = next_char(str, i, space_chars, true) |
280 |
i = next_char(str, i, space_chars, true) |
| 298 |
local chr = str:sub(i, i) |
281 |
local chr = str:sub(i, i) |
| 299 |
i = i + 1 |
282 |
i = i + 1 |
| 300 |
if chr == "]" then break end |
283 |
if chr == "]" then break end |
| 301 |
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end |
284 |
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end |
| 302 |
end |
285 |
end |
| 303 |
return res, i |
286 |
return res, i |
| 304 |
end |
287 |
end |
| 305 |
|
|
|
| 306 |
|
288 |
|
| 307 |
local function parse_object(str, i) |
289 |
local function parse_object(str, i) |
| 308 |
local res = {} |
290 |
local res = {} |
| 309 |
i = i + 1 |
291 |
i = i + 1 |
| 310 |
while 1 do |
292 |
while 1 do |
| 311 |
local key, val |
293 |
local key, val |
| 312 |
i = next_char(str, i, space_chars, true) |
294 |
i = next_char(str, i, space_chars, true) |
| 313 |
-- Empty / end of object? |
295 |
-- Empty / end of object? |
| 314 |
if str:sub(i, i) == "}" then |
296 |
if str:sub(i, i) == "}" then |
| 315 |
i = i + 1 |
297 |
i = i + 1 |
| 316 |
break |
298 |
break |
| 317 |
end |
299 |
end |
| 318 |
-- Read key |
300 |
-- Read key |
| 319 |
if str:sub(i, i) ~= '"' then |
301 |
if str:sub(i, i) ~= '"' then |
| 320 |
decode_error(str, i, "expected string for key") |
302 |
decode_error(str, i, "expected string for key") |
| 321 |
end |
303 |
end |
| 322 |
key, i = parse(str, i) |
304 |
key, i = parse(str, i) |
| 323 |
-- Read ':' delimiter |
305 |
-- Read ':' delimiter |
| 324 |
i = next_char(str, i, space_chars, true) |
306 |
i = next_char(str, i, space_chars, true) |
| 325 |
if str:sub(i, i) ~= ":" then |
307 |
if str:sub(i, i) ~= ":" then |
| 326 |
decode_error(str, i, "expected ':' after key") |
308 |
decode_error(str, i, "expected ':' after key") |
| 327 |
end |
309 |
end |
| 328 |
i = next_char(str, i + 1, space_chars, true) |
310 |
i = next_char(str, i + 1, space_chars, true) |
| 329 |
-- Read value |
311 |
-- Read value |
| 330 |
val, i = parse(str, i) |
312 |
val, i = parse(str, i) |
| 331 |
-- Set |
313 |
-- Set |
| 332 |
res[key] = val |
314 |
res[key] = val |
| 333 |
-- Next token |
315 |
-- Next token |
| 334 |
i = next_char(str, i, space_chars, true) |
316 |
i = next_char(str, i, space_chars, true) |
| 335 |
local chr = str:sub(i, i) |
317 |
local chr = str:sub(i, i) |
| 336 |
i = i + 1 |
318 |
i = i + 1 |
| 337 |
if chr == "}" then break end |
319 |
if chr == "}" then break end |
| 338 |
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end |
320 |
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end |
| 339 |
end |
321 |
end |
| 340 |
return res, i |
322 |
return res, i |
| 341 |
end |
323 |
end |
| 342 |
|
|
|
| 343 |
|
324 |
|
| 344 |
local char_func_map = { |
325 |
local char_func_map = { |
| 345 |
[ '"' ] = parse_string, |
326 |
[ '"' ] = parse_string, |
| 346 |
[ "0" ] = parse_number, |
327 |
[ "0" ] = parse_number, |
| 347 |
[ "1" ] = parse_number, |
328 |
[ "1" ] = parse_number, |
| 348 |
[ "2" ] = parse_number, |
329 |
[ "2" ] = parse_number, |
| 349 |
[ "3" ] = parse_number, |
330 |
[ "3" ] = parse_number, |
| 350 |
[ "4" ] = parse_number, |
331 |
[ "4" ] = parse_number, |
| 351 |
[ "5" ] = parse_number, |
332 |
[ "5" ] = parse_number, |
| 352 |
[ "6" ] = parse_number, |
333 |
[ "6" ] = parse_number, |
| 353 |
[ "7" ] = parse_number, |
334 |
[ "7" ] = parse_number, |
| 354 |
[ "8" ] = parse_number, |
335 |
[ "8" ] = parse_number, |
| 355 |
[ "9" ] = parse_number, |
336 |
[ "9" ] = parse_number, |
| 356 |
[ "-" ] = parse_number, |
337 |
[ "-" ] = parse_number, |
| 357 |
[ "t" ] = parse_literal, |
338 |
[ "t" ] = parse_literal, |
| 358 |
[ "f" ] = parse_literal, |
339 |
[ "f" ] = parse_literal, |
| 359 |
[ "n" ] = parse_literal, |
340 |
[ "n" ] = parse_literal, |
| 360 |
[ "[" ] = parse_array, |
341 |
[ "[" ] = parse_array, |
| 361 |
[ "{" ] = parse_object, |
342 |
[ "{" ] = parse_object, |
| 362 |
} |
343 |
} |
| 363 |
|
|
|
| 364 |
|
344 |
|
| 365 |
parse = function(str, idx) |
345 |
parse = function(str, idx) |
| 366 |
local chr = str:sub(idx, idx) |
346 |
local chr = str:sub(idx, idx) |
| 367 |
local f = char_func_map[chr] |
347 |
local f = char_func_map[chr] |
| 368 |
if f then |
348 |
if f then |
| 369 |
return f(str, idx) |
349 |
return f(str, idx) |
| 370 |
end |
350 |
end |
| 371 |
decode_error(str, idx, "unexpected character '" .. chr .. "'") |
351 |
decode_error(str, idx, "unexpected character '" .. chr .. "'") |
| 372 |
end |
352 |
end |
| 373 |
|
|
|
| 374 |
|
353 |
|
| 375 |
function json.decode(str) |
354 |
function json.decode(str) |
| 376 |
if type(str) ~= "string" then |
355 |
if type(str) ~= "string" then |
| 377 |
error("expected argument of type string, got " .. type(str)) |
356 |
error("expected argument of type string, got " .. type(str)) |
| 378 |
end |
357 |
end |
| 379 |
local res, idx = parse(str, next_char(str, 1, space_chars, true)) |
358 |
local res, idx = parse(str, next_char(str, 1, space_chars, true)) |
| 380 |
idx = next_char(str, idx, space_chars, true) |
359 |
idx = next_char(str, idx, space_chars, true) |
| 381 |
if idx <= #str then |
360 |
if idx <= #str then |
| 382 |
decode_error(str, idx, "trailing garbage") |
361 |
decode_error(str, idx, "trailing garbage") |
| 383 |
end |
362 |
end |
| 384 |
return res |
363 |
return res |
| 385 |
end |
364 |
end |
| 386 |
|
|
|
| 387 |
|
365 |
|
| 388 |
return json |
366 |
return json |