forked from public/foundryvtt-swade-fr
		
	Compare commits
	
		
			24 Commits
		
	
	
		
			foundryvtt
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| be5ec3a4d6 | |||
| 15109ddea8 | |||
| f46129e20f | |||
| 1cc3bca660 | |||
| c0d94d1fb0 | |||
| b63de0e7dd | |||
| 28e41b5371 | |||
| ea99bbc226 | |||
| cd44a6dab2 | |||
| 5f84fd08e8 | |||
| 67712c32cb | |||
| dbba2040f6 | |||
| 422d47ed71 | |||
| 68ebd6133b | |||
| 57a1b51aa4 | |||
| f901f25e89 | |||
| acadff5a54 | |||
| 1c15ba9140 | |||
| e922fd16f1 | |||
| 8e03faa61e | |||
| 51cc2803f7 | |||
| 35ec35bd2e | |||
| cd64f10d14 | |||
| 27b922ecd5 | 
| @@ -1,3 +1,11 @@ | ||||
| # 0.21.0.0 | ||||
| # 0.21.1.0 | ||||
|  | ||||
| Alignement sur SWADE v1.1.X et traductions de clés manquantes | ||||
|  | ||||
| # 0.21.0.0 | ||||
|  | ||||
| Alignement sur SWADE v1.1.X | ||||
|  | ||||
| # 0.20.0.3 | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   "name": "swade-fr", | ||||
|   "title": "SWADE - Traduction française", | ||||
|   "description": "Ajoute le français (FRANCE) au système SWADE.<p> Une traduction Babele des compendiums est inclue mais optionnelle. (Encore en test, à utiliser à vos risques et périls !) </p> <p>*** Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p>*** Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Discord francophone</a></p>", | ||||
|   "version": "0.20.0.3", | ||||
|   "version": "1.2.0", | ||||
|   "minimumCoreVersion" : "0.7.9", | ||||
|   "compatibleCoreVersion" : "9", | ||||
|   "author": "BoboursToutCool, Gronyon, Kyane, LeRatierBretonnien, Sasmira, U~man,X.O. de Vorcen", | ||||
| @@ -64,6 +64,6 @@ | ||||
|   ], | ||||
|    | ||||
|   "url": "https://www.uberwald.me/gitea/public//foundryvtt-swade-fr", | ||||
|   "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-swade-fr/raw/branch/master/system.jso", | ||||
|   "download": "https://www.uberwald.me/gitea/public/foundryvtt-swade-fr/archive/foundryvtt-swade-fr-0.20.0.3.zip" | ||||
|   "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-swade-fr/raw/branch/master/module.json", | ||||
|   "download": "https://www.uberwald.me/gitea/public/foundryvtt-swade-fr/archive/foundryvtt-swade-fr-1.2.0.zip" | ||||
| } | ||||
							
								
								
									
										39
									
								
								tools/detect_missing_strings.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tools/detect_missing_strings.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| package.path = package.path .. ";luajson/?.lua" | ||||
