2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
5 local lpeg
= require("lpeg")
7 local util
= require("json.decode.util")
8 local merge
= require("json.util").merge
10 local tonumber = tonumber
13 local tostring = tostring
17 module("json.decode.object")
19 -- BEGIN LPEG < 0.9 SUPPORT
20 local initObject
, applyObjectKey
21 if not (lpeg
.Cg
and lpeg
.Cf
and lpeg
.Ct
) then
25 function applyObjectKey(tab
, key
, val
)
30 -- END LPEG < 0.9 SUPPORT
32 local defaultOptions
= {
38 default
= nil -- Let the buildCapture optimization take place
46 local function buildItemSequence(objectItem
, ignored
)
47 return (objectItem
* (ignored
* lpeg
.P(",") * ignored
* objectItem
)^
0) + 0
50 local function buildCapture(options
, global_options
, state
)
51 local ignored
= global_options
.ignored
52 local string_type
= lpeg
.V(util
.types
.STRING
)
53 local integer_type
= lpeg
.V(util
.types
.INTEGER
)
54 local value_type
= lpeg
.V(util
.types
.VALUE
)
55 -- If match-time capture supported, use it to remove stack limit for JSON
57 value_type
= lpeg
.Cmt(lpeg
.Cp(), function(str
, i
)
58 -- Decode one value then return
61 -- Found empty segment
62 #lpeg
.P('}' * lpeg
.Cc(END_MARKER
) * lpeg
.Cp())
63 -- Found a value + captured, check for required , or } + capture next pos
64 + state
.VALUE_MATCH
* #(lpeg
.P(',') + lpeg
.P('}')) * lpeg
.Cp()
65 local capture
, i
= pattern
:match(str
, i
)
66 if END_MARKER
== capture
then
68 elseif (i
== nil and capture
== nil) then
77 options
= options
and merge({}, defaultOptions
, options
) or defaultOptions
78 local key
= string_type
79 if options
.identifier
then
80 key
= key
+ lpeg
.C(util
.identifier
)
82 if options
.number then
83 key
= key
+ integer_type
86 local objectItem
= (key
* ignored
* lpeg
.P(":") * ignored
* value_type
)
87 -- BEGIN LPEG < 0.9 SUPPORT
88 if not (lpeg
.Cg
and lpeg
.Cf
and lpeg
.Ct
) then
89 objectItems
= buildItemSequence(objectItem
/ applyObjectKey
, ignored
)
90 objectItems
= lpeg
.Ca(lpeg
.Cc(false) / initObject
* objectItems
)
91 -- END LPEG < 0.9 SUPPORT
93 objectItems
= buildItemSequence(lpeg
.Cg(objectItem
), ignored
)
94 objectItems
= lpeg
.Cf(lpeg
.Ct(0) * objectItems
, rawset)
98 local capture
= lpeg
.P("{") * ignored
99 capture
= capture
* objectItems
* ignored
100 if options
.trailingComma
then
101 capture
= capture
* (lpeg
.P(",") + 0) * ignored
103 capture
= capture
* lpeg
.P("}")
107 function register_types()
108 util
.register_type("OBJECT")
111 function load_types(options
, global_options
, grammar
, state
)
112 local capture
= buildCapture(options
, global_options
, state
)
113 local object_id
= util
.types
.OBJECT
114 grammar
[object_id
] = capture
115 util
.append_grammar_item(grammar
, "VALUE", lpeg
.V(object_id
))