My configuration files for Debian/Ubuntu applications
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

713 satır
22 KiB

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