| local JSON = require"json" | ||||
|  | ||||
| local enjsonf = "../../swade/src/lang/en.yml" | ||||
| local frjsonf = "../fr.json" | ||||
|  | ||||
| local fp = io.open(enjsonf, "r") | ||||
| local line = fp:read() | ||||
| local entags = {} | ||||
| while line do | ||||
|   --print("LINE", line)  | ||||
|   local key, value = line:match("([%w%.]*):([>%-%+%p%s%w%d%.]*)" ) | ||||
|   if key then  | ||||
|     entags[key] = value | ||||
|   end | ||||
|   line = fp:read() | ||||
| end | ||||
| fp:close() | ||||
|  | ||||
| fp = io.open(frjsonf, "r") | ||||
| local frtags = JSON.decode( fp:read("*a") ) | ||||
| fp:close() | ||||
|  | ||||
| local todisplay  = {} | ||||
| for tag, value in pairs(entags) do | ||||
|   if not frtags[tag] then  | ||||
|     todisplay[#todisplay+1] = { tag=tag, value=value } | ||||
|   end | ||||
| end | ||||
|  | ||||
| table.sort(todisplay, function (a, b)  | ||||
|     return a.tag < b.tag  | ||||
|   end | ||||
| ) | ||||
| for _, tagDef in pairs(todisplay) do | ||||
|   print('"'.. tagDef.tag ..'":"'.. tagDef.value..'",') | ||||
| end | ||||
|  | ||||
|  | ||||
							
								
								
									
										625
									
								
								tools/lpeg/lpcap.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										625
									
								
								tools/lpeg/lpcap.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,625 @@ | ||||
| --[[ | ||||
| LPEGLJ | ||||
| lpcap.lua | ||||
| Capture functions | ||||
| Copyright (C) 2014 Rostislav Sacek. | ||||
| based on LPeg v1.0 - PEG pattern matching for Lua | ||||
| Lua.org & PUC-Rio  written by Roberto Ierusalimschy | ||||
| http://www.inf.puc-rio.br/~roberto/lpeg/ | ||||
|  | ||||
| ** Permission is hereby granted, free of charge, to any person obtaining | ||||
| ** a copy of this software and associated documentation files (the | ||||
| ** "Software"), to deal in the Software without restriction, including | ||||
| ** without limitation the rights to use, copy, modify, merge, publish, | ||||
| ** distribute, sublicense, and/or sell copies of the Software, and to | ||||
| ** permit persons to whom the Software is furnished to do so, subject to | ||||
| ** the following conditions: | ||||
| ** | ||||
| ** The above copyright notice and this permission notice shall be | ||||
| ** included in all copies or substantial portions of the Software. | ||||
| ** | ||||
| ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
| ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||
| ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||
| ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||
| ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| ** | ||||
| ** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] | ||||
| --]] | ||||
| local ffi = require "ffi" | ||||
|  | ||||
| local Cclose = 0 | ||||
| local Cposition = 1 | ||||
| local Cconst = 2 | ||||
| local Cbackref = 3 | ||||
| local Carg = 4 | ||||
| local Csimple = 5 | ||||
| local Ctable = 6 | ||||
| local Cfunction = 7 | ||||
| local Cquery = 8 | ||||
| local Cstring = 9 | ||||
| local Cnum = 10 | ||||
| local Csubst = 11 | ||||
| local Cfold = 12 | ||||
| local Cruntime = 13 | ||||
| local Cgroup = 14 | ||||
|  | ||||
| local MAXSTRCAPS = 10 | ||||
|  | ||||
| local pushcapture | ||||
| local addonestring | ||||
|  | ||||
|  | ||||
| -- Goes back in a list of captures looking for an open capture | ||||
| -- corresponding to a close | ||||
|  | ||||
| local function findopen(cs, index) | ||||
|     local n = 0; -- number of closes waiting an open | ||||
|     while true do | ||||
|         index = index - 1 | ||||
|         if cs.ocap[index].kind == Cclose then | ||||
|             n = n + 1 -- one more open to skip | ||||
|         elseif cs.ocap[index].siz == 0 then | ||||
|             if n == 0 then | ||||
|                 return index | ||||
|             end | ||||
|             n = n - 1 | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| local function checknextcap(cs, captop) | ||||
|     local cap = cs.cap; | ||||
|     -- not a single capture?    ((cap)->siz != 0) | ||||
|     if cs.ocap[cap].siz == 0 then | ||||
|         local n = 0; -- number of opens waiting a close | ||||
|         -- look for corresponding close | ||||
|         while true do | ||||
|             cap = cap + 1 | ||||
|             if cap > captop then return end | ||||
|             if cs.ocap[cap].kind == Cclose then | ||||
|                 n = n - 1 | ||||
|                 if n + 1 == 0 then | ||||
|                     break; | ||||
|                 end | ||||
|             elseif cs.ocap[cap].siz == 0 then | ||||
|                 n = n + 1 | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|     cap = cap + 1; -- + 1 to skip last close (or entire single capture) | ||||
|     if cap > captop then return end | ||||
|     return true | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Go to the next capture | ||||
|  | ||||
| local function nextcap(cs) | ||||
|     local cap = cs.cap; | ||||
|     -- not a single capture?    ((cap)->siz != 0) | ||||
|     if cs.ocap[cap].siz == 0 then | ||||
|         local n = 0; -- number of opens waiting a close | ||||
|         -- look for corresponding close | ||||
|         while true do | ||||
|             cap = cap + 1 | ||||
|             if cs.ocap[cap].kind == Cclose then | ||||
|                 n = n - 1 | ||||
|                 if n + 1 == 0 then | ||||
|                     break; | ||||
|                 end | ||||
|             elseif cs.ocap[cap].siz == 0 then | ||||
|                 n = n + 1 | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|     cs.cap = cap + 1; -- + 1 to skip last close (or entire single capture) | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Push on the Lua stack all values generated by nested captures inside | ||||
| -- the current capture. Returns number of values pushed. 'addextra' | ||||
| -- makes it push the entire match after all captured values. The | ||||
| -- entire match is pushed also if there are no other nested values, | ||||
| -- so the function never returns zero. | ||||
|  | ||||
| local function pushnestedvalues(cs, addextra, out, valuetable) | ||||
|     local co = cs.cap | ||||
|     cs.cap = cs.cap + 1 | ||||
|     -- no nested captures? | ||||
|     if cs.ocap[cs.cap - 1].siz ~= 0 then | ||||
|         local st = cs.ocap[co].s | ||||
|         local l = cs.ocap[co].siz - 1 | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = cs.s and cs.s:sub(st, st + l - 1) or cs.stream(st, st + l - 1) | ||||
|         return 1; -- that is it | ||||
|     else | ||||
|         local n = 0; | ||||
|         while cs.ocap[cs.cap].kind ~= Cclose do -- repeat for all nested patterns | ||||
|         n = n + pushcapture(cs, out, valuetable); | ||||
|         end | ||||
|         -- need extra? | ||||
|         if addextra or n == 0 then | ||||
|             local st = cs.ocap[co].s | ||||
|             local l = cs.ocap[cs.cap].s - cs.ocap[co].s | ||||
|             out.outindex = out.outindex + 1 | ||||
|             out.out[out.outindex] = cs.s and cs.s:sub(st, st + l - 1) or cs.stream(st, st + l - 1) | ||||
|             n = n + 1 | ||||
|         end | ||||
|         cs.cap = cs.cap + 1 -- skip close entry | ||||
|         return n; | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Push only the first value generated by nested captures | ||||
|  | ||||
| local function pushonenestedvalue(cs, out, valuetable) | ||||
|     local n = pushnestedvalues(cs, false, out, valuetable) | ||||
|     for i = n, 2, -1 do | ||||
|         out.out[out.outindex] = nil | ||||
|         out.outindex = out.outindex - 1 | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Try to find a named group capture with the name given at the top of | ||||
| -- the stack; goes backward from 'cap'. | ||||
|  | ||||
| local function findback(cs, cap, name, valuetable) | ||||
|     -- repeat until end of list | ||||
|     while cap > 0 do | ||||
|         cap = cap - 1 | ||||
|         local continue | ||||
|         if cs.ocap[cap].kind == Cclose then | ||||
|             cap = findopen(cs, cap); -- skip nested captures | ||||
|         elseif cs.ocap[cap].siz == 0 then | ||||
|             continue = true -- opening an enclosing capture: skip and get previous | ||||
|         end | ||||
|         if not continue and cs.ocap[cap].kind == Cgroup and cs.ocap[cap].idx ~= 0 then | ||||
|             local gname = valuetable[cs.ocap[cap].idx] -- get group name | ||||
|             -- right group? | ||||
|             if name == gname then | ||||
|                 return cap; | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|     error(("back reference '%s' not found"):format(name), 0) | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Back-reference capture. Return number of values pushed. | ||||
|  | ||||
| local function backrefcap(cs, out, valuetable) | ||||
|     local curr = cs.cap; | ||||
|     local name = valuetable[cs.ocap[cs.cap].idx] -- reference name | ||||
|     cs.cap = findback(cs, curr, name, valuetable) -- find corresponding group | ||||
|     local n = pushnestedvalues(cs, false, out, valuetable); -- push group's values | ||||
|     cs.cap = curr + 1; | ||||
|     return n; | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Table capture: creates a new table and populates it with nested | ||||
| -- captures. | ||||
|  | ||||
| local function tablecap(cs, out, valuetable) | ||||
|     local n = 0; | ||||
|     local t = {} | ||||
|     cs.cap = cs.cap + 1 | ||||
|     -- table is empty | ||||
|     if cs.ocap[cs.cap - 1].siz == 0 then | ||||
|         while cs.ocap[cs.cap].kind ~= Cclose do | ||||
|             local subout = { outindex = 0, out = {} } | ||||
|             -- named group? | ||||
|             if cs.ocap[cs.cap].kind == Cgroup and cs.ocap[cs.cap].idx ~= 0 then | ||||
|                 local groupname = valuetable[cs.ocap[cs.cap].idx] -- push group name | ||||
|                 pushonenestedvalue(cs, subout, valuetable) | ||||
|                 t[groupname] = subout.out[1] | ||||
|             else | ||||
|                 -- not a named group | ||||
|                 local k = pushcapture(cs, subout, valuetable) | ||||
|                 -- store all values into table | ||||
|                 for i = 1, subout.outindex do | ||||
|                     t[i + n] = subout.out[i] | ||||
|                 end | ||||
|                 n = n + k; | ||||
|             end | ||||
|         end | ||||
|         cs.cap = cs.cap + 1 -- skip close entry | ||||
|     end | ||||
|     out.outindex = out.outindex + 1 | ||||
|     out.out[out.outindex] = t | ||||
|     return 1; -- number of values pushed (only the table) | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Table-query capture | ||||
|  | ||||
| local function querycap(cs, out, valuetable) | ||||
|     local table = valuetable[cs.ocap[cs.cap].idx] | ||||
|     local subout = { outindex = 0, out = {} } | ||||
|     pushonenestedvalue(cs, subout, valuetable) -- get nested capture | ||||
|     -- query cap. value at table | ||||
|     if table[subout.out[1]] ~= nil then | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = table[subout.out[1]] | ||||
|         return 1 | ||||
|     end | ||||
|     return 0 | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Fold capture | ||||
|  | ||||
| local function foldcap(cs, out, valuetable) | ||||
|     local fce = valuetable[cs.ocap[cs.cap].idx] | ||||
|     cs.cap = cs.cap + 1 | ||||
|     -- no nested captures? | ||||
|     -- or no nested captures (large subject)? | ||||
|     if cs.ocap[cs.cap - 1].siz ~= 0 or | ||||
|             cs.ocap[cs.cap].kind == Cclose then | ||||
|         error("no initial value for fold capture", 0); | ||||
|     end | ||||
|     local subout = { outindex = 0; out = {} } | ||||
|     local n = pushcapture(cs, subout, valuetable) -- nested captures with no values? | ||||
|     if n == 0 then | ||||
|         error("no initial value for fold capture", 0); | ||||
|     end | ||||
|     local acumulator = subout.out[1] -- leave only one result for accumulator | ||||
|     while cs.ocap[cs.cap].kind ~= Cclose do | ||||
|         local subout = { outindex = 0; out = {} } | ||||
|         n = pushcapture(cs, subout, valuetable); -- get next capture's values | ||||
|         acumulator = fce(acumulator, unpack(subout.out, 1, subout.outindex)) -- call folding function | ||||
|     end | ||||
|     cs.cap = cs.cap + 1; -- skip close entry | ||||
|     out.outindex = out.outindex + 1 | ||||
|     out.out[out.outindex] = acumulator | ||||
|     return 1; -- only accumulator left on the stack | ||||
| end | ||||
|  | ||||
|  | ||||
| local function retcount(...) | ||||
|     return select('#', ...), { ... } | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Function capture | ||||
|  | ||||
| local function functioncap(cs, out, valuetable) | ||||
|     local fce = valuetable[cs.ocap[cs.cap].idx] --  push function | ||||
|     local subout = { outindex = 0, out = {} } | ||||
|     local n = pushnestedvalues(cs, false, subout, valuetable); -- push nested captures | ||||
|     local count, ret = retcount(fce(unpack(subout.out, 1, n))) -- call function | ||||
|     for i = 1, count do | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = ret[i] | ||||
|     end | ||||
|     return count | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Select capture | ||||
|  | ||||
| local function numcap(cs, out, valuetable) | ||||
|     local idx = valuetable[cs.ocap[cs.cap].idx] -- value to select | ||||
|     -- no values? | ||||
|     if idx == 0 then | ||||
|         nextcap(cs); -- skip entire capture | ||||
|         return 0; -- no value produced | ||||
|     else | ||||
|         local subout = { outindex = 0, out = {} } | ||||
|         local n = pushnestedvalues(cs, false, subout, valuetable) | ||||
|         -- invalid index? | ||||
|         if n < idx then | ||||
|             error(("no capture '%d'"):format(idx), 0) | ||||
|         else | ||||
|             out.outindex = out.outindex + 1 | ||||
|             out.out[out.outindex] = subout.out[idx] -- get selected capture | ||||
|             return 1; | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Calls a runtime capture. Returns number of captures removed by | ||||
| -- the call, including the initial Cgroup. (Captures to be added are | ||||
| -- on the Lua stack.) | ||||
|  | ||||
| local function runtimecap(cs, close, s, out, valuetable) | ||||
|     local open = findopen(cs, close) | ||||
|     assert(cs.ocap[open].kind == Cgroup) | ||||
|     cs.ocap[close].kind = Cclose; -- closes the group | ||||
|     cs.ocap[close].s = s; | ||||
|     cs.cap = open; | ||||
|     local fce = valuetable[cs.ocap[cs.cap].idx] -- push function to be called | ||||
|     local subout = { outindex = 0, out = {} } | ||||
|     local n = pushnestedvalues(cs, false, subout, valuetable); -- push nested captures | ||||
|     local count, ret = retcount(fce(cs.s or cs.stream, s, unpack(subout.out, 1, n))) -- call dynamic function | ||||
|     for i = 1, count do | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = ret[i] | ||||
|     end | ||||
|     return close - open -- number of captures of all kinds removed | ||||
| end | ||||
|  | ||||
| -- Collect values from current capture into array 'cps'. Current | ||||
| -- capture must be Cstring (first call) or Csimple (recursive calls). | ||||
| -- (In first call, fills %0 with whole match for Cstring.) | ||||
| -- Returns number of elements in the array that were filled. | ||||
|  | ||||
| local function getstrcaps(cs, cps, n) | ||||
|     local k = n | ||||
|     n = n + 1 | ||||
|     cps[k + 1].isstring = true; -- get string value | ||||
|     cps[k + 1].startstr = cs.ocap[cs.cap].s; -- starts here | ||||
|     cs.cap = cs.cap + 1 | ||||
|     -- nested captures? | ||||
|     if cs.ocap[cs.cap - 1].siz == 0 then | ||||
|         -- traverse them | ||||
|         while cs.ocap[cs.cap].kind ~= Cclose do | ||||
|             -- too many captures? | ||||
|             if n >= MAXSTRCAPS then | ||||
|                 nextcap(cs); -- skip extra captures (will not need them) | ||||
|             elseif cs.ocap[cs.cap].kind == Csimple then | ||||
|                 -- string? | ||||
|                 n = getstrcaps(cs, cps, n); -- put info. into array | ||||
|             else | ||||
|                 cps[n + 1].isstring = false; -- not a string | ||||
|                 cps[n + 1].origcap = cs.cap; -- keep original capture | ||||
|                 nextcap(cs); | ||||
|                 n = n + 1; | ||||
|             end | ||||
|         end | ||||
|         cs.cap = cs.cap + 1 -- skip close | ||||
|     end | ||||
|     cps[k + 1].endstr = cs.ocap[cs.cap - 1].s + cs.ocap[cs.cap - 1].siz - 1 -- ends here | ||||
|     return n; | ||||
| end | ||||
|  | ||||
|  | ||||
| -- add next capture value (which should be a string) to buffer 'b' | ||||
|  | ||||
| -- String capture: add result to buffer 'b' (instead of pushing | ||||
| -- it into the stack) | ||||
|  | ||||
| local function stringcap(cs, b, valuetable) | ||||
|     local cps = {} | ||||
|     for i = 1, MAXSTRCAPS do | ||||
|         cps[#cps + 1] = {} | ||||
|     end | ||||
|     local fmt = valuetable[cs.ocap[cs.cap].idx] | ||||
|     local n = getstrcaps(cs, cps, 0) - 1; -- collect nested captures | ||||
|     local i = 1 | ||||
|     -- traverse them | ||||
|     while i <= #fmt do | ||||
|         local c = fmt:sub(i, i) | ||||
|         -- not an escape? | ||||
|         if c ~= '%' then | ||||
|             b[#b + 1] = c -- add it to buffer | ||||
|         elseif fmt:sub(i + 1, i + 1) < '0' or fmt:sub(i + 1, i + 1) > '9' then | ||||
|             -- not followed by a digit? | ||||
|             i = i + 1 | ||||
|             b[#b + 1] = fmt:sub(i, i) | ||||
|         else | ||||
|             i = i + 1 | ||||
|             local l = fmt:sub(i, i) - '0'; -- capture index | ||||
|             if l > n then | ||||
|                 error(("invalid capture index (%d)"):format(l), 0) | ||||
|             elseif cps[l + 1].isstring then | ||||
|                 b[#b + 1] = cs.s and cs.s:sub(cps[l + 1].startstr, cps[l + 1].endstr - cps[l + 1].startstr + cps[l + 1].startstr - 1) or | ||||
|                         cs.stream(cps[l + 1].startstr, cps[l + 1].endstr - cps[l + 1].startstr + cps[l + 1].startstr - 1) | ||||
|             else | ||||
|                 local curr = cs.cap; | ||||
|                 cs.cap = cps[l + 1].origcap; -- go back to evaluate that nested capture | ||||
|                 if not addonestring(cs, b, "capture", valuetable) then | ||||
|                     error(("no values in capture index %d"):format(l), 0) | ||||
|                 end | ||||
|                 cs.cap = curr; -- continue from where it stopped | ||||
|             end | ||||
|         end | ||||
|         i = i + 1 | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Substitution capture: add result to buffer 'b' | ||||
|  | ||||
| local function substcap(cs, b, valuetable) | ||||
|     local curr = cs.ocap[cs.cap].s; | ||||
|     -- no nested captures? | ||||
|     if cs.ocap[cs.cap].siz ~= 0 then | ||||
|         -- keep original text | ||||
|         b[#b + 1] = cs.s and cs.s:sub(curr, cs.ocap[cs.cap].siz - 1 + curr - 1) or | ||||
|                 cs.stream(curr, cs.ocap[cs.cap].siz - 1 + curr - 1) | ||||
|     else | ||||
|         cs.cap = cs.cap + 1 -- skip open entry | ||||
|         -- traverse nested captures | ||||
|         while cs.ocap[cs.cap].kind ~= Cclose do | ||||
|             local next = cs.ocap[cs.cap].s; | ||||
|             b[#b + 1] = cs.s and cs.s:sub(curr, next - curr + curr - 1) or | ||||
|                     cs.stream(curr, next - curr + curr - 1) -- add text up to capture | ||||
|             if addonestring(cs, b, "replacement", valuetable) then | ||||
|                 curr = cs.ocap[cs.cap - 1].s + cs.ocap[cs.cap - 1].siz - 1; -- continue after match | ||||
|             else | ||||
|                 -- no capture value | ||||
|                 curr = next; -- keep original text in final result | ||||
|             end | ||||
|         end | ||||
|         b[#b + 1] = cs.s and cs.s:sub(curr, curr + cs.ocap[cs.cap].s - curr - 1) or | ||||
|                 cs.stream(curr, curr + cs.ocap[cs.cap].s - curr - 1) -- add last piece of text | ||||
|     end | ||||
|     cs.cap = cs.cap + 1 -- go to next capture | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Evaluates a capture and adds its first value to buffer 'b'; returns | ||||
| -- whether there was a value | ||||
|  | ||||
| function addonestring(cs, b, what, valuetable) | ||||
|     local tag = cs.ocap[cs.cap].kind | ||||
|     if tag == Cstring then | ||||
|         stringcap(cs, b, valuetable); -- add capture directly to buffer | ||||
|         return 1 | ||||
|     elseif tag == Csubst then | ||||
|         substcap(cs, b, valuetable); -- add capture directly to buffer | ||||
|         return 1 | ||||
|     else | ||||
|         local subout = { outindex = 0, out = {} } | ||||
|         local n = pushcapture(cs, subout, valuetable); | ||||
|         if n > 0 then | ||||
|             if type(subout.out[1]) ~= 'string' and type(subout.out[1]) ~= 'number' then | ||||
|                 error(("invalid %s value (a %s)"):format(what, type(subout.out[1])), 0) | ||||
|             end | ||||
|             b[#b + 1] = subout.out[1] | ||||
|             return n | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Push all values of the current capture into the stack; returns | ||||
| -- number of values pushed | ||||
|  | ||||
| function pushcapture(cs, out, valuetable) | ||||
|     local type = cs.ocap[cs.cap].kind | ||||
|     if type == Cposition then | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = cs.ocap[cs.cap].s | ||||
|         cs.cap = cs.cap + 1; | ||||
|         return 1; | ||||
|     elseif type == Cconst then | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = valuetable[cs.ocap[cs.cap].idx] | ||||
|         cs.cap = cs.cap + 1 | ||||
|         return 1; | ||||
|     elseif type == Carg then | ||||
|         local arg = valuetable[cs.ocap[cs.cap].idx] | ||||
|         cs.cap = cs.cap + 1 | ||||
|         if arg > cs.ptopcount then | ||||
|             error(("reference to absent extra argument #%d"):format(arg), 0) | ||||
|         end | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = cs.ptop[arg] | ||||
|         return 1; | ||||
|     elseif type == Csimple then | ||||
|         local k = pushnestedvalues(cs, true, out, valuetable) | ||||
|         local index = out.outindex | ||||
|         table.insert(out.out, index - k + 1, out.out[index]) | ||||
|         out[index + 1] = nil | ||||
|         return k; | ||||
|     elseif type == Cruntime then | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = valuetable[cs.ocap[cs.cap].idx] | ||||
|         cs.cap = cs.cap + 1; | ||||
|         return 1; | ||||
|     elseif type == Cstring then | ||||
|         local b = {} | ||||
|         stringcap(cs, b, valuetable) | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = table.concat(b) | ||||
|         return 1; | ||||
|     elseif type == Csubst then | ||||
|         local b = {} | ||||
|         substcap(cs, b, valuetable); | ||||
|         out.outindex = out.outindex + 1 | ||||
|         out.out[out.outindex] = table.concat(b) | ||||
|         return 1; | ||||
|     elseif type == Cgroup then | ||||
|         -- anonymous group? | ||||
|         if cs.ocap[cs.cap].idx == 0 then | ||||
|             return pushnestedvalues(cs, false, out, valuetable); -- add all nested values | ||||
|         else | ||||
|             -- named group: add no values | ||||
|             nextcap(cs); -- skip capture | ||||
|             return 0 | ||||
|         end | ||||
|     elseif type == Cbackref then | ||||
|         return backrefcap(cs, out, valuetable) | ||||
|     elseif type == Ctable then | ||||
|         return tablecap(cs, out, valuetable) | ||||
|     elseif type == Cfunction then | ||||
|         return functioncap(cs, out, valuetable) | ||||
|     elseif type == Cnum then | ||||
|         return numcap(cs, out, valuetable) | ||||
|     elseif type == Cquery then | ||||
|         return querycap(cs, out, valuetable) | ||||
|     elseif type == Cfold then | ||||
|         return foldcap(cs, out, valuetable) | ||||
|     else | ||||
|         assert(false) | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| -- Prepare a CapState structure and traverse the entire list of | ||||
| -- captures in the stack pushing its results. 's' is the subject | ||||
| -- string, 'r' is the final position of the match, and 'ptop' | ||||
| -- the index in the stack where some useful values were pushed. | ||||
| -- Returns the number of results pushed. (If the list produces no | ||||
| -- results, push the final position of the match.) | ||||
|  | ||||
| local function getcaptures(capture, s, stream, r, valuetable, ...) | ||||
|     local n = 0; | ||||
|     local cs = { cap = 0 } | ||||
|     local out = { outindex = 0; out = {} } | ||||
|     -- is there any capture? | ||||
|     if capture[cs.cap].kind ~= Cclose then | ||||
|         cs.ocap = capture | ||||
|         cs.s = s; | ||||
|         cs.stream = stream | ||||
|         cs.ptopcount, cs.ptop = retcount(...) | ||||
|         repeat -- collect their values | ||||
|             n = n + pushcapture(cs, out, valuetable) | ||||
|         until cs.ocap[cs.cap].kind == Cclose | ||||
|     end | ||||
|     -- no capture values? | ||||
|     if n == 0 then | ||||
|         if not r then | ||||
|             return | ||||
|         else | ||||
|             return r | ||||
|         end | ||||
|     end | ||||
|     assert(out.outindex < 7998, "(too many captures)") | ||||
|     return unpack(out.out, 1, out.outindex) | ||||
| end | ||||
|  | ||||
| local function getcapturesruntime(capture, s, stream, notdelete, min, max, captop, valuetable, ...) | ||||
|     local n = 0; | ||||
|     local cs = { cap = min } | ||||
|     local out = { outindex = 0; out = {} } | ||||
|     cs.ocap = capture | ||||
|     cs.s = s | ||||
|     cs.stream = stream | ||||
|     cs.ptopcount, cs.ptop = retcount(...) | ||||
|     local start = 0 | ||||
|     repeat -- collect their values | ||||
|         if not checknextcap(cs, max) then break end | ||||
|         local notdelete = notdelete or capture[cs.cap].kind == Cgroup and capture[cs.cap].idx ~= 0 and capture[cs.cap].candelete == 0 | ||||
|         pushcapture(cs, out, valuetable) | ||||
|         if notdelete then | ||||
|             start = cs.cap | ||||
|         else | ||||
|             n = n + cs.cap - start | ||||
|             for i = 0, captop - cs.cap - 1 do | ||||
|                 ffi.copy(capture + start + i, capture + cs.cap + i, ffi.sizeof('CAPTURE')) | ||||
|             end | ||||
|             max = max - (cs.cap - start) | ||||
|             captop = captop - (cs.cap - start) | ||||
|             cs.cap = start | ||||
|         end | ||||
|     until cs.cap == max | ||||
|     assert(out.outindex < 7998, "(too many captures)") | ||||
|     return n, out.out, out.outindex | ||||
| end | ||||
|  | ||||
| return { | ||||
|     getcaptures = getcaptures, | ||||
|     runtimecap = runtimecap, | ||||
|     getcapturesruntime = getcapturesruntime, | ||||
| } | ||||
|  | ||||
							
								
								
									
										1057
									
								
								tools/lpeg/lpcode.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1057
									
								
								tools/lpeg/lpcode.lua
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1373
									
								
								tools/lpeg/lpeg.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1373
									
								
								tools/lpeg/lpeg.lua
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										356
									
								
								tools/lpeg/lpprint.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								tools/lpeg/lpprint.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,356 @@ | ||||
| --[[ | ||||
| LPEGLJ | ||||
| lpprint.lua | ||||
| Tree, code and debug print function (only for debuging) | ||||
| Copyright (C) 2014 Rostislav Sacek. | ||||
| based on LPeg v1.0 - PEG pattern matching for Lua | ||||
| Lua.org & PUC-Rio  written by Roberto Ierusalimschy | ||||
| http://www.inf.puc-rio.br/~roberto/lpeg/ | ||||
|  | ||||
| ** Permission is hereby granted, free of charge, to any person obtaining | ||||
| ** a copy of this software and associated documentation files (the | ||||
| ** "Software"), to deal in the Software without restriction, including | ||||
| ** without limitation the rights to use, copy, modify, merge, publish, | ||||
| ** distribute, sublicense, and/or sell copies of the Software, and to | ||||
| ** permit persons to whom the Software is furnished to do so, subject to | ||||
| ** the following conditions: | ||||
| ** | ||||
| ** The above copyright notice and this permission notice shall be | ||||
| ** included in all copies or substantial portions of the Software. | ||||
| ** | ||||
| ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
| ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||
| ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||
| ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||||
| ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| ** | ||||
| ** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] | ||||
| --]] | ||||
|  | ||||
| local ffi = require"ffi" | ||||
| local band, rshift, lshift = bit.band, bit.rshift, bit.lshift | ||||
|  | ||||
| ffi.cdef[[ | ||||
|   int isprint ( int c ); | ||||
| ]] | ||||
|  | ||||
| local RuleLR = 0x10000 | ||||
| local Ruleused = 0x20000 | ||||
|  | ||||
| -- {====================================================== | ||||
| -- Printing patterns (for debugging) | ||||
| -- ======================================================= | ||||
|  | ||||
| local TChar = 0 | ||||
| local TSet = 1 | ||||
| local TAny = 2 -- standard PEG elements | ||||
| local TTrue = 3 | ||||
| local TFalse = 4 | ||||
| local TRep = 5 | ||||
| local TSeq = 6 | ||||
| local TChoice = 7 | ||||
| local TNot = 8 | ||||
| local TAnd = 9 | ||||
| local TCall = 10 | ||||
| local TOpenCall = 11 | ||||
| local TRule = 12 -- sib1 is rule's pattern, sib2 is 'next' rule | ||||
| local TGrammar = 13 -- sib1 is initial (and first) rule | ||||
| local TBehind = 14 -- match behind | ||||
| local TCapture = 15 -- regular capture | ||||
| local TRunTime = 16 -- run-time capture | ||||
|  | ||||
| local IAny = 0 -- if no char, fail | ||||
| local IChar = 1 -- if char != aux, fail | ||||
| local ISet = 2 -- if char not in val, fail | ||||
| local ITestAny = 3 -- in no char, jump to 'offset' | ||||
| local ITestChar = 4 -- if char != aux, jump to 'offset' | ||||
| local ITestSet = 5 -- if char not in val, jump to 'offset' | ||||
| local ISpan = 6 -- read a span of chars in val | ||||
| local IBehind = 7 -- walk back 'aux' characters (fail if not possible) | ||||
| local IRet = 8 -- return from a rule | ||||
| local IEnd = 9 -- end of pattern | ||||
| local IChoice = 10 -- stack a choice; next fail will jump to 'offset' | ||||
| local IJmp = 11 -- jump to 'offset' | ||||
| local ICall = 12 -- call rule at 'offset' | ||||
| local IOpenCall = 13 -- call rule number 'offset' (must be closed to a ICall) | ||||
| local ICommit = 14 -- pop choice and jump to 'offset' | ||||
| local IPartialCommit = 15 -- update top choice to current position and jump | ||||
| local IBackCommit = 16 -- "fails" but jump to its own 'offset' | ||||
| local IFailTwice = 17 -- pop one choice and then fail | ||||
| local IFail = 18 -- go back to saved state on choice and jump to saved offset | ||||
| local IGiveup = 19 -- internal use | ||||
| local IFullCapture = 20 -- complete capture of last 'off' chars | ||||
| local IOpenCapture = 21 -- start a capture | ||||
| local ICloseCapture = 22 | ||||
| local ICloseRunTime = 23 | ||||
|  | ||||
| local Cclose = 0 | ||||
| local Cposition = 1 | ||||
| local Cconst = 2 | ||||
| local Cbackref = 3 | ||||
| local Carg = 4 | ||||
| local Csimple = 5 | ||||
| local Ctable = 6 | ||||
| local Cfunction = 7 | ||||
| local Cquery = 8 | ||||
| local Cstring = 9 | ||||
| local Cnum = 10 | ||||
| local Csubst = 11 | ||||
| local Cfold = 12 | ||||
| local Cruntime = 13 | ||||
| local Cgroup = 14 | ||||
|  | ||||
|  | ||||
| -- number of siblings for each tree | ||||
| local numsiblings = { | ||||
|     [TRep] = 1, | ||||
|     [TSeq] = 2, | ||||
|     [TChoice] = 2, | ||||
|     [TNot] = 1, | ||||
|     [TAnd] = 1, | ||||
|     [TRule] = 2, | ||||
|     [TGrammar] = 1, | ||||
|     [TBehind] = 1, | ||||
|     [TCapture] = 1, | ||||
|     [TRunTime] = 1, | ||||
| } | ||||
| local names = { | ||||
|     [IAny] = "any", | ||||
|     [IChar] = "char", | ||||
|     [ISet] = "set", | ||||
|     [ITestAny] = "testany", | ||||
|     [ITestChar] = "testchar", | ||||
|     [ITestSet] = "testset", | ||||
|     [ISpan] = "span", | ||||
|     [IBehind] = "behind", | ||||
|     [IRet] = "ret", | ||||
|     [IEnd] = "end", | ||||
|     [IChoice] = "choice", | ||||
|     [IJmp] = "jmp", | ||||
|     [ICall] = "call", | ||||
|     [IOpenCall] = "open_call", | ||||
|     [ICommit] = "commit", | ||||
|     [IPartialCommit] = "partial_commit", | ||||
|     [IBackCommit] = "back_commit", | ||||
|     [IFailTwice] = "failtwice", | ||||
|     [IFail] = "fail", | ||||
|     [IGiveup] = "giveup", | ||||
|     [IFullCapture] = "fullcapture", | ||||
|     [IOpenCapture] = "opencapture", | ||||
|     [ICloseCapture] = "closecapture", | ||||
|     [ICloseRunTime] = "closeruntime" | ||||
| } | ||||
|  | ||||
| local function printcharset(st) | ||||
|     io.write("["); | ||||
|     local i = 0 | ||||
|     while i <= 255 do | ||||
|         local first = i; | ||||
|         while band(st[rshift(i, 5)], lshift(1, band(i, 31))) ~= 0 and i <= 255 do | ||||
|             i = i + 1 | ||||
|         end | ||||
|         if i - 1 == first then -- unary range? | ||||
|             io.write(("(%02x)"):format(first)) | ||||
|         elseif i - 1 > first then -- non-empty range? | ||||
|             io.write(("(%02x-%02x)"):format(first, i - 1)) | ||||
|         end | ||||
|         i = i + 1 | ||||
|     end | ||||
|     io.write("]") | ||||
| end | ||||
|  | ||||
| local modes = { | ||||
|     [Cclose] = "close", | ||||
|     [Cposition] = "position", | ||||
|     [Cconst] = "constant", | ||||
|     [Cbackref] = "backref", | ||||
|     [Carg] = "argument", | ||||
|     [Csimple] = "simple", | ||||
|     [Ctable] = "table", | ||||
|     [Cfunction] = "function", | ||||
|     [Cquery] = "query", | ||||
|     [Cstring] = "string", | ||||
|     [Cnum] = "num", | ||||
|     [Csubst] = "substitution", | ||||
|     [Cfold] = "fold", | ||||
|     [Cruntime] = "runtime", | ||||
|     [Cgroup] = "group" | ||||
| } | ||||
|  | ||||
| local function printcapkind(kind) | ||||
|     io.write(("%s"):format(modes[kind])) | ||||
| end | ||||
|  | ||||
| local function printjmp(p, index) | ||||
|     io.write(("-> %d"):format(index + p[index].offset)) | ||||
| end | ||||
|  | ||||
| local function printrulename(p, index, rulenames) | ||||
|     if rulenames and rulenames[index + p[index].offset] then | ||||
|         io.write(' ', rulenames[index + p[index].offset]) | ||||
|     end | ||||
| end | ||||
|  | ||||
| local function printinst(p, index, valuetable, rulenames) | ||||
|     local code = p[index].code | ||||
|     if rulenames and rulenames[index] then | ||||
|         io.write(rulenames[index], '\n') | ||||
|     end | ||||
|     io.write(("%04d: %s "):format(index, names[code])) | ||||
|     if code == IChar then | ||||
|         io.write(("'%s'"):format(string.char(p[index].val))) | ||||
|     elseif code == ITestChar then | ||||
|         io.write(("'%s'"):format(string.char(p[index].val))) | ||||
|         printjmp(p, index) | ||||
|         printrulename(p, index, rulenames) | ||||
|     elseif code == IFullCapture then | ||||
|         printcapkind(band(p[index].val, 0x0f)); | ||||
|         io.write((" (size = %d)  (idx = %s)"):format(band(rshift(p[index].val, 4), 0xF), tostring(valuetable[p[index].offset]))) | ||||
|     elseif code == IOpenCapture then | ||||
|         printcapkind(band(p[index].val, 0x0f)) | ||||
|         io.write((" (idx = %s)"):format(tostring(valuetable[p[index].offset]))) | ||||
|     elseif code == ISet then | ||||
|         printcharset(valuetable[p[index].val]); | ||||
|     elseif code == ITestSet then | ||||
|         printcharset(valuetable[p[index].val]) | ||||
|         printjmp(p, index); | ||||
|         printrulename(p, index, rulenames) | ||||
|     elseif code == ISpan then | ||||
|         printcharset(valuetable[p[index].val]); | ||||
|     elseif code == IOpenCall then | ||||
|         io.write(("-> %d"):format(p[index].offset)) | ||||
|     elseif code == IBehind then | ||||
|         io.write(("%d"):format(p[index].val)) | ||||
|     elseif code == IJmp or code == ICall or code == ICommit or code == IChoice or | ||||
|             code == IPartialCommit or code == IBackCommit or code == ITestAny then | ||||
|         printjmp(p, index); | ||||
|         if (code == ICall or code == IJmp) and p[index].aux > 0 then | ||||
|             io.write(' ', valuetable[p[index].aux]) | ||||
|         else | ||||
|             printrulename(p, index, rulenames) | ||||
|         end | ||||
|     end | ||||
|     io.write("\n") | ||||
| end | ||||
|  | ||||
|  | ||||
| local function printpatt(p, valuetable) | ||||
|     local ruleNames = {} | ||||
|     for i = 0, p.size - 1 do | ||||
|         local code = p.p[i].code | ||||
|         if (code == ICall or code == IJmp) and p.p[i].aux > 0 then | ||||
|             local index = i + p.p[i].offset | ||||
|             ruleNames[index] = valuetable[p.p[i].aux] | ||||
|         end | ||||
|     end | ||||
|     for i = 0, p.size - 1 do | ||||
|         printinst(p.p, i, valuetable, ruleNames) | ||||
|     end | ||||
| end | ||||
|  | ||||
|  | ||||
| local function printcap(cap, index, valuetable) | ||||
|     printcapkind(cap[index].kind) | ||||
|     io.write((" (idx: %s - size: %d) -> %d\n"):format(valuetable[cap[index].idx], cap[index].siz, cap[index].s)) | ||||
| end | ||||
|  | ||||
|  | ||||
| local function printcaplist(cap, limit, valuetable) | ||||
|     io.write(">======\n") | ||||
|     local index = 0 | ||||
|     while cap[index].s and index < limit do | ||||
|         printcap(cap, index, valuetable) | ||||
|         index = index + 1 | ||||
|     end | ||||
|     io.write("=======\n") | ||||
| end | ||||
|  | ||||
| -- ====================================================== | ||||
|  | ||||
|  | ||||
|  | ||||
| -- {====================================================== | ||||
| -- Printing trees (for debugging) | ||||
| -- ======================================================= | ||||
|  | ||||
| local tagnames = { | ||||
|     [TChar] = "char", | ||||
|     [TSet] = "set", | ||||
|     [TAny] = "any", | ||||
|     [TTrue] = "true", | ||||
|     [TFalse] = "false", | ||||
|     [TRep] = "rep", | ||||
|     [TSeq] = "seq", | ||||
|     [TChoice] = "choice", | ||||
|     [TNot] = "not", | ||||
|     [TAnd] = "and", | ||||
|     [TCall] = "call", | ||||
|     [TOpenCall] = "opencall", | ||||
|     [TRule] = "rule", | ||||
|     [TGrammar] = "grammar", | ||||
|     [TBehind] = "behind", | ||||
|     [TCapture] = "capture", | ||||
|     [TRunTime] = "run-time" | ||||
| } | ||||
|  | ||||
|  | ||||
| local function printtree(tree, ident, index, valuetable) | ||||
|     for i = 1, ident do | ||||
|         io.write(" ") | ||||
|     end | ||||
|     local tag = tree[index].tag | ||||
|     io.write(("%s"):format(tagnames[tag])) | ||||
|     if tag == TChar then | ||||
|         local c = tree[index].val | ||||
|         if ffi.C.isprint(c) then | ||||
|             io.write((" '%c'\n"):format(c)) | ||||
|         else | ||||
|             io.write((" (%02X)\n"):format(c)) | ||||
|         end | ||||
|     elseif tag == TSet then | ||||
|         printcharset(valuetable[tree[index].val]); | ||||
|         io.write("\n") | ||||
|     elseif tag == TOpenCall or tag == TCall then | ||||
|         io.write((" key: %s\n"):format(tostring(valuetable[tree[index].val]))) | ||||
|     elseif tag == TBehind then | ||||
|         io.write((" %d\n"):format(tree[index].val)) | ||||
|         printtree(tree, ident + 2, index + 1, valuetable); | ||||
|     elseif tag == TCapture then | ||||
|         io.write((" cap: %s   n: %s\n"):format(modes[bit.band(tree[index].cap, 0xffff)], valuetable[tree[index].val])) | ||||
|         printtree(tree, ident + 2, index + 1, valuetable); | ||||
|     elseif tag == TRule then | ||||
|         local extra = bit.band(tree[index].cap, RuleLR) == RuleLR and ' left recursive' or '' | ||||
|         extra = extra .. (bit.band(tree[index].cap, Ruleused) ~= Ruleused and ' not used' or '') | ||||
|         io.write((" n: %d  key: %s%s\n"):format(bit.band(tree[index].cap, 0xffff) - 1, valuetable[tree[index].val], extra)) | ||||
|         printtree(tree, ident + 2, index + 1, valuetable); | ||||
|         -- do not print next rule as a sibling | ||||
|     elseif tag == TGrammar then | ||||
|         local ruleindex = index + 1 | ||||
|         io.write((" %d\n"):format(tree[index].val)) -- number of rules | ||||
|         for i = 1, tree[index].val do | ||||
|             printtree(tree, ident + 2, ruleindex, valuetable); | ||||
|             ruleindex = ruleindex + tree[ruleindex].ps | ||||
|         end | ||||
|         assert(tree[ruleindex].tag == TTrue); -- sentinel | ||||
|     else | ||||
|         local sibs = numsiblings[tree[index].tag] or 0 | ||||
|         io.write("\n") | ||||
|         if sibs >= 1 then | ||||
|             printtree(tree, ident + 2, index + 1, valuetable); | ||||
|             if sibs >= 2 then | ||||
|                 printtree(tree, ident + 2, index + tree[index].ps, valuetable) | ||||
|             end | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
| -- }====================================================== */ | ||||
|  | ||||
| return { | ||||
|     printtree = printtree, | ||||
|     printpatt = printpatt, | ||||
|     printcaplist = printcaplist, | ||||
|     printinst = printinst | ||||
| } | ||||
							
								
								
									
										1041
									
								
								tools/lpeg/lpvm.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1041
									
								
								tools/lpeg/lpvm.lua
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										286
									
								
								tools/lpeg/re.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								tools/lpeg/re.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,286 @@ | ||||
| -- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $ | ||||
| -- 2014/08/15 changes rostislav | ||||
|  | ||||
| -- imported functions and modules | ||||
| local tonumber, print, error = tonumber, print, error | ||||
| local setmetatable = setmetatable | ||||
| local m = require"lpeglj" | ||||
|  | ||||
| -- 'm' will be used to parse expressions, and 'mm' will be used to | ||||
| -- create expressions; that is, 're' runs on 'm', creating patterns | ||||
| -- on 'mm' | ||||
| local mm = m | ||||
|  | ||||
| -- pattern's metatable | ||||
| local mt = getmetatable(mm.P(0)) | ||||
| mt = m.version() == "1.0.0.0LJ" and m or mt | ||||
|  | ||||
|  | ||||
|  | ||||
| -- No more global accesses after this point | ||||
| local version = _VERSION | ||||
| if version == "Lua 5.2" then _ENV = nil end | ||||
|  | ||||
|  | ||||
| local any = m.P(1) | ||||
|  | ||||
|  | ||||
| -- Pre-defined names | ||||
| local Predef = { nl = m.P"\n" } | ||||
|  | ||||
|  | ||||
| local mem | ||||
| local fmem | ||||
| local gmem | ||||
|  | ||||
|  | ||||
| local function updatelocale () | ||||
|   mm.locale(Predef) | ||||
|   Predef.a = Predef.alpha | ||||
|   Predef.c = Predef.cntrl | ||||
|   Predef.d = Predef.digit | ||||
|   Predef.g = Predef.graph | ||||
|   Predef.l = Predef.lower | ||||
|   Predef.p = Predef.punct | ||||
|   Predef.s = Predef.space | ||||
|   Predef.u = Predef.upper | ||||
|   Predef.w = Predef.alnum | ||||
|   Predef.x = Predef.xdigit | ||||
|   Predef.A = any - Predef.a | ||||
|   Predef.C = any - Predef.c | ||||
|   Predef.D = any - Predef.d | ||||
|   Predef.G = any - Predef.g | ||||
|   Predef.L = any - Predef.l | ||||
|   Predef.P = any - Predef.p | ||||
|   Predef.S = any - Predef.s | ||||
|   Predef.U = any - Predef.u | ||||
|   Predef.W = any - Predef.w | ||||
|   Predef.X = any - Predef.x | ||||
|   mem = {}    -- restart memoization | ||||
|   fmem = {} | ||||
|   gmem = {} | ||||
|   local mt = {__mode = "v"} | ||||
|   setmetatable(mem, mt) | ||||
|   setmetatable(fmem, mt) | ||||
|   setmetatable(gmem, mt) | ||||
| end | ||||
|  | ||||
|  | ||||
| updatelocale() | ||||
|  | ||||
|  | ||||
|  | ||||
| local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end) | ||||
|  | ||||
|  | ||||
| local function getdef (id, defs) | ||||
|   local c = defs and defs[id] | ||||
|   if not c then error("undefined name: " .. id) end | ||||
|   return c | ||||
| end | ||||
|  | ||||
|  | ||||
| local function patt_error (s, i) | ||||
|   local msg = (#s < i + 20) and s:sub(i) | ||||
|                              or s:sub(i,i+20) .. "..." | ||||
|   msg = ("pattern error near '%s'"):format(msg) | ||||
|   error(msg, 2) | ||||
| end | ||||
|  | ||||
| local function mult (p, n) | ||||
|   local np = mm.P(true) | ||||
|   while n >= 1 do | ||||
|     if n%2 >= 1 then np = np * p end | ||||
|     p = p * p | ||||
|     n = n/2 | ||||
|   end | ||||
|   return np | ||||
| end | ||||
|  | ||||
| local function equalcap (s, i, c) | ||||
|   if type(c) ~= "string" then return nil end | ||||
|   local e = #c + i | ||||
|   if type(s) == 'function' then  -- stream mode | ||||
|       if s(i, e - 1) == c then return e else return nil end | ||||
|   else | ||||
|       if s:sub(i, e - 1) == c then return e else return nil end | ||||
|   end | ||||
| end | ||||
|  | ||||
|  | ||||
| local S = (Predef.space + "--" * (any - Predef.nl)^0)^0 | ||||
|  | ||||
| local name = m.R("AZ", "az", "__") * m.R("AZ", "az", "__", "09")^0 | ||||
|  | ||||
| local arrow = S * "<-" | ||||
|  | ||||
| local seq_follow = m.P"/" + ")" + "}" + ":}" + "~}" + "|}" + (name * arrow) + -1 | ||||
|  | ||||
| name = m.C(name) | ||||
|  | ||||
|  | ||||
| -- a defined name only have meaning in a given environment | ||||
| local Def = name * m.Carg(1) | ||||
|  | ||||
| local num = m.C(m.R"09"^1) * S / tonumber | ||||
|  | ||||
| local String = "'" * m.C((any - "'")^0) * "'" + | ||||
|                '"' * m.C((any - '"')^0) * '"' | ||||
|  | ||||
|  | ||||
| local defined = "%" * Def / function (c,Defs) | ||||
|   local cat =  Defs and Defs[c] or Predef[c] | ||||
|   if not cat then error ("name '" .. c .. "' undefined") end | ||||
|   return cat | ||||
| end | ||||
|  | ||||
| local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R | ||||
|  | ||||
| local item = defined + Range + m.C(any) | ||||
|  | ||||
| local Class = | ||||
|     "[" | ||||
|   * (m.C(m.P"^"^-1))    -- optional complement symbol | ||||
|   * m.Cf(item * (item - "]")^0, mt.__add) / | ||||
|                           function (c, p) return c == "^" and any - p or p end | ||||
|   * "]" | ||||
|  | ||||
| local function adddef (t, k, exp) | ||||
|   if t[k] then | ||||
|     error("'"..k.."' already defined as a rule") | ||||
|   else | ||||
|     t[k] = exp | ||||
|   end | ||||
|   return t | ||||
| end | ||||
|  | ||||
| local function firstdef (n, r) return adddef({n}, n, r) end | ||||
|  | ||||
|  | ||||
| local function NT (n, b, p) | ||||
|   if not b then | ||||
|     error("rule '"..n.."' used outside a grammar") | ||||
|   else return mm.V(n, p or 0) | ||||
|   end | ||||
| end | ||||
|  | ||||
|  | ||||
| local exp = m.P{ "Exp", | ||||
|   Exp = S * ( m.V"Grammar" | ||||
|             + m.Cf(m.V"Seq" * ("/" * S * m.V"Seq")^0, mt.__add) ); | ||||
|   Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^0 , mt.__mul) | ||||
|         * (#seq_follow + patt_error); | ||||
|   Prefix = "&" * S * m.V"Prefix" / mt.__len | ||||
|          + "!" * S * m.V"Prefix" / mt.__unm | ||||
|          + m.V"Suffix"; | ||||
|   Suffix = m.Cf(m.V"Primary" * S * | ||||
|           ( ( m.P"+" * m.Cc(1, mt.__pow) | ||||
|             + m.P"*" * m.Cc(0, mt.__pow) | ||||
|             + m.P"?" * m.Cc(-1, mt.__pow) | ||||
|             + "^" * ( m.Cg(num * m.Cc(mult)) | ||||
|                     + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow)) | ||||
|                     ) | ||||
|             + "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div)) | ||||
|                          + m.P"{}" * m.Cc(nil, m.Ct) | ||||
|                          + m.Cg(Def / getdef * m.Cc(mt.__div)) | ||||
|                          ) | ||||
|             + "=>" * S * m.Cg(Def / getdef * m.Cc(m.Cmt)) | ||||
|             ) * S | ||||
|           )^0, function (a,b,f) return f(a,b) end ); | ||||
|   Primary = "(" * m.V"Exp" * ")" | ||||
|             + String / mm.P | ||||
|             + Class | ||||
|             + defined | ||||
|             + "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" / | ||||
|                      function (n, p) return mm.Cg(p, n) end | ||||
|             + "=" * name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end | ||||
|             + m.P"{}" / mm.Cp | ||||
|             + "{~" * m.V"Exp" * "~}" / mm.Cs | ||||
|             + "{|" * m.V"Exp" * "|}" / mm.Ct | ||||
|             + "{" * m.V"Exp" * "}" / mm.C | ||||
|             + m.P"." * m.Cc(any) | ||||
|             + (name * m.Cb("G") * (S * ":" * S * num)^-1 * -arrow + "<" * name * m.Cb("G") * (S * ":" * S * num)^-1 * ">") / NT; | ||||
|   Definition = name * arrow * m.V"Exp"; | ||||
|   Grammar = m.Cg(m.Cc(true), "G") * | ||||
|             m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, | ||||
|               adddef) / mm.P | ||||
| } | ||||
|  | ||||
| local pattern = S * m.Cg(m.Cc(false), "G") * exp / mm.P * (-any + patt_error) | ||||
|  | ||||
|  | ||||
| local function compile (p, defs) | ||||
|   if mm.type(p) == "pattern" then return p end   -- already compiled | ||||
|   local cp = pattern:match(p, 1, defs) | ||||
|   if not cp then error("incorrect pattern", 3) end | ||||
|   return cp | ||||
| end | ||||
|  | ||||
| local function match (s, p, i) | ||||
|   local cp = mem[p] | ||||
|   if not cp then | ||||
|     cp = compile(p) | ||||
|     mem[p] = cp | ||||
|   end | ||||
|   return cp:match(s, i or 1) | ||||
| end | ||||
|  | ||||
| local function streammatch (p, i) | ||||
|     local cp = mem[p] | ||||
|     if not cp then | ||||
|         cp = compile(p) | ||||
|         mem[p] = cp | ||||
|     end | ||||
|     return cp:streammatch(i or 1) | ||||
| end | ||||
|  | ||||
| -- Only for testing purpose | ||||
| local function emulatestreammatch(s, p, i) | ||||
|     local cp = mem[p] | ||||
|     if not cp then | ||||
|         cp = compile(p) | ||||
|         mem[p] = cp | ||||
|     end | ||||
|     return cp:emulatestreammatch(s, i or 1) | ||||
| end | ||||
|  | ||||
| local function find (s, p, i) | ||||
|   local cp = fmem[p] | ||||
|   if not cp then | ||||
|     cp = compile(p) / 0 | ||||
|     cp = mm.P{ mm.Cp() * cp * mm.Cp() + 1 * mm.V(1) } | ||||
|     fmem[p] = cp | ||||
|   end | ||||
|   local i, e = cp:match(s, i or 1) | ||||
|   if i then return i, e - 1 | ||||
|   else return i | ||||
|   end | ||||
| end | ||||
|  | ||||
| local function gsub (s, p, rep) | ||||
|   local g = gmem[p] or {}   -- ensure gmem[p] is not collected while here | ||||
|   gmem[p] = g | ||||
|   local cp = g[rep] | ||||
|   if not cp then | ||||
|     cp = compile(p) | ||||
|     cp = mm.Cs((cp / rep + 1)^0) | ||||
|     g[rep] = cp | ||||
|   end | ||||
|   return cp:match(s) | ||||
| end | ||||
|  | ||||
|  | ||||
| -- exported names | ||||
| local re = { | ||||
|   compile = compile, | ||||
|   match = match, | ||||
|   streammatch = streammatch, | ||||
|   emulatestreammatch = emulatestreammatch, | ||||
|   find = find, | ||||
|   gsub = gsub, | ||||
|   updatelocale = updatelocale, | ||||
| } | ||||
|  | ||||
| if version == "Lua 5.1" then _G.re = re end | ||||
|  | ||||
| return re | ||||
							
								
								
									
										25
									
								
								tools/luajson/json.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tools/luajson/json.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| package.path = package.path .. ";lpeg/?.lua" | ||||
| local decode = require("json.decode") | ||||
| local encode = require("json.encode") | ||||
| local util = require("json.util") | ||||
|  | ||||
| local _G = _G | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local json = { | ||||
| 	_VERSION = "1.3.4", | ||||
| 	_DESCRIPTION = "LuaJSON : customizable JSON decoder/encoder", | ||||
| 	_COPYRIGHT = "Copyright (c) 2007-2014 Thomas Harning Jr. <harningt@gmail.com>", | ||||
| 	decode = decode, | ||||
| 	encode = encode, | ||||
| 	util = util | ||||
| } | ||||
|  | ||||
| _G.json = json | ||||
|  | ||||
| return json | ||||
							
								
								
									
										171
									
								
								tools/luajson/json/decode.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								tools/luajson/json/decode.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local lpeg = require("lpeg") | ||||
|  | ||||
| local error = error | ||||
| local pcall = pcall | ||||
|  | ||||
| local jsonutil = require("json.util") | ||||
| local merge = jsonutil.merge | ||||
| local util = require("json.decode.util") | ||||
|  | ||||
| local decode_state = require("json.decode.state") | ||||
|  | ||||
| local setmetatable, getmetatable = setmetatable, getmetatable | ||||
| local assert = assert | ||||
| local ipairs, pairs = ipairs, pairs | ||||
| local string_char = require("string").char | ||||
|  | ||||
| local type = type | ||||
|  | ||||
| local require = require | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local modulesToLoad = { | ||||
| 	"composite", | ||||
| 	"strings", | ||||
| 	"number", | ||||
| 	"others" | ||||
| } | ||||
| local loadedModules = { | ||||
| } | ||||
|  | ||||
| local json_decode = {} | ||||
|  | ||||
| json_decode.default = { | ||||
| 	unicodeWhitespace = true, | ||||
| 	initialObject = false, | ||||
| 	nothrow = false | ||||
| } | ||||
|  | ||||
| local modes_defined = { "default", "strict", "simple" } | ||||
|  | ||||
| json_decode.simple = {} | ||||
|  | ||||
| json_decode.strict = { | ||||
| 	unicodeWhitespace = true, | ||||
| 	initialObject = true, | ||||
| 	nothrow = false | ||||
| } | ||||
|  | ||||
| for _,name in ipairs(modulesToLoad) do | ||||
| 	local mod = require("json.decode." .. name) | ||||
| 	if mod.mergeOptions then | ||||
| 		for _, mode in pairs(modes_defined) do | ||||
| 			mod.mergeOptions(json_decode[mode], mode) | ||||
| 		end | ||||
| 	end | ||||
| 	loadedModules[#loadedModules + 1] = mod | ||||
| end | ||||
|  | ||||
| -- Shift over default into defaultOptions to permit build optimization | ||||
| local defaultOptions = json_decode.default | ||||
| json_decode.default = nil | ||||
|  | ||||
| local function generateDecoder(lexer, options) | ||||
| 	-- Marker to permit detection of final end | ||||
| 	local marker = {} | ||||
| 	local parser = lpeg.Ct((options.ignored * lexer)^0 * lpeg.Cc(marker)) * options.ignored * (lpeg.P(-1) + util.unexpected()) | ||||
| 	local decoder = function(data) | ||||
| 		local state = decode_state.create(options) | ||||
| 		local parsed = parser:match(data) | ||||
| 		assert(parsed, "Invalid JSON data") | ||||
| 		local i = 0 | ||||
| 		while true do | ||||
| 			i = i + 1 | ||||
| 			local item = parsed[i] | ||||
| 			if item == marker then break end | ||||
| 			if type(item) == 'function' and item ~= jsonutil.undefined and item ~= jsonutil.null then | ||||
| 				item(state) | ||||
| 			else | ||||
| 				state:set_value(item) | ||||
| 			end | ||||
| 		end | ||||
| 		if options.initialObject then | ||||
| 			assert(type(state.previous) == 'table', "Initial value not an object or array") | ||||
| 		end | ||||
| 		-- Make sure stack is empty | ||||
| 		assert(state.i == 0, "Unclosed elements present") | ||||
| 		return state.previous | ||||
| 	end | ||||
| 	if options.nothrow then | ||||
| 		return function(data) | ||||
| 			local status, rv = pcall(decoder, data) | ||||
| 			if status then | ||||
| 				return rv | ||||
| 			else | ||||
| 				return nil, rv | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	return decoder | ||||
| end | ||||
|  | ||||
| local function buildDecoder(mode) | ||||
| 	mode = mode and merge({}, defaultOptions, mode) or defaultOptions | ||||
| 	for _, mod in ipairs(loadedModules) do | ||||
| 		if mod.mergeOptions then | ||||
| 			mod.mergeOptions(mode) | ||||
| 		end | ||||
| 	end | ||||
| 	local ignored = mode.unicodeWhitespace and util.unicode_ignored or util.ascii_ignored | ||||
| 	-- Store 'ignored' in the global options table | ||||
| 	mode.ignored = ignored | ||||
|  | ||||
| 	--local grammar = { | ||||
| 	--	[1] = mode.initialObject and (ignored * (object_type + array_type)) or value_type | ||||
| 	--} | ||||
| 	local lexer | ||||
| 	for _, mod in ipairs(loadedModules) do | ||||
| 		local new_lexer = mod.generateLexer(mode) | ||||
| 		lexer = lexer and lexer + new_lexer or new_lexer | ||||
| 	end | ||||
| 	return generateDecoder(lexer, mode) | ||||
| end | ||||
|  | ||||
| -- Since 'default' is nil, we cannot take map it | ||||
| local defaultDecoder = buildDecoder(json_decode.default) | ||||
| local prebuilt_decoders = {} | ||||
| for _, mode in pairs(modes_defined) do | ||||
| 	if json_decode[mode] ~= nil then | ||||
| 		prebuilt_decoders[json_decode[mode]] = buildDecoder(json_decode[mode]) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| Options: | ||||
| 	number => number decode options | ||||
| 	string => string decode options | ||||
| 	array  => array decode options | ||||
| 	object => object decode options | ||||
| 	initialObject => whether or not to require the initial object to be a table/array | ||||
| 	allowUndefined => whether or not to allow undefined values | ||||
| ]] | ||||
| local function getDecoder(mode) | ||||
| 	mode = mode == true and json_decode.strict or mode or json_decode.default | ||||
| 	local decoder = mode == nil and defaultDecoder or prebuilt_decoders[mode] | ||||
| 	if decoder then | ||||
| 		return decoder | ||||
| 	end | ||||
| 	return buildDecoder(mode) | ||||
| end | ||||
|  | ||||
| local function decode(data, mode) | ||||
| 	local decoder = getDecoder(mode) | ||||
| 	return decoder(data) | ||||
| end | ||||
|  | ||||
| local mt = {} | ||||
| mt.__call = function(self, ...) | ||||
| 	return decode(...) | ||||
| end | ||||
|  | ||||
| json_decode.getDecoder = getDecoder | ||||
| json_decode.decode = decode | ||||
| json_decode.util = util | ||||
| setmetatable(json_decode, mt) | ||||
|  | ||||
| return json_decode | ||||
							
								
								
									
										190
									
								
								tools/luajson/json/decode/composite.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								tools/luajson/json/decode/composite.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local pairs = pairs | ||||
| local type = type | ||||
|  | ||||
| local lpeg = require("lpeg") | ||||
|  | ||||
| local util = require("json.decode.util") | ||||
| local jsonutil = require("json.util") | ||||
|  | ||||
| local rawset = rawset | ||||
|  | ||||
| local assert = assert | ||||
| local tostring = tostring | ||||
|  | ||||
| local error = error | ||||
| local getmetatable = getmetatable | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	array = { | ||||
| 		trailingComma = true | ||||
| 	}, | ||||
| 	object = { | ||||
| 		trailingComma = true, | ||||
| 		number = true, | ||||
| 		identifier = true, | ||||
| 		setObjectKey = rawset | ||||
| 	}, | ||||
| 	calls = { | ||||
| 		defs = nil, | ||||
| 		-- By default, do not allow undefined calls to be de-serialized as call objects | ||||
| 		allowUndefined = false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| local modeOptions = { | ||||
| 	default = nil, | ||||
| 	strict = { | ||||
| 		array = { | ||||
| 			trailingComma = false | ||||
| 		}, | ||||
| 		object = { | ||||
| 			trailingComma = false, | ||||
| 			number = false, | ||||
| 			identifier = false | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| local function BEGIN_ARRAY(state) | ||||
| 	state:push() | ||||
| 	state:new_array() | ||||
| end | ||||
| local function END_ARRAY(state) | ||||
| 	state:end_array() | ||||
| 	state:pop() | ||||
| end | ||||
|  | ||||
| local function BEGIN_OBJECT(state) | ||||
| 	state:push() | ||||
| 	state:new_object() | ||||
| end | ||||
| local function END_OBJECT(state) | ||||
| 	state:end_object() | ||||
| 	state:pop() | ||||
| end | ||||
|  | ||||
| local function END_CALL(state) | ||||
| 	state:end_call() | ||||
| 	state:pop() | ||||
| end | ||||
|  | ||||
| local function SET_KEY(state) | ||||
| 	state:set_key() | ||||
| end | ||||
|  | ||||
| local function NEXT_VALUE(state) | ||||
| 	state:put_value() | ||||
| end | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, true, 'array', defaultOptions, mode and modeOptions[mode]) | ||||
| 	jsonutil.doOptionMerge(options, true, 'object', defaultOptions, mode and modeOptions[mode]) | ||||
| 	jsonutil.doOptionMerge(options, true, 'calls', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
|  | ||||
| local isPattern | ||||
| if lpeg.type then | ||||
| 	function isPattern(value) | ||||
| 		return lpeg.type(value) == 'pattern' | ||||
| 	end | ||||
| else | ||||
| 	local metaAdd = getmetatable(lpeg.P("")).__add | ||||
| 	function isPattern(value) | ||||
| 		return getmetatable(value).__add == metaAdd | ||||
| 	end | ||||
| end | ||||
|  | ||||
|  | ||||
| local function generateSingleCallLexer(name, func) | ||||
| 	if type(name) ~= 'string' and not isPattern(name) then | ||||
| 		error("Invalid functionCalls name: " .. tostring(name) .. " not a string or LPEG pattern") | ||||
| 	end | ||||
| 	-- Allow boolean or function to match up w/ encoding permissions | ||||
| 	if type(func) ~= 'boolean' and type(func) ~= 'function' then | ||||
| 		error("Invalid functionCalls item: " .. name .. " not a function") | ||||
| 	end | ||||
| 	local function buildCallCapture(name) | ||||
| 		return function(state) | ||||
| 			if func == false then | ||||
| 				error("Function call on '" .. name .. "' not permitted") | ||||
| 			end | ||||
| 			state:push() | ||||
| 			state:new_call(name, func) | ||||
| 		end | ||||
| 	end | ||||
| 	local nameCallCapture | ||||
| 	if type(name) == 'string' then | ||||
| 		nameCallCapture = lpeg.P(name .. "(") * lpeg.Cc(name) / buildCallCapture | ||||
| 	else | ||||
| 		-- Name matcher expected to produce a capture | ||||
| 		nameCallCapture = name * "(" / buildCallCapture | ||||
| 	end | ||||
| 	-- Call func over nameCallCapture and value to permit function receiving name | ||||
| 	return nameCallCapture | ||||
| end | ||||
|  | ||||
| local function generateNamedCallLexers(options) | ||||
| 	if not options.calls or not options.calls.defs then | ||||
| 		return | ||||
| 	end | ||||
| 	local callCapture | ||||
| 	for name, func in pairs(options.calls.defs) do | ||||
| 		local newCapture = generateSingleCallLexer(name, func) | ||||
| 		if not callCapture then | ||||
| 			callCapture = newCapture | ||||
| 		else | ||||
| 			callCapture = callCapture + newCapture | ||||
| 		end | ||||
| 	end | ||||
| 	return callCapture | ||||
| end | ||||
|  | ||||
| local function generateCallLexer(options) | ||||
| 	local lexer | ||||
| 	local namedCapture = generateNamedCallLexers(options) | ||||
| 	if options.calls and options.calls.allowUndefined then | ||||
| 		lexer = generateSingleCallLexer(lpeg.C(util.identifier), true) | ||||
| 	end | ||||
| 	if namedCapture then | ||||
| 		lexer = lexer and lexer + namedCapture or namedCapture | ||||
| 	end | ||||
| 	if lexer then | ||||
| 		lexer = lexer + lpeg.P(")") * lpeg.Cc(END_CALL) | ||||
| 	end | ||||
| 	return lexer | ||||
| end | ||||
|  | ||||
| local function generateLexer(options) | ||||
| 	local ignored = options.ignored | ||||
| 	local array_options, object_options = options.array, options.object | ||||
| 	local lexer = | ||||
| 		lpeg.P("[") * lpeg.Cc(BEGIN_ARRAY) | ||||
| 		+ lpeg.P("]") * lpeg.Cc(END_ARRAY) | ||||
| 		+ lpeg.P("{") * lpeg.Cc(BEGIN_OBJECT) | ||||
| 		+ lpeg.P("}") * lpeg.Cc(END_OBJECT) | ||||
| 		+ lpeg.P(":") * lpeg.Cc(SET_KEY) | ||||
| 		+ lpeg.P(",") * lpeg.Cc(NEXT_VALUE) | ||||
| 	if object_options.identifier then | ||||
| 		-- Add identifier match w/ validation check that it is in key | ||||
| 		lexer = lexer + lpeg.C(util.identifier) * ignored * lpeg.P(":") * lpeg.Cc(SET_KEY) | ||||
| 	end | ||||
| 	local callLexers = generateCallLexer(options) | ||||
| 	if callLexers then | ||||
| 		lexer = lexer + callLexers | ||||
| 	end | ||||
| 	return lexer | ||||
| end | ||||
|  | ||||
| local composite = { | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	generateLexer = generateLexer | ||||
| } | ||||
|  | ||||
| return composite | ||||
							
								
								
									
										100
									
								
								tools/luajson/json/decode/number.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								tools/luajson/json/decode/number.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local lpeg = require("lpeg") | ||||
| local tonumber = tonumber | ||||
| local jsonutil = require("json.util") | ||||
| local merge = jsonutil.merge | ||||
| local util = require("json.decode.util") | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local digit  = lpeg.R("09") | ||||
| local digits = digit^1 | ||||
|  | ||||
| -- Illegal octal declaration | ||||
| local illegal_octal_detect = #(lpeg.P('0') * digits) * util.denied("Octal numbers") | ||||
|  | ||||
| local int = (lpeg.P('-') + 0) * (lpeg.R("19") * digits + illegal_octal_detect + digit) | ||||
|  | ||||
| local frac = lpeg.P('.') * digits | ||||
|  | ||||
| local exp = lpeg.S("Ee") * (lpeg.S("-+") + 0) * digits | ||||
|  | ||||
| local nan = lpeg.S("Nn") * lpeg.S("Aa") * lpeg.S("Nn") | ||||
| local inf = lpeg.S("Ii") * lpeg.P("nfinity") | ||||
| local ninf = lpeg.P('-') * lpeg.S("Ii") * lpeg.P("nfinity") | ||||
| local hex = (lpeg.P("0x") + lpeg.P("0X")) * lpeg.R("09","AF","af")^1 | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	nan = true, | ||||
| 	inf = true, | ||||
| 	frac = true, | ||||
| 	exp = true, | ||||
| 	hex = false | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
|  | ||||
| modeOptions.strict = { | ||||
| 	nan = false, | ||||
| 	inf = false | ||||
| } | ||||
|  | ||||
| local nan_value = 0/0 | ||||
| local inf_value = 1/0 | ||||
| local ninf_value = -1/0 | ||||
|  | ||||
| --[[ | ||||
| 	Options: configuration options for number rules | ||||
| 		nan: match NaN | ||||
| 		inf: match Infinity | ||||
| 	   frac: match fraction portion (.0) | ||||
| 	    exp: match exponent portion  (e1) | ||||
| 	DEFAULT: nan, inf, frac, exp | ||||
| ]] | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
| local function generateLexer(options) | ||||
| 	options = options.number | ||||
| 	local ret = int | ||||
| 	if options.frac then | ||||
| 		ret = ret * (frac + 0) | ||||
| 	else | ||||
| 		ret = ret * (#frac * util.denied("Fractions", "number.frac") + 0) | ||||
| 	end | ||||
| 	if options.exp then | ||||
| 		ret = ret * (exp + 0) | ||||
| 	else | ||||
| 		ret = ret * (#exp * util.denied("Exponents", "number.exp") + 0) | ||||
| 	end | ||||
| 	if options.hex then | ||||
| 		ret = hex + ret | ||||
| 	else | ||||
| 		ret = #hex * util.denied("Hexadecimal", "number.hex") + ret | ||||
| 	end | ||||
| 	-- Capture number now | ||||
| 	ret = ret / tonumber | ||||
| 	if options.nan then | ||||
| 		ret = ret + nan / function() return nan_value end | ||||
| 	else | ||||
| 		ret = ret + #nan * util.denied("NaN", "number.nan") | ||||
| 	end | ||||
| 	if options.inf then | ||||
| 		ret = ret + ninf / function() return ninf_value end + inf / function() return inf_value end | ||||
| 	else | ||||
| 		ret = ret + (#ninf + #inf) * util.denied("+/-Inf", "number.inf") | ||||
| 	end | ||||
| 	return ret | ||||
| end | ||||
|  | ||||
| local number = { | ||||
| 	int = int, | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	generateLexer = generateLexer | ||||
| } | ||||
|  | ||||
| return number | ||||
							
								
								
									
										62
									
								
								tools/luajson/json/decode/others.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								tools/luajson/json/decode/others.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local lpeg = require("lpeg") | ||||
| local jsonutil = require("json.util") | ||||
| local merge = jsonutil.merge | ||||
| local util = require("json.decode.util") | ||||
|  | ||||
| -- Container module for other JavaScript types (bool, null, undefined) | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| -- For null and undefined, use the util.null value to preserve null-ness | ||||
| local booleanCapture = | ||||
| 	lpeg.P("true") * lpeg.Cc(true) | ||||
| 	+ lpeg.P("false") * lpeg.Cc(false) | ||||
|  | ||||
| local nullCapture = lpeg.P("null") | ||||
| local undefinedCapture = lpeg.P("undefined") | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	allowUndefined = true, | ||||
| 	null = jsonutil.null, | ||||
| 	undefined = jsonutil.undefined | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
|  | ||||
| modeOptions.simple = { | ||||
| 	null = false,     -- Mapped to nil | ||||
| 	undefined = false -- Mapped to nil | ||||
| } | ||||
| modeOptions.strict = { | ||||
| 	allowUndefined = false | ||||
| } | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
| local function generateLexer(options) | ||||
| 	-- The 'or nil' clause allows false to map to a nil value since 'nil' cannot be merged | ||||
| 	options = options.others | ||||
| 	local valueCapture = ( | ||||
| 		booleanCapture | ||||
| 		+ nullCapture * lpeg.Cc(options.null or nil) | ||||
| 	) | ||||
| 	if options.allowUndefined then | ||||
| 		valueCapture = valueCapture + undefinedCapture * lpeg.Cc(options.undefined or nil) | ||||
| 	else | ||||
| 		valueCapture = valueCapture + #undefinedCapture * util.denied("undefined", "others.allowUndefined") | ||||
| 	end | ||||
| 	return valueCapture | ||||
| end | ||||
|  | ||||
| local others = { | ||||
| 	mergeOptions = mergeOptions,	 | ||||
| 	generateLexer = generateLexer | ||||
| } | ||||
|  | ||||
| return others | ||||
							
								
								
									
										189
									
								
								tools/luajson/json/decode/state.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								tools/luajson/json/decode/state.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
|  | ||||
| local setmetatable = setmetatable | ||||
| local jsonutil = require("json.util") | ||||
| local assert = assert | ||||
| local type = type | ||||
| local next = next | ||||
| local unpack = require("table").unpack or unpack | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local state_ops = {} | ||||
| local state_mt = { | ||||
| 	__index = state_ops | ||||
| } | ||||
|  | ||||
| function state_ops.pop(self) | ||||
| 	self.previous_set = true | ||||
| 	self.previous = self.active | ||||
| 	local i = self.i | ||||
| 	-- Load in this array into the active item | ||||
| 	self.active = self.stack[i] | ||||
| 	self.active_state = self.state_stack[i] | ||||
| 	self.active_key = self.key_stack[i] | ||||
| 	self.stack[i] = nil | ||||
| 	self.state_stack[i] = nil | ||||
| 	self.key_stack[i] = nil | ||||
|  | ||||
| 	self.i = i - 1 | ||||
| end | ||||
|  | ||||
| function state_ops.push(self) | ||||
| 	local i = self.i + 1 | ||||
| 	self.i = i | ||||
| 	 | ||||
| 	self.stack[i] = self.active | ||||
| 	self.state_stack[i] = self.active_state | ||||
| 	self.key_stack[i] = self.active_key | ||||
| end | ||||
|  | ||||
| function state_ops.put_object_value(self, trailing) | ||||
| 	local object_options = self.options.object | ||||
| 	if trailing and object_options.trailingComma then | ||||
| 		if not self.active_key then | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| 	assert(self.active_key, "Missing key value") | ||||
| 	object_options.setObjectKey(self.active, self.active_key, self:grab_value()) | ||||
| 	self.active_key = nil | ||||
| end | ||||
|  | ||||
| function state_ops.put_array_value(self, trailing) | ||||
| 	-- Safety check | ||||
| 	if trailing and not self.previous_set and self.options.array.trailingComma then | ||||
| 		return | ||||
| 	end | ||||
| 	local new_index = self.active_state + 1 | ||||
| 	self.active_state = new_index | ||||
| 	self.active[new_index] = self:grab_value() | ||||
| end | ||||
|  | ||||
| function state_ops.put_value(self, trailing) | ||||
| 	if self.active_state == 'object' then | ||||
| 		self:put_object_value(trailing) | ||||
| 	else | ||||
| 		self:put_array_value(trailing) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function state_ops.new_array(self) | ||||
| 	local new_array = {} | ||||
| 	if jsonutil.InitArray then | ||||
| 		new_array = jsonutil.InitArray(new_array) or new_array | ||||
| 	end | ||||
| 	self.active = new_array | ||||
| 	self.active_state = 0 | ||||
| 	self.active_key = nil | ||||
| 	self:unset_value() | ||||
| end | ||||
|  | ||||
| function state_ops.end_array(self) | ||||
| 	if self.previous_set or self.active_state ~= 0 then | ||||
| 		-- Not an empty array | ||||
| 		self:put_value(true) | ||||
| 	end | ||||
| 	if self.active_state ~= #self.active then | ||||
| 		-- Store the length in | ||||
| 		self.active.n = self.active_state | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function state_ops.new_object(self) | ||||
| 	local new_object = {} | ||||
| 	self.active = new_object | ||||
| 	self.active_state = 'object' | ||||
| 	self.active_key = nil | ||||
| 	self:unset_value() | ||||
| end | ||||
|  | ||||
| function state_ops.end_object(self) | ||||
| 	if self.previous_set or next(self.active) then | ||||
| 		-- Not an empty object | ||||
| 		self:put_value(true) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function state_ops.new_call(self, name, func) | ||||
| 	-- TODO setup properly | ||||
| 	local new_call = {} | ||||
| 	new_call.name = name | ||||
| 	new_call.func = func | ||||
| 	self.active = new_call | ||||
| 	self.active_state = 0 | ||||
| 	self.active_key = nil | ||||
| 	self:unset_value() | ||||
| end | ||||
|  | ||||
| function state_ops.end_call(self) | ||||
| 	if self.previous_set or self.active_state ~= 0 then | ||||
| 		-- Not an empty array | ||||
| 		self:put_value(true) | ||||
| 	end | ||||
| 	if self.active_state ~= #self.active then | ||||
| 		-- Store the length in | ||||
| 		self.active.n = self.active_state | ||||
| 	end | ||||
| 	local func = self.active.func | ||||
| 	if func == true then | ||||
| 		func = jsonutil.buildCall | ||||
| 	end | ||||
| 	self.active = func(self.active.name, unpack(self.active, 1, self.active.n or #self.active)) | ||||
| end | ||||
|  | ||||
|  | ||||
| function state_ops.unset_value(self) | ||||
| 	self.previous_set = false | ||||
| 	self.previous = nil | ||||
| end | ||||
|  | ||||
| function state_ops.grab_value(self) | ||||
| 	assert(self.previous_set, "Previous value not set") | ||||
| 	self.previous_set = false | ||||
| 	return self.previous | ||||
| end | ||||
|  | ||||
| function state_ops.set_value(self, value) | ||||
| 	assert(not self.previous_set, "Value set when one already in slot") | ||||
| 	self.previous_set = true | ||||
| 	self.previous = value | ||||
| end | ||||
|  | ||||
| function state_ops.set_key(self) | ||||
| 	assert(self.active_state == 'object', "Cannot set key on array") | ||||
| 	local value = self:grab_value() | ||||
| 	local value_type = type(value) | ||||
| 	if self.options.object.number then | ||||
| 		assert(value_type == 'string' or value_type == 'number', "As configured, a key must be a number or string")  | ||||
| 	else | ||||
| 		assert(value_type == 'string', "As configured, a key must be a string") | ||||
| 	end | ||||
| 	self.active_key = value | ||||
| end | ||||
|  | ||||
|  | ||||
| local function create(options) | ||||
| 	local ret = { | ||||
| 		options = options, | ||||
| 		stack = {}, | ||||
| 		state_stack = {}, | ||||
| 		key_stack = {}, | ||||
| 		i = 0, | ||||
| 		active = nil, | ||||
| 		active_key = nil, | ||||
| 		previous = nil, | ||||
| 		active_state = nil | ||||
|  | ||||
| 	} | ||||
| 	return setmetatable(ret, state_mt) | ||||
| end | ||||
|  | ||||
| local state = { | ||||
| 	create = create | ||||
| } | ||||
|  | ||||
| return state | ||||
							
								
								
									
										133
									
								
								tools/luajson/json/decode/strings.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								tools/luajson/json/decode/strings.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local lpeg = require("lpeg") | ||||
| local jsonutil = require("json.util") | ||||
| local util = require("json.decode.util") | ||||
| local merge = jsonutil.merge | ||||
|  | ||||
| local tonumber = tonumber | ||||
| local string_char = require("string").char | ||||
| local floor = require("math").floor | ||||
| local table_concat = require("table").concat | ||||
|  | ||||
| local error = error | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local function get_error(item) | ||||
| 	local fmt_string = item .. " in string [%q] @ %i:%i" | ||||
| 	return lpeg.P(function(data, index) | ||||
| 		local line, line_index, bad_char, last_line = util.get_invalid_character_info(data, index) | ||||
| 		local err = fmt_string:format(bad_char, line, line_index) | ||||
| 		error(err) | ||||
| 	end) * 1 | ||||
| end | ||||
|  | ||||
| local bad_unicode   = get_error("Illegal unicode escape") | ||||
| local bad_hex       = get_error("Illegal hex escape") | ||||
| local bad_character = get_error("Illegal character") | ||||
| local bad_escape    = get_error("Illegal escape") | ||||
|  | ||||
| local knownReplacements = { | ||||
| 	["'"] = "'", | ||||
| 	['"'] = '"', | ||||
| 	['\\'] = '\\', | ||||
| 	['/'] = '/', | ||||
| 	b = '\b', | ||||
| 	f = '\f', | ||||
| 	n = '\n', | ||||
| 	r = '\r', | ||||
| 	t = '\t', | ||||
| 	v = '\v', | ||||
| 	z = '\z' | ||||
| } | ||||
|  | ||||
| -- according to the table at http://da.wikipedia.org/wiki/UTF-8 | ||||
| local function utf8DecodeUnicode(code1, code2) | ||||
| 	code1, code2 = tonumber(code1, 16), tonumber(code2, 16) | ||||
| 	if code1 == 0 and code2 < 0x80 then | ||||
| 		return string_char(code2) | ||||
| 	end | ||||
| 	if code1 < 0x08 then | ||||
| 		return string_char( | ||||
| 			0xC0 + code1 * 4 + floor(code2 / 64), | ||||
| 			0x80 + code2 % 64) | ||||
| 	end | ||||
| 	return string_char( | ||||
| 		0xE0 + floor(code1 / 16), | ||||
| 		0x80 + (code1 % 16) * 4 + floor(code2 / 64), | ||||
| 		0x80 + code2 % 64) | ||||
| end | ||||
|  | ||||
| local function decodeX(code) | ||||
| 	code = tonumber(code, 16) | ||||
| 	return string_char(code) | ||||
| end | ||||
|  | ||||
| local doSimpleSub = lpeg.C(lpeg.S("'\"\\/bfnrtvz")) / knownReplacements | ||||
| local doUniSub = lpeg.P('u') * (lpeg.C(util.hexpair) * lpeg.C(util.hexpair) + bad_unicode) | ||||
| local doXSub = lpeg.P('x') * (lpeg.C(util.hexpair) + bad_hex) | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	badChars = '', | ||||
| 	additionalEscapes = false, -- disallow untranslated escapes | ||||
| 	escapeCheck = #lpeg.S('bfnrtv/\\"xu\'z'), -- no check on valid characters | ||||
| 	decodeUnicode = utf8DecodeUnicode, | ||||
| 	strict_quotes = false | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
|  | ||||
| modeOptions.strict = { | ||||
| 	badChars = '\b\f\n\r\t\v', | ||||
| 	additionalEscapes = false, -- no additional escapes | ||||
| 	escapeCheck = #lpeg.S('bfnrtv/\\"u'), --only these chars are allowed to be escaped | ||||
| 	strict_quotes = true | ||||
| } | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
| local function buildCaptureString(quote, badChars, escapeMatch) | ||||
| 	local captureChar = (1 - lpeg.S("\\" .. badChars .. quote)) + (lpeg.P("\\") / "" * escapeMatch) | ||||
| 	-- During error, force end | ||||
| 	local captureString = captureChar^0 + (-#lpeg.P(quote) * bad_character + -1) | ||||
| 	return lpeg.P(quote) * lpeg.Cs(captureString) * lpeg.P(quote) | ||||
| end | ||||
|  | ||||
| local function generateLexer(options) | ||||
| 	options = options.strings | ||||
| 	local quotes = { '"' } | ||||
| 	if not options.strict_quotes then | ||||
| 		quotes[#quotes + 1] = "'" | ||||
| 	end | ||||
| 	local escapeMatch = doSimpleSub | ||||
| 	escapeMatch = escapeMatch + doXSub / decodeX | ||||
| 	escapeMatch = escapeMatch + doUniSub / options.decodeUnicode | ||||
| 	if options.escapeCheck then | ||||
| 		escapeMatch = options.escapeCheck * escapeMatch + bad_escape | ||||
| 	end | ||||
| 	if options.additionalEscapes then | ||||
| 		escapeMatch = options.additionalEscapes + escapeMatch | ||||
| 	end | ||||
| 	local captureString | ||||
| 	for i = 1, #quotes do | ||||
| 		local cap = buildCaptureString(quotes[i], options.badChars, escapeMatch) | ||||
| 		if captureString == nil then | ||||
| 			captureString = cap | ||||
| 		else | ||||
| 			captureString = captureString + cap | ||||
| 		end | ||||
| 	end | ||||
| 	return captureString | ||||
| end | ||||
|  | ||||
| local strings = { | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	generateLexer = generateLexer | ||||
| } | ||||
|  | ||||
| return strings | ||||
							
								
								
									
										121
									
								
								tools/luajson/json/decode/util.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								tools/luajson/json/decode/util.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local lpeg = require("lpeg") | ||||
| local select = select | ||||
| local pairs, ipairs = pairs, ipairs | ||||
| local tonumber = tonumber | ||||
| local string_char = require("string").char | ||||
| local rawset = rawset | ||||
| local jsonutil = require("json.util") | ||||
|  | ||||
| local error = error | ||||
| local setmetatable = setmetatable | ||||
|  | ||||
| local table_concat = require("table").concat | ||||
|  | ||||
| local merge = require("json.util").merge | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local function get_invalid_character_info(input, index) | ||||
| 	local parsed = input:sub(1, index) | ||||
| 	local bad_character = input:sub(index, index) | ||||
| 	local _, line_number = parsed:gsub('\n',{}) | ||||
| 	local last_line = parsed:match("\n([^\n]+.)$") or parsed | ||||
| 	return line_number, #last_line, bad_character, last_line | ||||
| end | ||||
|  | ||||
| local function build_report(msg) | ||||
| 	local fmt = msg:gsub("%%", "%%%%") .. " @ character: %i %i:%i [%s] line:\n%s" | ||||
| 	return lpeg.P(function(data, pos) | ||||
| 		local line, line_index, bad_char, last_line = get_invalid_character_info(data, pos) | ||||
| 		local text = fmt:format(pos, line, line_index, bad_char, last_line) | ||||
| 		error(text) | ||||
| 	end) * 1 | ||||
| end | ||||
| local function unexpected() | ||||
| 	local msg = "unexpected character" | ||||
| 	return build_report(msg) | ||||
| end | ||||
| local function denied(item, option) | ||||
| 	local msg | ||||
| 	if option then | ||||
| 		msg = ("'%s' denied by option set '%s'"):format(item, option) | ||||
| 	else | ||||
| 		msg = ("'%s' denied"):format(item) | ||||
| 	end | ||||
| 	return build_report(msg) | ||||
| end | ||||
|  | ||||
| -- 09, 0A, 0B, 0C, 0D, 20 | ||||
| local ascii_space = lpeg.S("\t\n\v\f\r ") | ||||
| local unicode_space | ||||
| do | ||||
| 	local chr = string_char | ||||
| 	local u_space = ascii_space | ||||
| 	-- \u0085 \u00A0 | ||||
| 	u_space = u_space + lpeg.P(chr(0xC2)) * lpeg.S(chr(0x85) .. chr(0xA0)) | ||||
| 	-- \u1680 \u180E | ||||
| 	u_space = u_space + lpeg.P(chr(0xE1)) * (lpeg.P(chr(0x9A, 0x80)) + chr(0xA0, 0x8E)) | ||||
| 	-- \u2000 - \u200A, also 200B | ||||
| 	local spacing_end = "" | ||||
| 	for i = 0x80,0x8b do | ||||
| 		spacing_end = spacing_end .. chr(i) | ||||
| 	end | ||||
| 	-- \u2028 \u2029 \u202F | ||||
| 	spacing_end = spacing_end .. chr(0xA8) .. chr(0xA9) .. chr(0xAF) | ||||
| 	u_space = u_space + lpeg.P(chr(0xE2, 0x80)) * lpeg.S(spacing_end) | ||||
| 	-- \u205F | ||||
| 	u_space = u_space + lpeg.P(chr(0xE2, 0x81, 0x9F)) | ||||
| 	-- \u3000 | ||||
| 	u_space = u_space + lpeg.P(chr(0xE3, 0x80, 0x80)) | ||||
| 	-- BOM \uFEFF | ||||
| 	u_space = u_space + lpeg.P(chr(0xEF, 0xBB, 0xBF)) | ||||
| 	unicode_space = u_space | ||||
| end | ||||
|  | ||||
| local identifier = lpeg.R("AZ","az","__") * lpeg.R("AZ","az", "__", "09") ^0 | ||||
|  | ||||
| local hex = lpeg.R("09","AF","af") | ||||
| local hexpair = hex * hex | ||||
|  | ||||
| local comments = { | ||||
| 	cpp = lpeg.P("//") * (1 - lpeg.P("\n"))^0 * lpeg.P("\n"), | ||||
| 	c = lpeg.P("/*") * (1 - lpeg.P("*/"))^0 * lpeg.P("*/") | ||||
| } | ||||
|  | ||||
| local comment = comments.cpp + comments.c | ||||
|  | ||||
| local ascii_ignored = (ascii_space + comment)^0 | ||||
|  | ||||
| local unicode_ignored = (unicode_space + comment)^0 | ||||
|  | ||||
| -- Parse the lpeg version skipping patch-values | ||||
| -- LPEG <= 0.7 have no version value... so 0.7 is value | ||||
| local DecimalLpegVersion = lpeg.version and tonumber(lpeg.version():match("^(%d+%.%d+)")) or 0.7 | ||||
|  | ||||
| local function setObjectKeyForceNumber(t, key, value) | ||||
| 	key = tonumber(key) or key | ||||
| 	return rawset(t, key, value) | ||||
| end | ||||
|  | ||||
| local util = { | ||||
| 	unexpected = unexpected, | ||||
| 	denied = denied, | ||||
| 	ascii_space = ascii_space, | ||||
| 	unicode_space = unicode_space, | ||||
| 	identifier = identifier, | ||||
| 	hex = hex, | ||||
| 	hexpair = hexpair, | ||||
| 	comments = comments, | ||||
| 	comment = comment, | ||||
| 	ascii_ignored = ascii_ignored, | ||||
| 	unicode_ignored = unicode_ignored, | ||||
| 	DecimalLpegVersion = DecimalLpegVersion, | ||||
| 	get_invalid_character_info = get_invalid_character_info, | ||||
| 	setObjectKeyForceNumber = setObjectKeyForceNumber | ||||
| } | ||||
|  | ||||
| return util | ||||
							
								
								
									
										161
									
								
								tools/luajson/json/encode.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								tools/luajson/json/encode.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local type = type | ||||
| local assert, error = assert, error | ||||
| local getmetatable, setmetatable = getmetatable, setmetatable | ||||
|  | ||||
| local ipairs, pairs = ipairs, pairs | ||||
| local require = require | ||||
|  | ||||
| local output = require("json.encode.output") | ||||
|  | ||||
| local util = require("json.util") | ||||
| local util_merge, isCall = util.merge, util.isCall | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| --[[ | ||||
| 	List of encoding modules to load. | ||||
| 	Loaded in sequence such that earlier encoders get priority when | ||||
| 	duplicate type-handlers exist. | ||||
| ]] | ||||
| local modulesToLoad = { | ||||
| 	"strings", | ||||
| 	"number", | ||||
| 	"calls", | ||||
| 	"others", | ||||
| 	"array", | ||||
| 	"object" | ||||
| } | ||||
| -- Modules that have been loaded | ||||
| local loadedModules = {} | ||||
|  | ||||
| local json_encode = {} | ||||
|  | ||||
| -- Configuration bases for client apps | ||||
| local modes_defined = { "default", "strict" } | ||||
|  | ||||
| json_encode.default = {} | ||||
| json_encode.strict = { | ||||
| 	initialObject = true -- Require an object at the root | ||||
| } | ||||
|  | ||||
| -- For each module, load it and its defaults | ||||
| for _,name in ipairs(modulesToLoad) do | ||||
| 	local mod = require("json.encode." .. name) | ||||
| 	if mod.mergeOptions then | ||||
| 		for _, mode in pairs(modes_defined) do | ||||
| 			mod.mergeOptions(json_encode[mode], mode) | ||||
| 		end | ||||
| 	end | ||||
| 	loadedModules[name] = mod | ||||
| end | ||||
|  | ||||
| -- NOTE: Nested not found, so assume unsupported until use case arises | ||||
| local function flattenOutput(out, value) | ||||
|     assert(type(value) ~= 'table') | ||||
| 	out = out or {} | ||||
|     out[#out + 1] = value | ||||
|     return out | ||||
| end | ||||
|  | ||||
| -- Prepares the encoding map from the already provided modules and new config | ||||
| local function prepareEncodeMap(options) | ||||
| 	local map = {} | ||||
| 	for _, name in ipairs(modulesToLoad) do | ||||
| 		local encodermap = loadedModules[name].getEncoder(options[name]) | ||||
| 		for valueType, encoderSet in pairs(encodermap) do | ||||
| 			map[valueType] = flattenOutput(map[valueType], encoderSet) | ||||
| 		end | ||||
| 	end | ||||
| 	return map | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| 	Encode a value with a given encoding map and state | ||||
| ]] | ||||
| local function encodeWithMap(value, map, state, isObjectKey) | ||||
| 	local t = type(value) | ||||
| 	local encoderList = assert(map[t], "Failed to encode value, unhandled type: " .. t) | ||||
| 	for _, encoder in ipairs(encoderList) do | ||||
| 		local ret = encoder(value, state, isObjectKey) | ||||
| 		if false ~= ret then | ||||
| 			return ret | ||||
| 		end | ||||
| 	end | ||||
| 	error("Failed to encode value, encoders for " .. t .. " deny encoding") | ||||
| end | ||||
|  | ||||
|  | ||||
| local function getBaseEncoder(options) | ||||
| 	local encoderMap = prepareEncodeMap(options) | ||||
| 	if options.preProcess then | ||||
| 		local preProcess = options.preProcess | ||||
| 		return function(value, state, isObjectKey) | ||||
| 			local ret = preProcess(value, isObjectKey or false) | ||||
| 			if nil ~= ret then | ||||
| 				value = ret | ||||
| 			end | ||||
| 			return encodeWithMap(value, encoderMap, state) | ||||
| 		end | ||||
| 	end | ||||
| 	return function(value, state, isObjectKey) | ||||
| 		return encodeWithMap(value, encoderMap, state) | ||||
| 	end | ||||
| end | ||||
| --[[ | ||||
| 	Retreive an initial encoder instance based on provided options | ||||
| 	the initial encoder is responsible for initializing state | ||||
| 		State has at least these values configured: encode, check_unique, already_encoded | ||||
| ]] | ||||
| function json_encode.getEncoder(options) | ||||
| 	options = options and util_merge({}, json_encode.default, options) or json_encode.default | ||||
| 	local encode = getBaseEncoder(options) | ||||
|  | ||||
| 	local function initialEncode(value) | ||||
| 		if options.initialObject then | ||||
| 			local errorMessage = "Invalid arguments: expects a JSON Object or Array at the root" | ||||
| 			assert(type(value) == 'table' and not isCall(value, options), errorMessage) | ||||
| 		end | ||||
|  | ||||
| 		local alreadyEncoded = {} | ||||
| 		local function check_unique(value) | ||||
| 			assert(not alreadyEncoded[value], "Recursive encoding of value") | ||||
| 			alreadyEncoded[value] = true | ||||
| 		end | ||||
|  | ||||
| 		local outputEncoder = options.output and options.output() or output.getDefault() | ||||
| 		local state = { | ||||
| 			encode = encode, | ||||
| 			check_unique = check_unique, | ||||
| 			already_encoded = alreadyEncoded, -- To unmark encoding when moving up stack | ||||
| 			outputEncoder = outputEncoder | ||||
| 		} | ||||
| 		local ret = encode(value, state) | ||||
| 		if nil ~= ret then | ||||
| 			return outputEncoder.simple and outputEncoder.simple(ret) or ret | ||||
| 		end | ||||
| 	end | ||||
| 	return initialEncode | ||||
| end | ||||
|  | ||||
| -- CONSTRUCT STATE WITH FOLLOWING (at least) | ||||
| --[[ | ||||
| 	encoder | ||||
| 	check_unique -- used by inner encoders to make sure value is unique | ||||
| 	already_encoded -- used to unmark a value as unique | ||||
| ]] | ||||
| function json_encode.encode(data, options) | ||||
| 	return json_encode.getEncoder(options)(data) | ||||
| end | ||||
|  | ||||
| local mt = {} | ||||
| mt.__call = function(self, ...) | ||||
| 	return json_encode.encode(...) | ||||
| end | ||||
|  | ||||
| setmetatable(json_encode, mt) | ||||
|  | ||||
| return json_encode | ||||
							
								
								
									
										110
									
								
								tools/luajson/json/encode/array.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								tools/luajson/json/encode/array.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local jsonutil = require("json.util") | ||||
|  | ||||
| local type = type | ||||
| local pairs = pairs | ||||
| local assert = assert | ||||
|  | ||||
| local table = require("table") | ||||
| local math = require("math") | ||||
| local table_concat = table.concat | ||||
| local math_floor, math_modf = math.floor, math.modf | ||||
|  | ||||
| local jsonutil = require("json.util") | ||||
| local util_IsArray = jsonutil.IsArray | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	isArray = util_IsArray | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'array', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| 	Utility function to determine whether a table is an array or not. | ||||
| 	Criteria for it being an array: | ||||
| 		* ExternalIsArray returns true (or false directly reports not-array) | ||||
| 		* If the table has an 'n' value that is an integer >= 1 then it | ||||
| 		  is an array... may result in false positives (should check some values | ||||
| 		  before it) | ||||
| 		* It is a contiguous list of values with zero string-based keys | ||||
| ]] | ||||
| local function isArray(val, options) | ||||
| 	local externalIsArray = options and options.isArray | ||||
|  | ||||
| 	if externalIsArray then | ||||
| 		local ret = externalIsArray(val) | ||||
| 		if ret == true or ret == false then | ||||
| 			return ret | ||||
| 		end | ||||
| 	end | ||||
| 	-- Use the 'n' element if it's a number | ||||
| 	if type(val.n) == 'number' and math_floor(val.n) == val.n and val.n >= 1 then | ||||
| 		return true | ||||
| 	end | ||||
| 	local len = #val | ||||
| 	for k,v in pairs(val) do | ||||
| 		if type(k) ~= 'number' then | ||||
| 			return false | ||||
| 		end | ||||
| 		local _, decim = math_modf(k) | ||||
| 		if not (decim == 0 and 1<=k) then | ||||
| 			return false | ||||
| 		end | ||||
| 		if k > len then -- Use Lua's length as absolute determiner | ||||
| 			return false | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	return true | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| 	Cleanup function to unmark a value as in the encoding process and return | ||||
| 	trailing results | ||||
| ]] | ||||
| local function unmarkAfterEncode(tab, state, ...) | ||||
| 	state.already_encoded[tab] = nil | ||||
| 	return ... | ||||
| end | ||||
| local function getEncoder(options) | ||||
| 	options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions | ||||
| 	local function encodeArray(tab,  state) | ||||
| 		if not isArray(tab, options) then | ||||
| 			return false | ||||
| 		end | ||||
| 		-- Make sure this value hasn't been encoded yet | ||||
| 		state.check_unique(tab) | ||||
| 		local encode = state.encode | ||||
| 		local compositeEncoder = state.outputEncoder.composite | ||||
| 		local valueEncoder = [[ | ||||
| 		for i = 1, (composite.n or #composite) do | ||||
| 			local val = composite[i] | ||||
| 			PUTINNER(i ~= 1) | ||||
| 			val = encode(val, state) | ||||
| 			val = val or '' | ||||
| 			if val then | ||||
| 				PUTVALUE(val) | ||||
| 			end | ||||
| 		end | ||||
| 		]] | ||||
| 		return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '[', ']', ',', tab, encode, state)) | ||||
| 	end | ||||
| 	return { table = encodeArray } | ||||
| end | ||||
|  | ||||
| local array = { | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	isArray = isArray, | ||||
| 	getEncoder = getEncoder | ||||
| } | ||||
|  | ||||
| return array | ||||
							
								
								
									
										68
									
								
								tools/luajson/json/encode/calls.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								tools/luajson/json/encode/calls.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local table = require("table") | ||||
| local table_concat = table.concat | ||||
|  | ||||
| local select = select | ||||
| local getmetatable, setmetatable = getmetatable, setmetatable | ||||
| local assert = assert | ||||
|  | ||||
| local jsonutil = require("json.util") | ||||
|  | ||||
| local isCall, decodeCall = jsonutil.isCall, jsonutil.decodeCall | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local defaultOptions = { | ||||
| } | ||||
|  | ||||
| -- No real default-option handling needed... | ||||
| local modeOptions = {} | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'calls', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
|  | ||||
| --[[ | ||||
| 	Encodes 'value' as a function call | ||||
| 	Must have parameters in the 'callData' field of the metatable | ||||
| 		name == name of the function call | ||||
| 		parameters == array of parameters to encode | ||||
| ]] | ||||
| local function getEncoder(options) | ||||
| 	options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions | ||||
| 	local function encodeCall(value, state) | ||||
| 		if not isCall(value) then | ||||
| 			return false | ||||
| 		end | ||||
| 		local encode = state.encode | ||||
| 		local name, params = decodeCall(value) | ||||
| 		local compositeEncoder = state.outputEncoder.composite | ||||
| 		local valueEncoder = [[ | ||||
| 		for i = 1, (composite.n or #composite) do | ||||
| 			local val = composite[i] | ||||
| 			PUTINNER(i ~= 1) | ||||
| 			val = encode(val, state) | ||||
| 			val = val or '' | ||||
| 			if val then | ||||
| 				PUTVALUE(val) | ||||
| 			end | ||||
| 		end | ||||
| 		]] | ||||
| 		return compositeEncoder(valueEncoder, name .. '(', ')', ',', params, encode, state) | ||||
| 	end | ||||
| 	return { | ||||
| 		table = encodeCall, | ||||
| 		['function'] = encodeCall | ||||
| 	} | ||||
| end | ||||
|  | ||||
| local calls = { | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	getEncoder = getEncoder | ||||
| } | ||||
|  | ||||
| return calls | ||||
							
								
								
									
										58
									
								
								tools/luajson/json/encode/number.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								tools/luajson/json/encode/number.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local tostring = tostring | ||||
| local assert = assert | ||||
| local jsonutil = require("json.util") | ||||
| local huge = require("math").huge | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	nan = true, | ||||
| 	inf = true | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
| modeOptions.strict = { | ||||
| 	nan = false, | ||||
| 	inf = false | ||||
| } | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
|  | ||||
| local function encodeNumber(number, options) | ||||
| 	if number ~= number then | ||||
| 		assert(options.nan, "Invalid number: NaN not enabled") | ||||
| 		return "NaN" | ||||
| 	end | ||||
| 	if number == huge then | ||||
| 		assert(options.inf, "Invalid number: Infinity not enabled") | ||||
| 		return "Infinity" | ||||
| 	end | ||||
| 	if number == -huge then | ||||
| 		assert(options.inf, "Invalid number: Infinity not enabled") | ||||
| 		return "-Infinity" | ||||
| 	end | ||||
| 	return tostring(number) | ||||
| end | ||||
|  | ||||
| local function getEncoder(options) | ||||
| 	options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions | ||||
| 	return { | ||||
| 		number = function(number, state) | ||||
| 			return encodeNumber(number, options) | ||||
| 		end | ||||
| 	} | ||||
| end | ||||
|  | ||||
| local number = { | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	getEncoder = getEncoder | ||||
| } | ||||
|  | ||||
| return number | ||||
							
								
								
									
										77
									
								
								tools/luajson/json/encode/object.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								tools/luajson/json/encode/object.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local pairs = pairs | ||||
| local assert = assert | ||||
|  | ||||
| local type = type | ||||
| local tostring = tostring | ||||
|  | ||||
| local table_concat = require("table").concat | ||||
| local jsonutil = require("json.util") | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local defaultOptions = { | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'object', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
| --[[ | ||||
| 	Cleanup function to unmark a value as in the encoding process and return | ||||
| 	trailing results | ||||
| ]] | ||||
| local function unmarkAfterEncode(tab, state, ...) | ||||
| 	state.already_encoded[tab] = nil | ||||
| 	return ... | ||||
| end | ||||
| --[[ | ||||
| 	Encode a table as a JSON Object ( keys = strings, values = anything else ) | ||||
| ]] | ||||
| local function encodeTable(tab, options, state) | ||||
| 	-- Make sure this value hasn't been encoded yet | ||||
| 	state.check_unique(tab) | ||||
| 	local encode = state.encode | ||||
| 	local compositeEncoder = state.outputEncoder.composite | ||||
| 	local valueEncoder = [[ | ||||
| 	local first = true | ||||
| 	for k, v in pairs(composite) do | ||||
| 		local ti = type(k) | ||||
| 		assert(ti == 'string' or ti == 'number' or ti == 'boolean', "Invalid object index type: " .. ti) | ||||
| 		local name = encode(tostring(k), state, true) | ||||
| 		if first then | ||||
| 			first = false | ||||
| 		else | ||||
| 			name = ',' .. name | ||||
| 		end | ||||
| 		PUTVALUE(name .. ':') | ||||
| 		local val = encode(v, state) | ||||
| 		val = val or '' | ||||
| 		if val then | ||||
| 			PUTVALUE(val) | ||||
| 		end | ||||
| 	end | ||||
| 	]] | ||||
| 	return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '{', '}', nil, tab, encode, state)) | ||||
| end | ||||
|  | ||||
| local function getEncoder(options) | ||||
| 	options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions | ||||
| 	return { | ||||
| 		table = function(tab, state) | ||||
| 			return encodeTable(tab, options, state) | ||||
| 		end | ||||
| 	} | ||||
| end | ||||
|  | ||||
| local object = { | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	getEncoder = getEncoder | ||||
| } | ||||
|  | ||||
| return object | ||||
							
								
								
									
										66
									
								
								tools/luajson/json/encode/others.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								tools/luajson/json/encode/others.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local tostring = tostring | ||||
|  | ||||
| local assert = assert | ||||
| local jsonutil = require("json.util") | ||||
| local type = type | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| -- Shortcut that works | ||||
| local encodeBoolean = tostring | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	allowUndefined = true, | ||||
| 	null = jsonutil.null, | ||||
| 	undefined = jsonutil.undefined | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
|  | ||||
| modeOptions.strict = { | ||||
| 	allowUndefined = false | ||||
| } | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
| local function getEncoder(options) | ||||
| 	options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions | ||||
| 	local function encodeOthers(value, state) | ||||
| 		if value == options.null then | ||||
| 			return 'null' | ||||
| 		elseif value == options.undefined then | ||||
| 			assert(options.allowUndefined, "Invalid value: Unsupported 'Undefined' parameter") | ||||
| 			return 'undefined' | ||||
| 		else | ||||
| 			return false | ||||
| 		end | ||||
| 	end | ||||
| 	local function encodeBoolean(value, state) | ||||
| 		return value and 'true' or 'false' | ||||
| 	end | ||||
| 	local nullType = type(options.null) | ||||
| 	local undefinedType = options.undefined and type(options.undefined) | ||||
| 	-- Make sure that all of the types handled here are handled | ||||
| 	local ret = { | ||||
| 		boolean = encodeBoolean, | ||||
| 		['nil'] = function() return 'null' end, | ||||
| 		[nullType] = encodeOthers | ||||
| 	} | ||||
| 	if undefinedType then | ||||
| 		ret[undefinedType] = encodeOthers | ||||
| 	end | ||||
| 	return ret | ||||
| end | ||||
|  | ||||
| local others = { | ||||
| 	encodeBoolean = encodeBoolean, | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	getEncoder = getEncoder | ||||
| } | ||||
|  | ||||
| return others | ||||
							
								
								
									
										91
									
								
								tools/luajson/json/encode/output.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								tools/luajson/json/encode/output.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local type = type | ||||
| local assert, error = assert, error | ||||
| local table_concat = require("table").concat | ||||
| local loadstring = loadstring or load | ||||
|  | ||||
| local io = require("io") | ||||
|  | ||||
| local setmetatable = setmetatable | ||||
|  | ||||
| local output_utility = require("json.encode.output_utility") | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local tableCompositeCache = setmetatable({}, {__mode = 'v'}) | ||||
|  | ||||
| local TABLE_VALUE_WRITER = [[ | ||||
| 	ret[#ret + 1] = %VALUE% | ||||
| ]] | ||||
|  | ||||
| local TABLE_INNER_WRITER = "" | ||||
|  | ||||
| --[[ | ||||
| 	nextValues can output a max of two values to throw into the data stream | ||||
| 	expected to be called until nil is first return value | ||||
| 	value separator should either be attached to v1 or in innerValue | ||||
| ]] | ||||
| local function defaultTableCompositeWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state) | ||||
| 	if type(nextValues) == 'string' then | ||||
| 		local fun = output_utility.prepareEncoder(defaultTableCompositeWriter, nextValues, innerValue, TABLE_VALUE_WRITER, TABLE_INNER_WRITER) | ||||
| 		local ret = {} | ||||
| 		fun(composite, ret, encode, state) | ||||
| 		return beginValue .. table_concat(ret, innerValue) .. closeValue | ||||
| 	end | ||||
| end | ||||
|  | ||||
| -- no 'simple' as default action is just to return the value | ||||
| local function getDefault() | ||||
| 	return { composite = defaultTableCompositeWriter } | ||||
| end | ||||
|  | ||||
| -- BEGIN IO-WRITER OUTPUT | ||||
| local IO_INNER_WRITER = [[ | ||||
| 	if %WRITE_INNER% then | ||||
| 		state.__outputFile:write(%INNER_VALUE%) | ||||
| 	end | ||||
| ]] | ||||
| local IO_VALUE_WRITER = [[ | ||||
| 	state.__outputFile:write(%VALUE%) | ||||
| ]] | ||||
|  | ||||
| local function buildIoWriter(output) | ||||
| 	if not output then -- Default to stdout | ||||
| 		output = io.output() | ||||
| 	end | ||||
| 	local function ioWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state) | ||||
| 		-- HOOK OUTPUT STATE | ||||
| 		state.__outputFile = output | ||||
| 		if type(nextValues) == 'string' then | ||||
| 			local fun = output_utility.prepareEncoder(ioWriter, nextValues, innerValue, IO_VALUE_WRITER, IO_INNER_WRITER) | ||||
| 			local ret = {} | ||||
| 			output:write(beginValue) | ||||
| 			fun(composite, ret, encode, state) | ||||
| 			output:write(closeValue) | ||||
| 			return nil | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	local function ioSimpleWriter(encoded) | ||||
| 		if encoded then | ||||
| 			output:write(encoded) | ||||
| 		end | ||||
| 		return nil | ||||
| 	end | ||||
| 	return { composite = ioWriter, simple = ioSimpleWriter } | ||||
| end | ||||
| local function getIoWriter(output) | ||||
| 	return function() | ||||
| 		return buildIoWriter(output) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| local output = { | ||||
| 	getDefault = getDefault, | ||||
| 	getIoWriter = getIoWriter | ||||
| } | ||||
|  | ||||
| return output | ||||
							
								
								
									
										54
									
								
								tools/luajson/json/encode/output_utility.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								tools/luajson/json/encode/output_utility.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local setmetatable = setmetatable | ||||
| local assert, loadstring = assert, loadstring or load | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| -- Key == weak, if main key goes away, then cache cleared | ||||
| local outputCache = setmetatable({}, {__mode = 'k'}) | ||||
| -- TODO: inner tables weak? | ||||
|  | ||||
| local function buildFunction(nextValues, innerValue, valueWriter, innerWriter) | ||||
| 	local putInner = "" | ||||
| 	if innerValue and innerWriter then | ||||
| 		-- Prepare the lua-string representation of the separator to put in between values | ||||
| 		local formattedInnerValue = ("%q"):format(innerValue) | ||||
| 		-- Fill in the condition %WRITE_INNER% and the %INNER_VALUE% to actually write | ||||
| 		putInner = innerWriter:gsub("%%WRITE_INNER%%", "%%1"):gsub("%%INNER_VALUE%%", formattedInnerValue) | ||||
| 	end | ||||
| 	-- Template-in the value writer (if present) and its conditional argument | ||||
| 	local functionCode = nextValues:gsub("PUTINNER(%b())", putInner) | ||||
| 	-- %VALUE% is to be filled in by the value-to-write | ||||
| 	valueWriter = valueWriter:gsub("%%VALUE%%", "%%1") | ||||
| 	-- Template-in the value writer with its argument | ||||
| 	functionCode = functionCode:gsub("PUTVALUE(%b())", valueWriter) | ||||
| 	functionCode = [[ | ||||
| 		return function(composite, ret, encode, state) | ||||
| 	]] .. functionCode .. [[ | ||||
| 		end | ||||
| 	]] | ||||
| 	return assert(loadstring(functionCode))() | ||||
| end | ||||
|  | ||||
| local function prepareEncoder(cacheKey, nextValues, innerValue, valueWriter, innerWriter) | ||||
| 	local cache = outputCache[cacheKey] | ||||
| 	if not cache then | ||||
| 		cache = {} | ||||
| 		outputCache[cacheKey] = cache | ||||
| 	end | ||||
| 	local fun = cache[nextValues] | ||||
| 	if not fun then | ||||
| 		fun = buildFunction(nextValues, innerValue, valueWriter, innerWriter) | ||||
| 		cache[nextValues] = fun | ||||
| 	end | ||||
| 	return fun | ||||
| end | ||||
|  | ||||
| local output_utility = { | ||||
| 	prepareEncoder = prepareEncoder | ||||
| } | ||||
|  | ||||
| return output_utility | ||||
							
								
								
									
										88
									
								
								tools/luajson/json/encode/strings.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								tools/luajson/json/encode/strings.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local string_char = require("string").char | ||||
| local pairs = pairs | ||||
|  | ||||
| local jsonutil = require("json.util") | ||||
| local util_merge = jsonutil.merge | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local normalEncodingMap = { | ||||
| 	['"'] = '\\"', | ||||
| 	['\\'] = '\\\\', | ||||
| 	['/'] = '\\/', | ||||
| 	['\b'] = '\\b', | ||||
| 	['\f'] = '\\f', | ||||
| 	['\n'] = '\\n', | ||||
| 	['\r'] = '\\r', | ||||
| 	['\t'] = '\\t', | ||||
| 	['\v'] = '\\v' -- not in official spec, on report, removing | ||||
| } | ||||
|  | ||||
| local xEncodingMap = {} | ||||
| for char, encoded in pairs(normalEncodingMap) do | ||||
| 	xEncodingMap[char] = encoded | ||||
| end | ||||
|  | ||||
| -- Pre-encode the control characters to speed up encoding... | ||||
| -- NOTE: UTF-8 may not work out right w/ JavaScript | ||||
| -- JavaScript uses 2 bytes after a \u... yet UTF-8 is a | ||||
| -- byte-stream encoding, not pairs of bytes (it does encode | ||||
| -- some letters > 1 byte, but base case is 1) | ||||
| for i = 0, 255 do | ||||
| 	local c = string_char(i) | ||||
| 	if c:match('[%z\1-\031\128-\255]') and not normalEncodingMap[c] then | ||||
| 		-- WARN: UTF8 specializes values >= 0x80 as parts of sequences... | ||||
| 		--       without \x encoding, do not allow encoding > 7F | ||||
| 		normalEncodingMap[c] = ('\\u%.4X'):format(i) | ||||
| 		xEncodingMap[c] = ('\\x%.2X'):format(i) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| local defaultOptions = { | ||||
| 	xEncode = false, -- Encode single-bytes as \xXX | ||||
| 	processor = nil, -- Simple processor for the string prior to quoting | ||||
| 	-- / is not required to be quoted but it helps with certain decoding | ||||
| 	-- Required encoded characters, " \, and 00-1F  (0 - 31) | ||||
| 	encodeSet = '\\"/%z\1-\031', | ||||
| 	encodeSetAppend = nil -- Chars to append to the default set | ||||
| } | ||||
|  | ||||
| local modeOptions = {} | ||||
|  | ||||
| local function mergeOptions(options, mode) | ||||
| 	jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode]) | ||||
| end | ||||
|  | ||||
| local function getEncoder(options) | ||||
| 	options = options and util_merge({}, defaultOptions, options) or defaultOptions | ||||
| 	local encodeSet = options.encodeSet | ||||
| 	if options.encodeSetAppend then | ||||
| 		encodeSet = encodeSet .. options.encodeSetAppend | ||||
| 	end | ||||
| 	local encodingMap = options.xEncode and xEncodingMap or normalEncodingMap | ||||
| 	local encodeString | ||||
| 	if options.processor then | ||||
| 		local processor = options.processor | ||||
| 		encodeString = function(s, state) | ||||
| 			return '"' .. processor(s:gsub('[' .. encodeSet .. ']', encodingMap)) .. '"' | ||||
| 		end | ||||
| 	else | ||||
| 		encodeString = function(s, state) | ||||
| 			return '"' .. s:gsub('[' .. encodeSet .. ']', encodingMap) .. '"' | ||||
| 		end | ||||
| 	end | ||||
| 	return { | ||||
| 		string = encodeString | ||||
| 	} | ||||
| end | ||||
|  | ||||
| local strings = { | ||||
| 	mergeOptions = mergeOptions, | ||||
| 	getEncoder = getEncoder | ||||
| } | ||||
|  | ||||
| return strings | ||||
							
								
								
									
										152
									
								
								tools/luajson/json/util.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								tools/luajson/json/util.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| --[[ | ||||
| 	Licensed according to the included 'LICENSE' document | ||||
| 	Author: Thomas Harning Jr <harningt@gmail.com> | ||||
| ]] | ||||
| local type = type | ||||
| local print = print | ||||
| local tostring = tostring | ||||
| local pairs = pairs | ||||
| local getmetatable, setmetatable = getmetatable, setmetatable | ||||
| local select = select | ||||
|  | ||||
| local _ENV = nil | ||||
|  | ||||
| local function foreach(tab, func) | ||||
| 	for k, v in pairs(tab) do | ||||
| 		func(k,v) | ||||
| 	end | ||||
| end | ||||
| local function printValue(tab, name) | ||||
|         local parsed = {} | ||||
|         local function doPrint(key, value, space) | ||||
|                 space = space or '' | ||||
|                 if type(value) == 'table' then | ||||
|                         if parsed[value] then | ||||
|                                 print(space .. key .. '= <' .. parsed[value] .. '>') | ||||
|                         else | ||||
|                                 parsed[value] = key | ||||
|                                 print(space .. key .. '= {') | ||||
|                                 space = space .. ' ' | ||||
|                                 foreach(value, function(key, value) doPrint(key, value, space) end) | ||||
|                         end | ||||
|                 else | ||||
| 					if type(value) == 'string' then | ||||
| 						value = '[[' .. tostring(value) .. ']]' | ||||
| 					end | ||||
| 					print(space .. key .. '=' .. tostring(value)) | ||||
|                 end | ||||
|         end | ||||
|         doPrint(name, tab) | ||||
| end | ||||
|  | ||||
| local function clone(t) | ||||
| 	local ret = {} | ||||
| 	for k,v in pairs(t) do | ||||
| 		ret[k] = v | ||||
| 	end | ||||
| 	return ret | ||||
| end | ||||
|  | ||||
| local function inner_merge(t, remaining, from, ...) | ||||
| 	if remaining == 0 then | ||||
| 		return t | ||||
| 	end | ||||
| 	if from then | ||||
| 		for k,v in pairs(from) do | ||||
| 			t[k] = v | ||||
| 		end | ||||
| 	end | ||||
| 	return inner_merge(t, remaining - 1, ...) | ||||
| end | ||||
|  | ||||
| --[[* | ||||
|     Shallow-merges tables in order onto the first table. | ||||
|  | ||||
|     @param t table to merge entries onto | ||||
|     @param ... sequence of 0 or more tables to merge onto 't' | ||||
|  | ||||
|     @returns table 't' from input | ||||
| ]] | ||||
| local function merge(t, ...) | ||||
| 	return inner_merge(t, select('#', ...), ...) | ||||
| end | ||||
|  | ||||
| -- Function to insert nulls into the JSON stream | ||||
| local function null() | ||||
| 	return null | ||||
| end | ||||
|  | ||||
| -- Marker for 'undefined' values | ||||
| local function undefined() | ||||
| 	return undefined | ||||
| end | ||||
|  | ||||
| local ArrayMT = {} | ||||
|  | ||||
| --[[ | ||||
| 	Return's true if the metatable marks it as an array.. | ||||
| 	Or false if it has no array component at all | ||||
| 	Otherwise nil to get the normal detection component working | ||||
| ]] | ||||
| local function IsArray(value) | ||||
| 	if type(value) ~= 'table' then return false end | ||||
| 	local meta = getmetatable(value) | ||||
| 	local ret = meta == ArrayMT or (meta ~= nil and meta.__is_luajson_array) | ||||
| 	if not ret then | ||||
| 		if #value == 0 then return false end | ||||
| 	else | ||||
| 		return ret | ||||
| 	end | ||||
| end | ||||
| local function InitArray(array) | ||||
| 	setmetatable(array, ArrayMT) | ||||
| 	return array | ||||
| end | ||||
|  | ||||
| local CallMT = {} | ||||
|  | ||||
| local function isCall(value) | ||||
| 	return CallMT == getmetatable(value) | ||||
| end | ||||
|  | ||||
| local function buildCall(name, ...) | ||||
| 	local callData = { | ||||
| 		name = name, | ||||
| 		parameters = {n = select('#', ...), ...} | ||||
| 	} | ||||
| 	return setmetatable(callData, CallMT) | ||||
| end | ||||
|  | ||||
| local function decodeCall(callData) | ||||
| 	if not isCall(callData) then return nil end | ||||
| 	return callData.name, callData.parameters | ||||
| end | ||||
|  | ||||
| local function doOptionMerge(options, nested, name, defaultOptions, modeOptions) | ||||
| 	if nested then | ||||
| 		modeOptions = modeOptions and modeOptions[name] | ||||
| 		defaultOptions = defaultOptions and defaultOptions[name] | ||||
| 	end | ||||
| 	options[name] = merge( | ||||
| 		{}, | ||||
| 		defaultOptions, | ||||
| 		modeOptions, | ||||
| 		options[name] | ||||
| 	) | ||||
| end | ||||
|  | ||||
| local json_util = { | ||||
| 	printValue = printValue, | ||||
| 	clone = clone, | ||||
| 	merge = merge, | ||||
| 	null = null, | ||||
| 	undefined = undefined, | ||||
| 	IsArray = IsArray, | ||||
| 	InitArray = InitArray, | ||||
| 	isCall = isCall, | ||||
| 	buildCall = buildCall, | ||||
| 	decodeCall = decodeCall, | ||||
| 	doOptionMerge = doOptionMerge | ||||
| } | ||||
|  | ||||
| return json_util | ||||
							
								
								
									
										95
									
								
								tools/luajson/test_json.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								tools/luajson/test_json.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| package.path = package.path .. ";lua_scripts/libraries/luajson/?.lua" | ||||
|  | ||||
| local JSON = require"json" | ||||
|  | ||||
| local jsontest = [[{ 1:{"scn_ptz_id":"", | ||||
| "scn_ptz_prepos":"Preset 176", | ||||
| "scn_ptz_order":1, | ||||
| "scn_ptz_duration":"30", | ||||
| "scn_ptz_rally_delay":"2"} | ||||
| , | ||||
| 2:{"scn_ptz_id":"","scn_ptz_prepos":"route","scn_ptz_order":2,"scn_ptz_duration":"30","scn_ptz_rally_delay":"2"} } | ||||
| ]] | ||||
| local jsontest2 = [[{ | ||||
| 	"extension":"mpg", | ||||
| 	"id":1545148451781, | ||||
| 	"name":"Foule_1280x720p.mpg", | ||||
| 	"size":67240746, | ||||
| 	"date":1545148451, | ||||
| 	"mime":"video\/mpeg", | ||||
| 	"filename":"1545148451781.mpg", | ||||
| 	"dir":"\/home\/pixalarm_data\/fileprocessor_data", | ||||
| 	"function_metadatas": | ||||
| 	{ | ||||
| 		"function_faceblur": | ||||
| 		{ | ||||
| 		   "date":1545228627, | ||||
| 		   "current_frame":"845", | ||||
| 		   "polygons":[ | ||||
| 			{ | ||||
| 				"polygon_id":"new_1", | ||||
| 				"polygon_vertex":"[ | ||||
| 				   [0.14254859611231102,0.12476007677543186],[0.13174946004319654,0.4740882917466411], | ||||
| 				   [0.3898488120950324,0.6621880998080614],[0.4038876889848812,0.11516314779270634] | ||||
| 				]", | ||||
| 				"polygon_frame_start":"1", | ||||
| 				"polygon_frame_stop":"300", | ||||
|                                 "polygon_type":"full_blur" | ||||
| 			}, | ||||
| 			{ | ||||
| 				"polygon_id":"new_2", | ||||
| 				"polygon_vertex":"[ | ||||
| 				   [0.6198704103671706,0.1727447216890595],[0.5496760259179265,0.6007677543186181], | ||||
| 				   [0.7775377969762419,0.7946257197696737],[0.9028077753779697,0.761996161228407], | ||||
| 				   [0.9481641468682506,0.2821497120921305],[0.7829373650107991,0.04798464491362764] | ||||
| 				]", | ||||
| 				"polygon_frame_start":"200", | ||||
| 				"polygon_frame_stop":"845", | ||||
|                                 "polygon_type":"no_blur" | ||||
| 			} | ||||
|                    ], | ||||
| 		   "framecuts":[ | ||||
| 		      ["17","110"], | ||||
| 		      ["248","298"], | ||||
| 		      ["488","620"], | ||||
| 		      ["378","428"] | ||||
| 		   ], | ||||
|                    "face_selection":[ | ||||
|                        { | ||||
|                          "frame":"21", | ||||
|                           "x":"0.5", | ||||
|                           "y":"0.356" | ||||
|                        }, | ||||
|                        { | ||||
|                           "frame":"108", | ||||
|                           "x":"0.4289", | ||||
|                           "y":"0.275" | ||||
|                        }, | ||||
|                        { | ||||
|                           "frame":"294", | ||||
|                           "x":"0.726", | ||||
|                            "y":"0.2364" | ||||
|                        } | ||||
|                     ], | ||||
| 		    "blur_type":"blur", | ||||
| 		    "blur_area":"face" | ||||
| 		} | ||||
| 	}, | ||||
| 	"total_frame":"845", | ||||
| 	"status":"DECODE_FINISHED", | ||||
| 	"fps":"25.00" | ||||
| }]] | ||||
|  | ||||
| local res = JSON.decode(jsontest2) | ||||
| for k, v in pairs(res) do | ||||
|   print( k, v) | ||||
| end | ||||
|  | ||||
| res = JSON.decode( '{"content" : {},"date" : "2014-12-30T08:29:48Z","error" : {"code" : 0,"httpcode" : 200,"message" : ""},"status" : 1}' ) | ||||
| for k, v in pairs(res) do | ||||
|   print( k, v) | ||||
| end | ||||
|  | ||||
| local jsondata = JSON.encode( res ) | ||||
| print(jsondata) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user