172 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| --[[
 | |
| 	Licensed according to the included 'LICENSE' document
 | |
| 	Author: Thomas Harning Jr <harningt@gmail.com>
 | |
| ]]
 | |
| local lpeg = require("lpeg")
 | |
| 
 | |
| local error = error
 | |
| local pcall = pcall
 | |
| 
 | |
| local jsonutil = require("json.util")
 | |
| local merge = jsonutil.merge
 | |
| local util = require("json.decode.util")
 | |
| 
 | |
| local decode_state = require("json.decode.state")
 | |
| 
 | |
| local setmetatable, getmetatable = setmetatable, getmetatable
 | |
| local assert = assert
 | |
| local ipairs, pairs = ipairs, pairs
 | |
| local string_char = require("string").char
 | |
| 
 | |
| local type = type
 | |
| 
 | |
| local require = require
 | |
| 
 | |
| local _ENV = nil
 | |
| 
 | |
| local modulesToLoad = {
 | |
| 	"composite",
 | |
| 	"strings",
 | |
| 	"number",
 | |
| 	"others"
 | |
| }
 | |
| local loadedModules = {
 | |
| }
 | |
| 
 | |
| local json_decode = {}
 | |
| 
 | |
| json_decode.default = {
 | |
| 	unicodeWhitespace = true,
 | |
| 	initialObject = false,
 | |
| 	nothrow = false
 | |
| }
 | |
| 
 | |
| local modes_defined = { "default", "strict", "simple" }
 | |
| 
 | |
| json_decode.simple = {}
 | |
| 
 | |
| json_decode.strict = {
 | |
| 	unicodeWhitespace = true,
 | |
| 	initialObject = true,
 | |
| 	nothrow = false
 | |
| }
 | |
| 
 | |
| for _,name in ipairs(modulesToLoad) do
 | |
| 	local mod = require("json.decode." .. name)
 | |
| 	if mod.mergeOptions then
 | |
| 		for _, mode in pairs(modes_defined) do
 | |
| 			mod.mergeOptions(json_decode[mode], mode)
 | |
| 		end
 | |
| 	end
 | |
| 	loadedModules[#loadedModules + 1] = mod
 | |
| end
 | |
| 
 | |
| -- Shift over default into defaultOptions to permit build optimization
 | |
| local defaultOptions = json_decode.default
 | |
| json_decode.default = nil
 | |
| 
 | |
| local function generateDecoder(lexer, options)
 | |
| 	-- Marker to permit detection of final end
 | |
| 	local marker = {}
 | |
| 	local parser = lpeg.Ct((options.ignored * lexer)^0 * lpeg.Cc(marker)) * options.ignored * (lpeg.P(-1) + util.unexpected())
 | |
| 	local decoder = function(data)
 | |
| 		local state = decode_state.create(options)
 | |
| 		local parsed = parser:match(data)
 | |
| 		assert(parsed, "Invalid JSON data")
 | |
| 		local i = 0
 | |
| 		while true do
 | |
| 			i = i + 1
 | |
| 			local item = parsed[i]
 | |
| 			if item == marker then break end
 | |
| 			if type(item) == 'function' and item ~= jsonutil.undefined and item ~= jsonutil.null then
 | |
| 				item(state)
 | |
| 			else
 | |
| 				state:set_value(item)
 | |
| 			end
 | |
| 		end
 | |
| 		if options.initialObject then
 | |
| 			assert(type(state.previous) == 'table', "Initial value not an object or array")
 | |
| 		end
 | |
| 		-- Make sure stack is empty
 | |
| 		assert(state.i == 0, "Unclosed elements present")
 | |
| 		return state.previous
 | |
| 	end
 | |
| 	if options.nothrow then
 | |
| 		return function(data)
 | |
| 			local status, rv = pcall(decoder, data)
 | |
| 			if status then
 | |
| 				return rv
 | |
| 			else
 | |
| 				return nil, rv
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| 	return decoder
 | |
| end
 | |
| 
 | |
| local function buildDecoder(mode)
 | |
| 	mode = mode and merge({}, defaultOptions, mode) or defaultOptions
 | |
| 	for _, mod in ipairs(loadedModules) do
 | |
| 		if mod.mergeOptions then
 | |
| 			mod.mergeOptions(mode)
 | |
| 		end
 | |
| 	end
 | |
| 	local ignored = mode.unicodeWhitespace and util.unicode_ignored or util.ascii_ignored
 | |
| 	-- Store 'ignored' in the global options table
 | |
| 	mode.ignored = ignored
 | |
| 
 | |
| 	--local grammar = {
 | |
| 	--	[1] = mode.initialObject and (ignored * (object_type + array_type)) or value_type
 | |
| 	--}
 | |
| 	local lexer
 | |
| 	for _, mod in ipairs(loadedModules) do
 | |
| 		local new_lexer = mod.generateLexer(mode)
 | |
| 		lexer = lexer and lexer + new_lexer or new_lexer
 | |
| 	end
 | |
| 	return generateDecoder(lexer, mode)
 | |
| end
 | |
| 
 | |
| -- Since 'default' is nil, we cannot take map it
 | |
| local defaultDecoder = buildDecoder(json_decode.default)
 | |
| local prebuilt_decoders = {}
 | |
| for _, mode in pairs(modes_defined) do
 | |
| 	if json_decode[mode] ~= nil then
 | |
| 		prebuilt_decoders[json_decode[mode]] = buildDecoder(json_decode[mode])
 | |
| 	end
 | |
| end
 | |
| 
 | |
| --[[
 | |
| Options:
 | |
| 	number => number decode options
 | |
| 	string => string decode options
 | |
| 	array  => array decode options
 | |
| 	object => object decode options
 | |
| 	initialObject => whether or not to require the initial object to be a table/array
 | |
| 	allowUndefined => whether or not to allow undefined values
 | |
| ]]
 | |
| local function getDecoder(mode)
 | |
| 	mode = mode == true and json_decode.strict or mode or json_decode.default
 | |
| 	local decoder = mode == nil and defaultDecoder or prebuilt_decoders[mode]
 | |
| 	if decoder then
 | |
| 		return decoder
 | |
| 	end
 | |
| 	return buildDecoder(mode)
 | |
| end
 | |
| 
 | |
| local function decode(data, mode)
 | |
| 	local decoder = getDecoder(mode)
 | |
| 	return decoder(data)
 | |
| end
 | |
| 
 | |
| local mt = {}
 | |
| mt.__call = function(self, ...)
 | |
| 	return decode(...)
 | |
| end
 | |
| 
 | |
| json_decode.getDecoder = getDecoder
 | |
| json_decode.decode = decode
 | |
| json_decode.util = util
 | |
| setmetatable(json_decode, mt)
 | |
| 
 | |
| return json_decode
 |