blob: 94b699d8efea2f2d17e139a480c8371c2c6d582e [file] [log] [blame]
--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local lpeg = require("lpeg")
local util = require("json.decode.util")
local merge = require("json.util").merge
local tonumber = tonumber
local unpack = unpack
local print = print
local tostring = tostring
local rawset = rawset
module("json.decode.object")
-- BEGIN LPEG < 0.9 SUPPORT
local initObject, applyObjectKey
if not (lpeg.Cg and lpeg.Cf and lpeg.Ct) then
function initObject()
return {}
end
function applyObjectKey(tab, key, val)
tab[key] = val
return tab
end
end
-- END LPEG < 0.9 SUPPORT
local defaultOptions = {
number = true,
identifier = true,
trailingComma = true
}
default = nil -- Let the buildCapture optimization take place
strict = {
number = false,
identifier = false,
trailingComma = false
}
local function buildItemSequence(objectItem, ignored)
return (objectItem * (ignored * lpeg.P(",") * ignored * objectItem)^0) + 0
end
local function buildCapture(options, global_options)
local ignored = global_options.ignored
local string_type = lpeg.V(util.types.STRING)
local integer_type = lpeg.V(util.types.INTEGER)
local value_type = lpeg.V(util.types.VALUE)
options = options and merge({}, defaultOptions, options) or defaultOptions
local key = string_type
if options.identifier then
key = key + lpeg.C(util.identifier)
end
if options.number then
key = key + integer_type
end
local objectItems
local objectItem = (key * ignored * lpeg.P(":") * ignored * value_type)
-- BEGIN LPEG < 0.9 SUPPORT
if not (lpeg.Cg and lpeg.Cf and lpeg.Ct) then
local set_key = applyObjectKey
if options.setObjectKey then
local setObjectKey = options.setObjectKey
set_key = function(tab, key, val)
setObjectKey(tab, key, val)
return tab
end
end
objectItems = buildItemSequence(objectItem / set_key, ignored)
objectItems = lpeg.Ca(lpeg.Cc(false) / initObject * objectItems)
-- END LPEG < 0.9 SUPPORT
else
objectItems = buildItemSequence(lpeg.Cg(objectItem), ignored)
objectItems = lpeg.Cf(lpeg.Ct(0) * objectItems, options.setObjectKey or rawset)
end
local capture = lpeg.P("{") * ignored
capture = capture * objectItems * ignored
if options.trailingComma then
capture = capture * (lpeg.P(",") + 0) * ignored
end
capture = capture * lpeg.P("}")
return capture
end
function register_types()
util.register_type("OBJECT")
end
function load_types(options, global_options, grammar)
local capture = buildCapture(options, global_options)
local object_id = util.types.OBJECT
grammar[object_id] = capture
util.append_grammar_item(grammar, "VALUE", lpeg.V(object_id))
end