summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/util-jsn.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/util-jsn.lua')
-rw-r--r--tex/context/base/mkiv/util-jsn.lua95
1 files changed, 60 insertions, 35 deletions
diff --git a/tex/context/base/mkiv/util-jsn.lua b/tex/context/base/mkiv/util-jsn.lua
index e5f83e06c..acbf16090 100644
--- a/tex/context/base/mkiv/util-jsn.lua
+++ b/tex/context/base/mkiv/util-jsn.lua
@@ -14,10 +14,12 @@ if not modules then modules = { } end modules ['util-jsn'] = {
--
-- Reminder for me: check usage in framework and extend when needed. Also document
-- it in the cld lib documentation.
+--
+-- Upgraded for handling the somewhat more fax server templates.
local P, V, R, S, C, Cc, Cs, Ct, Cf, Cg = lpeg.P, lpeg.V, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cf, lpeg.Cg
local lpegmatch = lpeg.match
-local format = string.format
+local format, gsub = string.format, string.gsub
local utfchar = utf.char
local concat = table.concat
@@ -26,9 +28,6 @@ local tonumber, tostring, rawset, type, next = tonumber, tostring, rawset, type,
local json = utilities.json or { }
utilities.json = json
--- moduledata = moduledata or { }
--- moduledata.json = json
-
-- \\ \/ \b \f \n \r \t \uHHHH
local lbrace = P("{")
@@ -43,16 +42,19 @@ local whitespace = lpeg.patterns.whitespace
local optionalws = whitespace^0
local escapes = {
- -- ["\\"] = "\\", -- lua will escape these
- -- ["/"] = "/", -- no need to escape this one
- ["b"] = "\010",
- ["f"] = "\014",
- ["n"] = "\n",
- ["r"] = "\r",
- ["t"] = "\t",
+ ["b"] = "\010",
+ ["f"] = "\014",
+ ["n"] = "\n",
+ ["r"] = "\r",
+ ["t"] = "\t",
}
-local escape_un = C(P("\\u") / "0x" * S("09","AF","af")) / function(s) return utfchar(tonumber(s)) end
+-- todo: also handle larger utf16
+
+local escape_un = P("\\u")/"" * (C(R("09","AF","af")^-4) / function(s)
+ return utfchar(tonumber(s,16))
+end)
+
local escape_bs = P([[\]]) / "" * (P(1) / escapes) -- if not found then P(1) is returned i.e. the to be escaped char
local jstring = dquote * Cs((escape_un + escape_bs + (1-dquote))^0) * dquote
@@ -85,7 +87,9 @@ function json.tolua(str)
return lpegmatch(jsonconverter,str)
end
-local function tojson(value,t) -- we could optimize #t
+local escaper
+
+local function tojson(value,t,n) -- we could optimize #t
local kind = type(value)
if kind == "table" then
local done = false
@@ -93,60 +97,75 @@ local function tojson(value,t) -- we could optimize #t
if size == 0 then
for k, v in next, value do
if done then
- t[#t+1] = ","
+ n = n + 1 ; t[n] = ","
else
- t[#t+1] = "{"
+ n = n + 1 ; t[n] = "{"
done = true
end
- t[#t+1] = format("%q:",k)
- tojson(v,t)
+ n = n + 1 ; t[n] = format("%q:",k)
+ t, n = tojson(v,t,n)
end
if done then
- t[#t+1] = "}"
+ n = n + 1 ; t[n] = "}"
else
- t[#t+1] = "{}"
+ n = n + 1 ; t[n] = "{}"
end
elseif size == 1 then
-- we can optimize for non tables
- t[#t+1] = "["
- tojson(value[1],t)
- t[#t+1] = "]"
+ n = n + 1 ; t[n] = "["
+ t, n = tojson(value[1],t,n)
+ n = n + 1 ; t[n] = "]"
else
for i=1,size do
if done then
- t[#t+1] = ","
+ n = n + 1 ; t[n] = ","
else
- t[#t+1] = "["
+ n = n + 1 ; t[n] = "["
done = true
end
- tojson(value[i],t)
+ t, n = tojson(value[i],t,n)
end
- t[#t+1] = "]"
+ n = n + 1 ; t[n] = "]"
end
elseif kind == "string" then
- t[#t+1] = format("%q",value)
+ n = n + 1 ; t[n] = '"'
+ n = n + 1 ; t[n] = lpegmatch(escaper,value) or value
+ n = n + 1 ; t[n] = '"'
elseif kind == "number" then
- t[#t+1] = value
+ n = n + 1 ; t[n] = value
elseif kind == "boolean" then
- t[#t+1] = tostring(value)
+ n = n + 1 ; t[n] = tostring(value)
end
- return t
+ return t, n
end
function json.tostring(value)
-- todo optimize for non table
local kind = type(value)
if kind == "table" then
- return concat(tojson(value,{}),"")
+ if not escaper then
+ local escapes = {
+ ["\\"] = "\\u005C",
+ ["\""] = "\\u0022",
+ }
+ for i=0,0x20 do
+ escapes[utfchar(i)] = format("\\u%04X",i)
+ end
+ escaper = Cs( (
+ (R('\0\x20') + S('\"\\')) / escapes
+ + P(1)
+ )^1 )
+
+ end
+ return concat((tojson(value,{},0)))
elseif kind == "string" or kind == "number" then
- return value
+ return lpegmatch(escaper,value) or value
else
return tostring(value)
end
end
--- local tmp = [[ { "a" : true, "b" : [ 123 , 456E-10, { "a" : true, "b" : [ 123 , 456 ] } ] } ]]
-
+-- local tmp = [[ { "t" : "foobar", "a" : true, "b" : [ 123 , 456E-10, { "a" : true, "b" : [ 123 , 456 ] } ] } ]]
-- tmp = json.tolua(tmp)
-- inspect(tmp)
-- tmp = json.tostring(tmp)
@@ -155,7 +174,6 @@ end
-- inspect(tmp)
-- tmp = json.tostring(tmp)
-- inspect(tmp)
-
-- inspect(json.tostring(true))
function json.load(filename)
@@ -165,4 +183,11 @@ function json.load(filename)
end
end
+-- local s = [[\foo"bar"]]
+-- local j = json.tostring { s = s }
+-- local l = json.tolua(j)
+-- inspect(j)
+-- inspect(l)
+-- print(s==l.s)
+
return json