• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Keine Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revision59b72f8914e127fcbe75a008d566214468c3330c (tree)
Zeit2024-04-08 22:21:22
AutorFs <Fsu0413@vip....>
CommiterFs

Log Message

import dkjson

Ändern Zusammenfassung

Diff

--- a/UpdateWebsite/UpdateWebsite.lua
+++ b/UpdateWebsite/UpdateWebsite.lua
@@ -16,6 +16,7 @@ package.path = scriptPath .. "/lib/?.lua;" .. package.path
1616 parseConfTable = reuqire("ParseConfTable")
1717 compare = require("Compare")
1818 download = require("Download")
19+json = require("dkjson")
1920
2021 local buildContent = function(buildJob)
2122 if string.sub(buildJob, 1, 1) == "q" then
--- a/UpdateWebsite/lib/Compare.lua
+++ b/UpdateWebsite/lib/Compare.lua
@@ -228,7 +228,6 @@ end
228228
229229 local pathPrefixForBuildTargetArchAndToolchainVersion = function(target, arch, toolchainVersion)
230230 if target == "Windows" then
231- -- This expects change
232231 -- There is too many toolchain variants in current build: MSVC / MinGW-GCC / MinGW-LLVM, and there is an amazing amount of 18 builds in one single directory!
233232 -- So it need subdirectory (will be considered in next whole rebuild):
234233
--- /dev/null
+++ b/UpdateWebsite/lib/dkjson.lua
@@ -0,0 +1,749 @@
1+-- Module options:
2+local always_use_lpeg = false
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.4
9+
10+Version 2.7
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-2024 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.7" }
56+
57+local jsonlpeg = {}
58+
59+if register_global_module_table then
60+ if always_use_lpeg then
61+ _G[global_module_name] = jsonlpeg
62+ else
63+ _G[global_module_name] = json
64+ end
65+end
66+
67+local _ENV = nil -- blocking globals in Lua 5.2 and later
68+
69+pcall (function()
70+ -- Enable access to blocked metatables.
71+ -- Don't worry, this module doesn't change anything in them.
72+ local debmeta = require "debug".getmetatable
73+ if debmeta then getmetatable = debmeta end
74+end)
75+
76+json.null = setmetatable ({}, {
77+ __tojson = function () return "null" end
78+})
79+
80+local function isarray (tbl)
81+ local max, n, arraylen = 0, 0, 0
82+ for k,v in pairs (tbl) do
83+ if k == 'n' and type(v) == 'number' then
84+ arraylen = v
85+ if v > max then
86+ max = v
87+ end
88+ else
89+ if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
90+ return false
91+ end
92+ if k > max then
93+ max = k
94+ end
95+ n = n + 1
96+ end
97+ end
98+ if max > 10 and max > arraylen and max > n * 2 then
99+ return false -- don't create an array with too many holes
100+ end
101+ return true, max
102+end
103+
104+local escapecodes = {
105+ ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
106+ ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
107+}
108+
109+local function escapeutf8 (uchar)
110+ local value = escapecodes[uchar]
111+ if value then
112+ return value
113+ end
114+ local a, b, c, d = strbyte (uchar, 1, 4)
115+ a, b, c, d = a or 0, b or 0, c or 0, d or 0
116+ if a <= 0x7f then
117+ value = a
118+ elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
119+ value = (a - 0xc0) * 0x40 + b - 0x80
120+ elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
121+ value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
122+ elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
123+ value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
124+ else
125+ return ""
126+ end
127+ if value <= 0xffff then
128+ return strformat ("\\u%.4x", value)
129+ elseif value <= 0x10ffff then
130+ -- encode as UTF-16 surrogate pair
131+ value = value - 0x10000
132+ local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
133+ return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
134+ else
135+ return ""
136+ end
137+end
138+
139+local function fsub (str, pattern, repl)
140+ -- gsub always builds a new string in a buffer, even when no match
141+ -- exists. First using find should be more efficient when most strings
142+ -- don't contain the pattern.
143+ if strfind (str, pattern) then
144+ return gsub (str, pattern, repl)
145+ else
146+ return str
147+ end
148+end
149+
150+local function quotestring (value)
151+ -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
152+ value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
153+ if strfind (value, "[\194\216\220\225\226\239]") then
154+ value = fsub (value, "\194[\128-\159\173]", escapeutf8)
155+ value = fsub (value, "\216[\128-\132]", escapeutf8)
156+ value = fsub (value, "\220\143", escapeutf8)
157+ value = fsub (value, "\225\158[\180\181]", escapeutf8)
158+ value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
159+ value = fsub (value, "\226\129[\160-\175]", escapeutf8)
160+ value = fsub (value, "\239\187\191", escapeutf8)
161+ value = fsub (value, "\239\191[\176-\191]", escapeutf8)
162+ end
163+ return "\"" .. value .. "\""
164+end
165+json.quotestring = quotestring
166+
167+local function replace(str, o, n)
168+ local i, j = strfind (str, o, 1, true)
169+ if i then
170+ return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
171+ else
172+ return str
173+ end
174+end
175+
176+-- locale independent num2str and str2num functions
177+local decpoint, numfilter
178+
179+local function updatedecpoint ()
180+ decpoint = strmatch(tostring(0.5), "([^05+])")
181+ -- build a filter that can be used to remove group separators
182+ numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
183+end
184+
185+updatedecpoint()
186+
187+local function num2str (num)
188+ return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
189+end
190+
191+local function str2num (str)
192+ local num = tonumber(replace(str, ".", decpoint))
193+ if not num then
194+ updatedecpoint()
195+ num = tonumber(replace(str, ".", decpoint))
196+ end
197+ return num
198+end
199+
200+local function addnewline2 (level, buffer, buflen)
201+ buffer[buflen+1] = "\n"
202+ buffer[buflen+2] = strrep (" ", level)
203+ buflen = buflen + 2
204+ return buflen
205+end
206+
207+function json.addnewline (state)
208+ if state.indent then
209+ state.bufferlen = addnewline2 (state.level or 0,
210+ state.buffer, state.bufferlen or #(state.buffer))
211+ end
212+end
213+
214+local encode2 -- forward declaration
215+
216+local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
217+ local kt = type (key)
218+ if kt ~= 'string' and kt ~= 'number' then
219+ return nil, "type '" .. kt .. "' is not supported as a key by JSON."
220+ end
221+ if prev then
222+ buflen = buflen + 1
223+ buffer[buflen] = ","
224+ end
225+ if indent then
226+ buflen = addnewline2 (level, buffer, buflen)
227+ end
228+ buffer[buflen+1] = quotestring (key)
229+ buffer[buflen+2] = ":"
230+ return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
231+end
232+
233+local function appendcustom(res, buffer, state)
234+ local buflen = state.bufferlen
235+ if type (res) == 'string' then
236+ buflen = buflen + 1
237+ buffer[buflen] = res
238+ end
239+ return buflen
240+end
241+
242+local function exception(reason, value, state, buffer, buflen, defaultmessage)
243+ defaultmessage = defaultmessage or reason
244+ local handler = state.exception
245+ if not handler then
246+ return nil, defaultmessage
247+ else
248+ state.bufferlen = buflen
249+ local ret, msg = handler (reason, value, state, defaultmessage)
250+ if not ret then return nil, msg or defaultmessage end
251+ return appendcustom(ret, buffer, state)
252+ end
253+end
254+
255+function json.encodeexception(reason, value, state, defaultmessage)
256+ return quotestring("<" .. defaultmessage .. ">")
257+end
258+
259+encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
260+ local valtype = type (value)
261+ local valmeta = getmetatable (value)
262+ valmeta = type (valmeta) == 'table' and valmeta -- only tables
263+ local valtojson = valmeta and valmeta.__tojson
264+ if valtojson then
265+ if tables[value] then
266+ return exception('reference cycle', value, state, buffer, buflen)
267+ end
268+ tables[value] = true
269+ state.bufferlen = buflen
270+ local ret, msg = valtojson (value, state)
271+ if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
272+ tables[value] = nil
273+ buflen = appendcustom(ret, buffer, state)
274+ elseif value == nil then
275+ buflen = buflen + 1
276+ buffer[buflen] = "null"
277+ elseif valtype == 'number' then
278+ local s
279+ if value ~= value or value >= huge or -value >= huge then
280+ -- This is the behaviour of the original JSON implementation.
281+ s = "null"
282+ else
283+ s = num2str (value)
284+ end
285+ buflen = buflen + 1
286+ buffer[buflen] = s
287+ elseif valtype == 'boolean' then
288+ buflen = buflen + 1
289+ buffer[buflen] = value and "true" or "false"
290+ elseif valtype == 'string' then
291+ buflen = buflen + 1
292+ buffer[buflen] = quotestring (value)
293+ elseif valtype == 'table' then
294+ if tables[value] then
295+ return exception('reference cycle', value, state, buffer, buflen)
296+ end
297+ tables[value] = true
298+ level = level + 1
299+ local isa, n = isarray (value)
300+ if n == 0 and valmeta and valmeta.__jsontype == 'object' then
301+ isa = false
302+ end
303+ local msg
304+ if isa then -- JSON array
305+ buflen = buflen + 1
306+ buffer[buflen] = "["
307+ for i = 1, n do
308+ buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
309+ if not buflen then return nil, msg end
310+ if i < n then
311+ buflen = buflen + 1
312+ buffer[buflen] = ","
313+ end
314+ end
315+ buflen = buflen + 1
316+ buffer[buflen] = "]"
317+ else -- JSON object
318+ local prev = false
319+ buflen = buflen + 1
320+ buffer[buflen] = "{"
321+ local order = valmeta and valmeta.__jsonorder or globalorder
322+ if order then
323+ local used = {}
324+ n = #order
325+ for i = 1, n do
326+ local k = order[i]
327+ local v = value[k]
328+ if v ~= nil then
329+ used[k] = true
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+ for k,v in pairs (value) do
336+ if not used[k] then
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+ else -- unordered
343+ for k,v in pairs (value) do
344+ buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
345+ if not buflen then return nil, msg end
346+ prev = true -- add a seperator before the next element
347+ end
348+ end
349+ if indent then
350+ buflen = addnewline2 (level - 1, buffer, buflen)
351+ end
352+ buflen = buflen + 1
353+ buffer[buflen] = "}"
354+ end
355+ tables[value] = nil
356+ else
357+ return exception ('unsupported type', value, state, buffer, buflen,
358+ "type '" .. valtype .. "' is not supported by JSON.")
359+ end
360+ return buflen
361+end
362+
363+function json.encode (value, state)
364+ state = state or {}
365+ local oldbuffer = state.buffer
366+ local buffer = oldbuffer or {}
367+ state.buffer = buffer
368+ updatedecpoint()
369+ local ret, msg = encode2 (value, state.indent, state.level or 0,
370+ buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
371+ if not ret then
372+ error (msg, 2)
373+ elseif oldbuffer == buffer then
374+ state.bufferlen = ret
375+ return true
376+ else
377+ state.bufferlen = nil
378+ state.buffer = nil
379+ return concat (buffer)
380+ end
381+end
382+
383+local function loc (str, where)
384+ local line, pos, linepos = 1, 1, 0
385+ while true do
386+ pos = strfind (str, "\n", pos, true)
387+ if pos and pos < where then
388+ line = line + 1
389+ linepos = pos
390+ pos = pos + 1
391+ else
392+ break
393+ end
394+ end
395+ return "line " .. line .. ", column " .. (where - linepos)
396+end
397+
398+local function unterminated (str, what, where)
399+ return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
400+end
401+
402+local function scanwhite (str, pos)
403+ while true do
404+ pos = strfind (str, "%S", pos)
405+ if not pos then return nil end
406+ local sub2 = strsub (str, pos, pos + 1)
407+ if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
408+ -- UTF-8 Byte Order Mark
409+ pos = pos + 3
410+ elseif sub2 == "//" then
411+ pos = strfind (str, "[\n\r]", pos + 2)
412+ if not pos then return nil end
413+ elseif sub2 == "/*" then
414+ pos = strfind (str, "*/", pos + 2)
415+ if not pos then return nil end
416+ pos = pos + 2
417+ else
418+ return pos
419+ end
420+ end
421+end
422+
423+local escapechars = {
424+ ["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
425+ ["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
426+}
427+
428+local function unichar (value)
429+ if value < 0 then
430+ return nil
431+ elseif value <= 0x007f then
432+ return strchar (value)
433+ elseif value <= 0x07ff then
434+ return strchar (0xc0 + floor(value/0x40),
435+ 0x80 + (floor(value) % 0x40))
436+ elseif value <= 0xffff then
437+ return strchar (0xe0 + floor(value/0x1000),
438+ 0x80 + (floor(value/0x40) % 0x40),
439+ 0x80 + (floor(value) % 0x40))
440+ elseif value <= 0x10ffff then
441+ return strchar (0xf0 + floor(value/0x40000),
442+ 0x80 + (floor(value/0x1000) % 0x40),
443+ 0x80 + (floor(value/0x40) % 0x40),
444+ 0x80 + (floor(value) % 0x40))
445+ else
446+ return nil
447+ end
448+end
449+
450+local function scanstring (str, pos)
451+ local lastpos = pos + 1
452+ local buffer, n = {}, 0
453+ while true do
454+ local nextpos = strfind (str, "[\"\\]", lastpos)
455+ if not nextpos then
456+ return unterminated (str, "string", pos)
457+ end
458+ if nextpos > lastpos then
459+ n = n + 1
460+ buffer[n] = strsub (str, lastpos, nextpos - 1)
461+ end
462+ if strsub (str, nextpos, nextpos) == "\"" then
463+ lastpos = nextpos + 1
464+ break
465+ else
466+ local escchar = strsub (str, nextpos + 1, nextpos + 1)
467+ local value
468+ if escchar == "u" then
469+ value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
470+ if value then
471+ local value2
472+ if 0xD800 <= value and value <= 0xDBff then
473+ -- we have the high surrogate of UTF-16. Check if there is a
474+ -- low surrogate escaped nearby to combine them.
475+ if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
476+ value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
477+ if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
478+ value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
479+ else
480+ value2 = nil -- in case it was out of range for a low surrogate
481+ end
482+ end
483+ end
484+ value = value and unichar (value)
485+ if value then
486+ if value2 then
487+ lastpos = nextpos + 12
488+ else
489+ lastpos = nextpos + 6
490+ end
491+ end
492+ end
493+ end
494+ if not value then
495+ value = escapechars[escchar] or escchar
496+ lastpos = nextpos + 2
497+ end
498+ n = n + 1
499+ buffer[n] = value
500+ end
501+ end
502+ if n == 1 then
503+ return buffer[1], lastpos
504+ elseif n > 1 then
505+ return concat (buffer), lastpos
506+ else
507+ return "", lastpos
508+ end
509+end
510+
511+local scanvalue -- forward declaration
512+
513+local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
514+ local len = strlen (str)
515+ local tbl, n = {}, 0
516+ local pos = startpos + 1
517+ if what == 'object' then
518+ setmetatable (tbl, objectmeta)
519+ else
520+ setmetatable (tbl, arraymeta)
521+ end
522+ while true do
523+ pos = scanwhite (str, pos)
524+ if not pos then return unterminated (str, what, startpos) end
525+ local char = strsub (str, pos, pos)
526+ if char == closechar then
527+ return tbl, pos + 1
528+ end
529+ local val1, err
530+ val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
531+ if err then return nil, pos, err end
532+ pos = scanwhite (str, pos)
533+ if not pos then return unterminated (str, what, startpos) end
534+ char = strsub (str, pos, pos)
535+ if char == ":" then
536+ if val1 == nil then
537+ return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
538+ end
539+ pos = scanwhite (str, pos + 1)
540+ if not pos then return unterminated (str, what, startpos) end
541+ local val2
542+ val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
543+ if err then return nil, pos, err end
544+ tbl[val1] = val2
545+ pos = scanwhite (str, pos)
546+ if not pos then return unterminated (str, what, startpos) end
547+ char = strsub (str, pos, pos)
548+ else
549+ n = n + 1
550+ tbl[n] = val1
551+ end
552+ if char == "," then
553+ pos = pos + 1
554+ end
555+ end
556+end
557+
558+scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
559+ pos = pos or 1
560+ pos = scanwhite (str, pos)
561+ if not pos then
562+ return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
563+ end
564+ local char = strsub (str, pos, pos)
565+ if char == "{" then
566+ return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
567+ elseif char == "[" then
568+ return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
569+ elseif char == "\"" then
570+ return scanstring (str, pos)
571+ else
572+ local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
573+ if pstart then
574+ local number = str2num (strsub (str, pstart, pend))
575+ if number then
576+ return number, pend + 1
577+ end
578+ end
579+ pstart, pend = strfind (str, "^%a%w*", pos)
580+ if pstart then
581+ local name = strsub (str, pstart, pend)
582+ if name == "true" then
583+ return true, pend + 1
584+ elseif name == "false" then
585+ return false, pend + 1
586+ elseif name == "null" then
587+ return nullval, pend + 1
588+ end
589+ end
590+ return nil, pos, "no valid JSON value at " .. loc (str, pos)
591+ end
592+end
593+
594+local function optionalmetatables(...)
595+ if select("#", ...) > 0 then
596+ return ...
597+ else
598+ return {__jsontype = 'object'}, {__jsontype = 'array'}
599+ end
600+end
601+
602+function json.decode (str, pos, nullval, ...)
603+ local objectmeta, arraymeta = optionalmetatables(...)
604+ return scanvalue (str, pos, nullval, objectmeta, arraymeta)
605+end
606+
607+function json.use_lpeg ()
608+ local g = require ("lpeg")
609+
610+ if type(g.version) == 'function' and g.version() == "0.11" then
611+ error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
612+ end
613+
614+ local pegmatch = g.match
615+ local P, S, R = g.P, g.S, g.R
616+
617+ local function ErrorCall (str, pos, msg, state)
618+ if not state.msg then
619+ state.msg = msg .. " at " .. loc (str, pos)
620+ state.pos = pos
621+ end
622+ return false
623+ end
624+
625+ local function Err (msg)
626+ return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
627+ end
628+
629+ local function ErrorUnterminatedCall (str, pos, what, state)
630+ return ErrorCall (str, pos - 1, "unterminated " .. what, state)
631+ end
632+
633+ local SingleLineComment = P"//" * (1 - S"\n\r")^0
634+ local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
635+ local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
636+
637+ local function ErrUnterminated (what)
638+ return g.Cmt (g.Cc (what) * g.Carg (2), ErrorUnterminatedCall)
639+ end
640+
641+ local PlainChar = 1 - S"\"\\\n\r"
642+ local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
643+ local HexDigit = R("09", "af", "AF")
644+ local function UTF16Surrogate (match, pos, high, low)
645+ high, low = tonumber (high, 16), tonumber (low, 16)
646+ if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
647+ return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
648+ else
649+ return false
650+ end
651+ end
652+ local function UTF16BMP (hex)
653+ return unichar (tonumber (hex, 16))
654+ end
655+ local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
656+ local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
657+ local Char = UnicodeEscape + EscapeSequence + PlainChar
658+ local String = P"\"" * (g.Cs (Char ^ 0) * P"\"" + ErrUnterminated "string")
659+ local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
660+ local Fractal = P"." * R"09"^0
661+ local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
662+ local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
663+ local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
664+ local SimpleValue = Number + String + Constant
665+ local ArrayContent, ObjectContent
666+
667+ -- The functions parsearray and parseobject parse only a single value/pair
668+ -- at a time and store them directly to avoid hitting the LPeg limits.
669+ local function parsearray (str, pos, nullval, state)
670+ local obj, cont
671+ local start = pos
672+ local npos
673+ local t, nt = {}, 0
674+ repeat
675+ obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
676+ if cont == 'end' then
677+ return ErrorUnterminatedCall (str, start, "array", state)
678+ end
679+ pos = npos
680+ if cont == 'cont' or cont == 'last' then
681+ nt = nt + 1
682+ t[nt] = obj
683+ end
684+ until cont ~= 'cont'
685+ return pos, setmetatable (t, state.arraymeta)
686+ end
687+
688+ local function parseobject (str, pos, nullval, state)
689+ local obj, key, cont
690+ local start = pos
691+ local npos
692+ local t = {}
693+ repeat
694+ key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
695+ if cont == 'end' then
696+ return ErrorUnterminatedCall (str, start, "object", state)
697+ end
698+ pos = npos
699+ if cont == 'cont' or cont == 'last' then
700+ t[key] = obj
701+ end
702+ until cont ~= 'cont'
703+ return pos, setmetatable (t, state.objectmeta)
704+ end
705+
706+ local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray)
707+ local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject)
708+ local Value = Space * (Array + Object + SimpleValue)
709+ local ExpectedValue = Value + Space * Err "value expected"
710+ local ExpectedKey = String + Err "key expected"
711+ local End = P(-1) * g.Cc'end'
712+ local ErrInvalid = Err "invalid JSON"
713+ ArrayContent = (Value * Space * (P"," * g.Cc'cont' + P"]" * g.Cc'last'+ End + ErrInvalid) + g.Cc(nil) * (P"]" * g.Cc'empty' + End + ErrInvalid)) * g.Cp()
714+ local Pair = g.Cg (Space * ExpectedKey * Space * (P":" + Err "colon expected") * ExpectedValue)
715+ ObjectContent = (g.Cc(nil) * g.Cc(nil) * P"}" * g.Cc'empty' + End + (Pair * Space * (P"," * g.Cc'cont' + P"}" * g.Cc'last' + End + ErrInvalid) + ErrInvalid)) * g.Cp()
716+ local DecodeValue = ExpectedValue * g.Cp ()
717+
718+ jsonlpeg.version = json.version
719+ jsonlpeg.encode = json.encode
720+ jsonlpeg.null = json.null
721+ jsonlpeg.quotestring = json.quotestring
722+ jsonlpeg.addnewline = json.addnewline
723+ jsonlpeg.encodeexception = json.encodeexception
724+ jsonlpeg.using_lpeg = true
725+
726+ function jsonlpeg.decode (str, pos, nullval, ...)
727+ local state = {}
728+ state.objectmeta, state.arraymeta = optionalmetatables(...)
729+ local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
730+ if state.msg then
731+ return nil, state.pos, state.msg
732+ else
733+ return obj, retpos
734+ end
735+ end
736+
737+ -- cache result of this function:
738+ json.use_lpeg = function () return jsonlpeg end
739+ jsonlpeg.use_lpeg = json.use_lpeg
740+
741+ return jsonlpeg
742+end
743+
744+if always_use_lpeg then
745+ return json.use_lpeg()
746+end
747+
748+return json
749+