base: fixes regression test lua path
[luajson.git] / lua / json / decode / calls.lua
blob5455eeef5602bb285635407eb5a87e51a5cd8c5f
1 --[[
2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
4 ]]
5 local lpeg = require("lpeg")
6 local tostring = tostring
7 local pairs, ipairs = pairs, ipairs
8 local next, type = next, type
9 local error = error
11 local util = require("json.decode.util")
13 local buildCall = require("json.util").buildCall
15 local getmetatable = getmetatable
17 module("json.decode.calls")
19 local defaultOptions = {
20 defs = nil,
21 -- By default, do not allow undefined calls to be de-serialized as call objects
22 allowUndefined = false
25 -- No real default-option handling needed...
26 default = nil
27 strict = nil
29 local isPattern
30 if lpeg.type then
31 function isPattern(value)
32 return lpeg.type(value) == 'pattern'
33 end
34 else
35 local metaAdd = getmetatable(lpeg.P("")).__add
36 function isPattern(value)
37 return getmetatable(value).__add == metaAdd
38 end
39 end
41 local function buildDefinedCaptures(argumentCapture, defs)
42 local callCapture
43 if not defs then return end
44 for name, func in pairs(defs) do
45 if type(name) ~= 'string' and not isPattern(name) then
46 error("Invalid functionCalls name: " .. tostring(name) .. " not a string or LPEG pattern")
47 end
48 -- Allow boolean or function to match up w/ encoding permissions
49 if type(func) ~= 'boolean' and type(func) ~= 'function' then
50 error("Invalid functionCalls item: " .. name .. " not a function")
51 end
52 local nameCallCapture
53 if type(name) == 'string' then
54 nameCallCapture = lpeg.P(name .. "(") * lpeg.Cc(name)
55 else
56 -- Name matcher expected to produce a capture
57 nameCallCapture = name * "("
58 end
59 -- Call func over nameCallCapture and value to permit function receiving name
61 -- Process 'func' if it is not a function
62 if type(func) == 'boolean' then
63 local allowed = func
64 func = function(name, ...)
65 if not allowed then
66 error("Function call on '" .. name .. "' not permitted")
67 end
68 return buildCall(name, ...)
69 end
70 end
71 local newCapture = (nameCallCapture * argumentCapture) / func * ")"
72 if not callCapture then
73 callCapture = newCapture
74 else
75 callCapture = callCapture + newCapture
76 end
77 end
78 return callCapture
79 end
81 local function buildCapture(options, global_options, state)
82 if not options -- No ops, don't bother to parse
83 or not (options.defs and (nil ~= next(options.defs)) or options.allowUndefined) then
84 return nil
85 end
86 -- Allow zero or more arguments separated by commas
87 local value = lpeg.V(util.types.VALUE)
88 if lpeg.Cmt then
89 value = lpeg.Cmt(lpeg.Cp(), function(str, i)
90 -- Decode one value then return
91 local END_MARKER = {}
92 local pattern =
93 -- Found empty segment
94 #lpeg.P(')' * lpeg.Cc(END_MARKER) * lpeg.Cp())
95 -- Found a value + captured, check for required , or ) + capture next pos
96 + state.VALUE_MATCH * #(lpeg.P(',') + lpeg.P(')')) * lpeg.Cp()
97 local capture, i = pattern:match(str, i)
98 if END_MARKER == capture then
99 return i
100 elseif (i == nil and capture == nil) then
101 return false
102 else
103 return i, capture
105 end)
107 local argumentCapture = (value * (lpeg.P(",") * value)^0) + 0
108 local callCapture = buildDefinedCaptures(argumentCapture, options.defs)
109 if options.allowUndefined then
110 local function func(name, ...)
111 return buildCall(name, ...)
113 -- Identifier-type-match
114 local nameCallCapture = lpeg.C(util.identifier) * "("
115 local newCapture = (nameCallCapture * argumentCapture) / func * ")"
116 if not callCapture then
117 callCapture = newCapture
118 else
119 callCapture = callCapture + newCapture
122 return callCapture
125 function load_types(options, global_options, grammar, state)
126 local capture = buildCapture(options, global_options, state)
127 if capture then
128 util.append_grammar_item(grammar, "VALUE", capture)