2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
5 local lpeg
= require("lpeg")
10 local jsonutil
= require("json.util")
11 local merge
= jsonutil
.merge
12 local util
= require("json.decode.util")
14 local decode_state
= require("json.decode.state")
16 local setmetatable
, getmetatable
= setmetatable
, getmetatable
18 local ipairs
, pairs
= ipairs
, pairs
19 local string_char
= require("string").char
23 local require
= require
27 local modulesToLoad
= {
33 local loadedModules
= {
36 local json_decode
= {}
38 json_decode
.default
= {
39 unicodeWhitespace
= true,
40 initialObject
= false,
44 local modes_defined
= { "default", "strict", "simple" }
46 json_decode
.simple
= {}
48 json_decode
.strict
= {
49 unicodeWhitespace
= true,
54 for _
,name
in ipairs(modulesToLoad
) do
55 local mod = require("json.decode." .. name
)
56 if mod.mergeOptions
then
57 for _
, mode
in pairs(modes_defined
) do
58 mod.mergeOptions(json_decode
[mode
], mode
)
61 loadedModules
[#loadedModules
+ 1] = mod
64 -- Shift over default into defaultOptions to permit build optimization
65 local defaultOptions
= json_decode
.default
66 json_decode
.default
= nil
68 local function generateDecoder(lexer
, options
)
69 -- Marker to permit detection of final end
71 local parser
= lpeg
.Ct((options
.ignored
* lexer
)^
0 * lpeg
.Cc(marker
)) * options
.ignored
* (lpeg
.P(-1) + util
.unexpected())
72 local decoder
= function(data
)
73 local state
= decode_state
.create(options
)
74 local parsed
= parser
:match(data
)
75 assert(parsed
, "Invalid JSON data")
79 local item
= parsed
[i
]
80 if item
== marker
then break end
81 if type(item
) == 'function' and item
~= jsonutil
.undefined
and item
~= jsonutil
.null
then
87 if options
.initialObject
then
88 assert(type(state
.previous
) == 'table', "Initial value not an object or array")
90 -- Make sure stack is empty
91 assert(state
.i
== 0, "Unclosed elements present")
94 if options
.nothrow
then
96 local status
, rv
= pcall(decoder
, data
)
107 local function buildDecoder(mode
)
108 mode
= mode
and merge({}, defaultOptions
, mode
) or defaultOptions
109 for _
, mod in ipairs(loadedModules
) do
110 if mod.mergeOptions
then
111 mod.mergeOptions(mode
)
114 local ignored
= mode
.unicodeWhitespace
and util
.unicode_ignored
or util
.ascii_ignored
115 -- Store 'ignored' in the global options table
116 mode
.ignored
= ignored
119 -- [1] = mode.initialObject and (ignored * (object_type + array_type)) or value_type
122 for _
, mod in ipairs(loadedModules
) do
123 local new_lexer
= mod.generateLexer(mode
)
124 lexer
= lexer
and lexer
+ new_lexer
or new_lexer
126 return generateDecoder(lexer
, mode
)
129 -- Since 'default' is nil, we cannot take map it
130 local defaultDecoder
= buildDecoder(json_decode
.default
)
131 local prebuilt_decoders
= {}
132 for _
, mode
in pairs(modes_defined
) do
133 if json_decode
[mode
] ~= nil then
134 prebuilt_decoders
[json_decode
[mode]]
= buildDecoder(json_decode
[mode
])
140 number => number decode options
141 string => string decode options
142 array => array decode options
143 object => object decode options
144 initialObject => whether or not to require the initial object to be a table/array
145 allowUndefined => whether or not to allow undefined values
147 local function getDecoder(mode
)
148 mode
= mode
== true and json_decode
.strict
or mode
or json_decode
.default
149 local decoder
= mode
== nil and defaultDecoder
or prebuilt_decoders
[mode
]
153 return buildDecoder(mode
)
156 local function decode(data
, mode
)
157 local decoder
= getDecoder(mode
)
162 mt
.__call
= function(self
, ...)
166 json_decode
.getDecoder
= getDecoder
167 json_decode
.decode
= decode
168 json_decode
.util
= util
169 setmetatable(json_decode
, mt
)