2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
8 local lpeg
= require("lpeg")
10 local util
= require("json.decode.util")
11 local jsonutil
= require("json.util")
16 local tostring = tostring
19 local getmetatable
= getmetatable
23 local defaultOptions
= {
25 allowEmptyElement
= false,
30 allowEmptyElement
= false,
37 allowEmptyElement
= false,
39 -- By default, do not allow undefined calls to be de-serialized as call objects
40 allowUndefined
= false,
52 trailingComma
= false,
59 local function BEGIN_ARRAY(state
)
63 local function END_ARRAY(state
)
68 local function BEGIN_OBJECT(state
)
72 local function END_OBJECT(state
)
77 local function END_CALL(state
)
82 local function SET_KEY(state
)
86 local function NEXT_VALUE(state
)
90 local function mergeOptions(options
, mode
)
91 jsonutil
.doOptionMerge(options
, true, 'array', defaultOptions
, mode
and modeOptions
[mode
])
92 jsonutil
.doOptionMerge(options
, true, 'object', defaultOptions
, mode
and modeOptions
[mode
])
93 jsonutil
.doOptionMerge(options
, true, 'calls', defaultOptions
, mode
and modeOptions
[mode
])
99 function isPattern(value
)
100 return lpeg
.type(value
) == 'pattern'
103 local metaAdd
= getmetatable(lpeg
.P("")).__add
104 function isPattern(value
)
105 return getmetatable(value
).__add
== metaAdd
110 local function generateSingleCallLexer(name
, func
)
111 if type(name
) ~= 'string' and not isPattern(name
) then
112 error("Invalid functionCalls name: " .. tostring(name
) .. " not a string or LPEG pattern")
114 -- Allow boolean or function to match up w/ encoding permissions
115 if type(func
) ~= 'boolean' and type(func
) ~= 'function' then
116 error("Invalid functionCalls item: " .. name
.. " not a function")
118 local function buildCallCapture(name
)
119 return function(state
)
120 if func
== false then
121 error("Function call on '" .. name
.. "' not permitted")
124 state
:new_call(name
, func
)
127 local nameCallCapture
128 if type(name
) == 'string' then
129 nameCallCapture
= lpeg
.P(name
.. "(") * lpeg
.Cc(name
) / buildCallCapture
131 -- Name matcher expected to produce a capture
132 nameCallCapture
= name
* "(" / buildCallCapture
134 -- Call func over nameCallCapture and value to permit function receiving name
135 return nameCallCapture
138 local function generateNamedCallLexers(options
)
139 if not options
.calls
or not options
.calls
.defs
then
143 for name
, func
in pairs(options
.calls
.defs
) do
144 local newCapture
= generateSingleCallLexer(name
, func
)
145 if not callCapture
then
146 callCapture
= newCapture
148 callCapture
= callCapture
+ newCapture
154 local function generateCallLexer(options
)
156 local namedCapture
= generateNamedCallLexers(options
)
157 if options
.calls
and options
.calls
.allowUndefined
then
158 lexer
= generateSingleCallLexer(lpeg
.C(util
.identifier
), true)
161 lexer
= lexer
and lexer
+ namedCapture
or namedCapture
164 lexer
= lexer
+ lpeg
.P(")") * lpeg
.Cc(END_CALL
)
169 local function generateLexer(options
)
170 local ignored
= options
.ignored
171 local array_options
, object_options
= options
.array
, options
.object
173 lpeg
.P("[") * lpeg
.Cc(BEGIN_ARRAY
)
174 + lpeg
.P("]") * lpeg
.Cc(END_ARRAY
)
175 + lpeg
.P("{") * lpeg
.Cc(BEGIN_OBJECT
)
176 + lpeg
.P("}") * lpeg
.Cc(END_OBJECT
)
177 + lpeg
.P(":") * lpeg
.Cc(SET_KEY
)
178 + lpeg
.P(",") * lpeg
.Cc(NEXT_VALUE
)
179 if object_options
.identifier
then
180 -- Add identifier match w/ validation check that it is in key
181 lexer
= lexer
+ lpeg
.C(util
.identifier
) * ignored
* lpeg
.P(":") * lpeg
.Cc(SET_KEY
)
183 local callLexers
= generateCallLexer(options
)
185 lexer
= lexer
+ callLexers
191 mergeOptions
= mergeOptions
,
192 generateLexer
= generateLexer