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 | # 0.20.0.3 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|   "name": "swade-fr", |   "name": "swade-fr", | ||||||
|   "title": "SWADE - Traduction française", |   "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>", |   "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", |   "minimumCoreVersion" : "0.7.9", | ||||||
|   "compatibleCoreVersion" : "9", |   "compatibleCoreVersion" : "9", | ||||||
|   "author": "BoboursToutCool, Gronyon, Kyane, LeRatierBretonnien, Sasmira, U~man,X.O. de Vorcen", |   "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", |   "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", |   "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-0.20.0.3.zip" |   "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