]> git.zerfleddert.de Git - proxmark3-svn/blob - client/lualibs/dkjson.lua
ADD: added dkjson.lua for json support
[proxmark3-svn] / client / lualibs / dkjson.lua
1 -- Module options:
2 local always_try_using_lpeg = true
3 local register_global_module_table = false
4 local global_module_name = 'json'
5
6 --[==[
7
8 David Kolf's JSON module for Lua 5.1/5.2
9
10 Version 2.5
11
12
13 For the documentation see the corresponding readme.txt or visit
14 <http://dkolf.de/src/dkjson-lua.fsl/>.
15
16 You can contact the author by sending an e-mail to 'david' at the
17 domain 'dkolf.de'.
18
19
20 Copyright (C) 2010-2013 David Heiko Kolf
21
22 Permission is hereby granted, free of charge, to any person obtaining
23 a copy of this software and associated documentation files (the
24 "Software"), to deal in the Software without restriction, including
25 without limitation the rights to use, copy, modify, merge, publish,
26 distribute, sublicense, and/or sell copies of the Software, and to
27 permit persons to whom the Software is furnished to do so, subject to
28 the following conditions:
29
30 The above copyright notice and this permission notice shall be
31 included in all copies or substantial portions of the Software.
32
33 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
36 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
37 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
38 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40 SOFTWARE.
41
42 --]==]
43
44 -- global dependencies:
45 local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
46 pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
47 local error, require, pcall, select = error, require, pcall, select
48 local floor, huge = math.floor, math.huge
49 local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
50 string.rep, string.gsub, string.sub, string.byte, string.char,
51 string.find, string.len, string.format
52 local strmatch = string.match
53 local concat = table.concat
54
55 local json = { version = "dkjson 2.5" }
56
57 if register_global_module_table then
58 _G[global_module_name] = json
59 end
60
61 local _ENV = nil -- blocking globals in Lua 5.2
62
63 pcall (function()
64 -- Enable access to blocked metatables.
65 -- Don't worry, this module doesn't change anything in them.
66 local debmeta = require "debug".getmetatable
67 if debmeta then getmetatable = debmeta end
68 end)
69
70 json.null = setmetatable ({}, {
71 __tojson = function () return "null" end
72 })
73
74 local function isarray (tbl)
75 local max, n, arraylen = 0, 0, 0
76 for k,v in pairs (tbl) do
77 if k == 'n' and type(v) == 'number' then
78 arraylen = v
79 if v > max then
80 max = v
81 end
82 else
83 if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
84 return false
85 end
86 if k > max then
87 max = k
88 end
89 n = n + 1
90 end
91 end
92 if max > 10 and max > arraylen and max > n * 2 then
93 return false -- don't create an array with too many holes
94 end
95 return true, max
96 end
97
98 local escapecodes = {
99 ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
100 ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
101 }
102
103 local function escapeutf8 (uchar)
104 local value = escapecodes[uchar]
105 if value then
106 return value
107 end
108 local a, b, c, d = strbyte (uchar, 1, 4)
109 a, b, c, d = a or 0, b or 0, c or 0, d or 0
110 if a <= 0x7f then
111 value = a
112 elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
113 value = (a - 0xc0) * 0x40 + b - 0x80
114 elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
115 value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
116 elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
117 value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
118 else
119 return ""
120 end
121 if value <= 0xffff then
122 return strformat ("\\u%.4x", value)
123 elseif value <= 0x10ffff then
124 -- encode as UTF-16 surrogate pair
125 value = value - 0x10000
126 local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
127 return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
128 else
129 return ""
130 end
131 end
132
133 local function fsub (str, pattern, repl)
134 -- gsub always builds a new string in a buffer, even when no match
135 -- exists. First using find should be more efficient when most strings
136 -- don't contain the pattern.
137 if strfind (str, pattern) then
138 return gsub (str, pattern, repl)
139 else
140 return str
141 end
142 end
143
144 local function quotestring (value)
145 -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
146 value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
147 if strfind (value, "[\194\216\220\225\226\239]") then
148 value = fsub (value, "\194[\128-\159\173]", escapeutf8)
149 value = fsub (value, "\216[\128-\132]", escapeutf8)
150 value = fsub (value, "\220\143", escapeutf8)
151 value = fsub (value, "\225\158[\180\181]", escapeutf8)
152 value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
153 value = fsub (value, "\226\129[\160-\175]", escapeutf8)
154 value = fsub (value, "\239\187\191", escapeutf8)
155 value = fsub (value, "\239\191[\176-\191]", escapeutf8)
156 end
157 return "\"" .. value .. "\""
158 end
159 json.quotestring = quotestring
160
161 local function replace(str, o, n)
162 local i, j = strfind (str, o, 1, true)
163 if i then
164 return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
165 else
166 return str
167 end
168 end
169
170 -- locale independent num2str and str2num functions
171 local decpoint, numfilter
172
173 local function updatedecpoint ()
174 decpoint = strmatch(tostring(0.5), "([^05+])")
175 -- build a filter that can be used to remove group separators
176 numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
177 end
178
179 updatedecpoint()
180
181 local function num2str (num)
182 return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
183 end
184
185 local function str2num (str)
186 local num = tonumber(replace(str, ".", decpoint))
187 if not num then
188 updatedecpoint()
189 num = tonumber(replace(str, ".", decpoint))
190 end
191 return num
192 end
193
194 local function addnewline2 (level, buffer, buflen)
195 buffer[buflen+1] = "\n"
196 buffer[buflen+2] = strrep (" ", level)
197 buflen = buflen + 2
198 return buflen
199 end
200
201 function json.addnewline (state)
202 if state.indent then
203 state.bufferlen = addnewline2 (state.level or 0,
204 state.buffer, state.bufferlen or #(state.buffer))
205 end
206 end
207
208 local encode2 -- forward declaration
209
210 local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
211 local kt = type (key)
212 if kt ~= 'string' and kt ~= 'number' then
213 return nil, "type '" .. kt .. "' is not supported as a key by JSON."
214 end
215 if prev then
216 buflen = buflen + 1
217 buffer[buflen] = ","
218 end
219 if indent then
220 buflen = addnewline2 (level, buffer, buflen)
221 end
222 buffer[buflen+1] = quotestring (key)
223 buffer[buflen+2] = ":"
224 return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
225 end
226
227 local function appendcustom(res, buffer, state)
228 local buflen = state.bufferlen
229 if type (res) == 'string' then
230 buflen = buflen + 1
231 buffer[buflen] = res
232 end
233 return buflen
234 end
235
236 local function exception(reason, value, state, buffer, buflen, defaultmessage)
237 defaultmessage = defaultmessage or reason
238 local handler = state.exception
239 if not handler then
240 return nil, defaultmessage
241 else
242 state.bufferlen = buflen
243 local ret, msg = handler (reason, value, state, defaultmessage)
244 if not ret then return nil, msg or defaultmessage end
245 return appendcustom(ret, buffer, state)
246 end
247 end
248
249 function json.encodeexception(reason, value, state, defaultmessage)
250 return quotestring("<" .. defaultmessage .. ">")
251 end
252
253 encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
254 local valtype = type (value)
255 local valmeta = getmetatable (value)
256 valmeta = type (valmeta) == 'table' and valmeta -- only tables
257 local valtojson = valmeta and valmeta.__tojson
258 if valtojson then
259 if tables[value] then
260 return exception('reference cycle', value, state, buffer, buflen)
261 end
262 tables[value] = true
263 state.bufferlen = buflen
264 local ret, msg = valtojson (value, state)
265 if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
266 tables[value] = nil
267 buflen = appendcustom(ret, buffer, state)
268 elseif value == nil then
269 buflen = buflen + 1
270 buffer[buflen] = "null"
271 elseif valtype == 'number' then
272 local s
273 if value ~= value or value >= huge or -value >= huge then
274 -- This is the behaviour of the original JSON implementation.
275 s = "null"
276 else
277 s = num2str (value)
278 end
279 buflen = buflen + 1
280 buffer[buflen] = s
281 elseif valtype == 'boolean' then
282 buflen = buflen + 1
283 buffer[buflen] = value and "true" or "false"
284 elseif valtype == 'string' then
285 buflen = buflen + 1
286 buffer[buflen] = quotestring (value)
287 elseif valtype == 'table' then
288 if tables[value] then
289 return exception('reference cycle', value, state, buffer, buflen)
290 end
291 tables[value] = true
292 level = level + 1
293 local isa, n = isarray (value)
294 if n == 0 and valmeta and valmeta.__jsontype == 'object' then
295 isa = false
296 end
297 local msg
298 if isa then -- JSON array
299 buflen = buflen + 1
300 buffer[buflen] = "["
301 for i = 1, n do
302 buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
303 if not buflen then return nil, msg end
304 if i < n then
305 buflen = buflen + 1
306 buffer[buflen] = ","
307 end
308 end
309 buflen = buflen + 1
310 buffer[buflen] = "]"
311 else -- JSON object
312 local prev = false
313 buflen = buflen + 1
314 buffer[buflen] = "{"
315 local order = valmeta and valmeta.__jsonorder or globalorder
316 if order then
317 local used = {}
318 n = #order
319 for i = 1, n do
320 local k = order[i]
321 local v = value[k]
322 if v then
323 used[k] = true
324 buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
325 prev = true -- add a seperator before the next element
326 end
327 end
328 for k,v in pairs (value) do
329 if not used[k] then
330 buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
331 if not buflen then return nil, msg end
332 prev = true -- add a seperator before the next element
333 end
334 end
335 else -- unordered
336 for k,v in pairs (value) do
337 buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
338 if not buflen then return nil, msg end
339 prev = true -- add a seperator before the next element
340 end
341 end
342 if indent then
343 buflen = addnewline2 (level - 1, buffer, buflen)
344 end
345 buflen = buflen + 1
346 buffer[buflen] = "}"
347 end
348 tables[value] = nil
349 else
350 return exception ('unsupported type', value, state, buffer, buflen,
351 "type '" .. valtype .. "' is not supported by JSON.")
352 end
353 return buflen
354 end
355
356 function json.encode (value, state)
357 state = state or {}
358 local oldbuffer = state.buffer
359 local buffer = oldbuffer or {}
360 state.buffer = buffer
361 updatedecpoint()
362 local ret, msg = encode2 (value, state.indent, state.level or 0,
363 buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
364 if not ret then
365 error (msg, 2)
366 elseif oldbuffer == buffer then
367 state.bufferlen = ret
368 return true
369 else
370 state.bufferlen = nil
371 state.buffer = nil
372 return concat (buffer)
373 end
374 end
375
376 local function loc (str, where)
377 local line, pos, linepos = 1, 1, 0
378 while true do
379 pos = strfind (str, "\n", pos, true)
380 if pos and pos < where then
381 line = line + 1
382 linepos = pos
383 pos = pos + 1
384 else
385 break
386 end
387 end
388 return "line " .. line .. ", column " .. (where - linepos)
389 end
390
391 local function unterminated (str, what, where)
392 return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
393 end
394
395 local function scanwhite (str, pos)
396 while true do
397 pos = strfind (str, "%S", pos)
398 if not pos then return nil end
399 local sub2 = strsub (str, pos, pos + 1)
400 if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
401 -- UTF-8 Byte Order Mark
402 pos = pos + 3
403 elseif sub2 == "//" then
404 pos = strfind (str, "[\n\r]", pos + 2)
405 if not pos then return nil end
406 elseif sub2 == "/*" then
407 pos = strfind (str, "*/", pos + 2)
408 if not pos then return nil end
409 pos = pos + 2
410 else
411 return pos
412 end
413 end
414 end
415
416 local escapechars = {
417 ["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
418 ["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
419 }
420
421 local function unichar (value)
422 if value < 0 then
423 return nil
424 elseif value <= 0x007f then
425 return strchar (value)
426 elseif value <= 0x07ff then
427 return strchar (0xc0 + floor(value/0x40),
428 0x80 + (floor(value) % 0x40))
429 elseif value <= 0xffff then
430 return strchar (0xe0 + floor(value/0x1000),
431 0x80 + (floor(value/0x40) % 0x40),
432 0x80 + (floor(value) % 0x40))
433 elseif value <= 0x10ffff then
434 return strchar (0xf0 + floor(value/0x40000),
435 0x80 + (floor(value/0x1000) % 0x40),
436 0x80 + (floor(value/0x40) % 0x40),
437 0x80 + (floor(value) % 0x40))
438 else
439 return nil
440 end
441 end
442
443 local function scanstring (str, pos)
444 local lastpos = pos + 1
445 local buffer, n = {}, 0
446 while true do
447 local nextpos = strfind (str, "[\"\\]", lastpos)
448 if not nextpos then
449 return unterminated (str, "string", pos)
450 end
451 if nextpos > lastpos then
452 n = n + 1
453 buffer[n] = strsub (str, lastpos, nextpos - 1)
454 end
455 if strsub (str, nextpos, nextpos) == "\"" then
456 lastpos = nextpos + 1
457 break
458 else
459 local escchar = strsub (str, nextpos + 1, nextpos + 1)
460 local value
461 if escchar == "u" then
462 value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
463 if value then
464 local value2
465 if 0xD800 <= value and value <= 0xDBff then
466 -- we have the high surrogate of UTF-16. Check if there is a
467 -- low surrogate escaped nearby to combine them.
468 if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
469 value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
470 if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
471 value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
472 else
473 value2 = nil -- in case it was out of range for a low surrogate
474 end
475 end
476 end
477 value = value and unichar (value)
478 if value then
479 if value2 then
480 lastpos = nextpos + 12
481 else
482 lastpos = nextpos + 6
483 end
484 end
485 end
486 end
487 if not value then
488 value = escapechars[escchar] or escchar
489 lastpos = nextpos + 2
490 end
491 n = n + 1
492 buffer[n] = value
493 end
494 end
495 if n == 1 then
496 return buffer[1], lastpos
497 elseif n > 1 then
498 return concat (buffer), lastpos
499 else
500 return "", lastpos
501 end
502 end
503
504 local scanvalue -- forward declaration
505
506 local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
507 local len = strlen (str)
508 local tbl, n = {}, 0
509 local pos = startpos + 1
510 if what == 'object' then
511 setmetatable (tbl, objectmeta)
512 else
513 setmetatable (tbl, arraymeta)
514 end
515 while true do
516 pos = scanwhite (str, pos)
517 if not pos then return unterminated (str, what, startpos) end
518 local char = strsub (str, pos, pos)
519 if char == closechar then
520 return tbl, pos + 1
521 end
522 local val1, err
523 val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
524 if err then return nil, pos, err end
525 pos = scanwhite (str, pos)
526 if not pos then return unterminated (str, what, startpos) end
527 char = strsub (str, pos, pos)
528 if char == ":" then
529 if val1 == nil then
530 return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
531 end
532 pos = scanwhite (str, pos + 1)
533 if not pos then return unterminated (str, what, startpos) end
534 local val2
535 val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
536 if err then return nil, pos, err end
537 tbl[val1] = val2
538 pos = scanwhite (str, pos)
539 if not pos then return unterminated (str, what, startpos) end
540 char = strsub (str, pos, pos)
541 else
542 n = n + 1
543 tbl[n] = val1
544 end
545 if char == "," then
546 pos = pos + 1
547 end
548 end
549 end
550
551 scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
552 pos = pos or 1
553 pos = scanwhite (str, pos)
554 if not pos then
555 return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
556 end
557 local char = strsub (str, pos, pos)
558 if char == "{" then
559 return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
560 elseif char == "[" then
561 return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
562 elseif char == "\"" then
563 return scanstring (str, pos)
564 else
565 local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
566 if pstart then
567 local number = str2num (strsub (str, pstart, pend))
568 if number then
569 return number, pend + 1
570 end
571 end
572 pstart, pend = strfind (str, "^%a%w*", pos)
573 if pstart then
574 local name = strsub (str, pstart, pend)
575 if name == "true" then
576 return true, pend + 1
577 elseif name == "false" then
578 return false, pend + 1
579 elseif name == "null" then
580 return nullval, pend + 1
581 end
582 end
583 return nil, pos, "no valid JSON value at " .. loc (str, pos)
584 end
585 end
586
587 local function optionalmetatables(...)
588 if select("#", ...) > 0 then
589 return ...
590 else
591 return {__jsontype = 'object'}, {__jsontype = 'array'}
592 end
593 end
594
595 function json.decode (str, pos, nullval, ...)
596 local objectmeta, arraymeta = optionalmetatables(...)
597 return scanvalue (str, pos, nullval, objectmeta, arraymeta)
598 end
599
600 function json.use_lpeg ()
601 local g = require ("lpeg")
602
603 if g.version() == "0.11" then
604 error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
605 end
606
607 local pegmatch = g.match
608 local P, S, R = g.P, g.S, g.R
609
610 local function ErrorCall (str, pos, msg, state)
611 if not state.msg then
612 state.msg = msg .. " at " .. loc (str, pos)
613 state.pos = pos
614 end
615 return false
616 end
617
618 local function Err (msg)
619 return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
620 end
621
622 local SingleLineComment = P"//" * (1 - S"\n\r")^0
623 local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
624 local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
625
626 local PlainChar = 1 - S"\"\\\n\r"
627 local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
628 local HexDigit = R("09", "af", "AF")
629 local function UTF16Surrogate (match, pos, high, low)
630 high, low = tonumber (high, 16), tonumber (low, 16)
631 if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
632 return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
633 else
634 return false
635 end
636 end
637 local function UTF16BMP (hex)
638 return unichar (tonumber (hex, 16))
639 end
640 local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
641 local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
642 local Char = UnicodeEscape + EscapeSequence + PlainChar
643 local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
644 local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
645 local Fractal = P"." * R"09"^0
646 local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
647 local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
648 local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
649 local SimpleValue = Number + String + Constant
650 local ArrayContent, ObjectContent
651
652 -- The functions parsearray and parseobject parse only a single value/pair
653 -- at a time and store them directly to avoid hitting the LPeg limits.
654 local function parsearray (str, pos, nullval, state)
655 local obj, cont
656 local npos
657 local t, nt = {}, 0
658 repeat
659 obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
660 if not npos then break end
661 pos = npos
662 nt = nt + 1
663 t[nt] = obj
664 until cont == 'last'
665 return pos, setmetatable (t, state.arraymeta)
666 end
667
668 local function parseobject (str, pos, nullval, state)
669 local obj, key, cont
670 local npos
671 local t = {}
672 repeat
673 key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
674 if not npos then break end
675 pos = npos
676 t[key] = obj
677 until cont == 'last'
678 return pos, setmetatable (t, state.objectmeta)
679 end
680
681 local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
682 local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
683 local Value = Space * (Array + Object + SimpleValue)
684 local ExpectedValue = Value + Space * Err "value expected"
685 ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
686 local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
687 ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
688 local DecodeValue = ExpectedValue * g.Cp ()
689
690 function json.decode (str, pos, nullval, ...)
691 local state = {}
692 state.objectmeta, state.arraymeta = optionalmetatables(...)
693 local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
694 if state.msg then
695 return nil, state.pos, state.msg
696 else
697 return obj, retpos
698 end
699 end
700
701 -- use this function only once:
702 json.use_lpeg = function () return json end
703
704 json.using_lpeg = true
705
706 return json -- so you can get the module using json = require "dkjson".use_lpeg()
707 end
708
709 if always_try_using_lpeg then
710 pcall (json.use_lpeg)
711 end
712
713 return json
714
Impressum, Datenschutz