swade-fr-content/tools/luajson/json/decode/state.lua

190 lines
4.2 KiB
Lua

--[[
Licensed according to the included 'LICENSE' document
Author: Thomas Harning Jr <harningt@gmail.com>
]]
local setmetatable = setmetatable
local jsonutil = require("json.util")
local assert = assert
local type = type
local next = next
local unpack = require("table").unpack or unpack
local _ENV = nil
local state_ops = {}
local state_mt = {
__index = state_ops
}
function state_ops.pop(self)
self.previous_set = true
self.previous = self.active
local i = self.i
-- Load in this array into the active item
self.active = self.stack[i]
self.active_state = self.state_stack[i]
self.active_key = self.key_stack[i]
self.stack[i] = nil
self.state_stack[i] = nil
self.key_stack[i] = nil
self.i = i - 1
end
function state_ops.push(self)
local i = self.i + 1
self.i = i
self.stack[i] = self.active
self.state_stack[i] = self.active_state
self.key_stack[i] = self.active_key
end
function state_ops.put_object_value(self, trailing)
local object_options = self.options.object
if trailing and object_options.trailingComma then
if not self.active_key then
return
end
end
assert(self.active_key, "Missing key value")
object_options.setObjectKey(self.active, self.active_key, self:grab_value())
self.active_key = nil
end
function state_ops.put_array_value(self, trailing)
-- Safety check
if trailing and not self.previous_set and self.options.array.trailingComma then
return
end
local new_index = self.active_state + 1
self.active_state = new_index
self.active[new_index] = self:grab_value()
end
function state_ops.put_value(self, trailing)
if self.active_state == 'object' then
self:put_object_value(trailing)
else
self:put_array_value(trailing)
end
end
function state_ops.new_array(self)
local new_array = {}
if jsonutil.InitArray then
new_array = jsonutil.InitArray(new_array) or new_array
end
self.active = new_array
self.active_state = 0
self.active_key = nil
self:unset_value()
end
function state_ops.end_array(self)
if self.previous_set or self.active_state ~= 0 then
-- Not an empty array
self:put_value(true)
end
if self.active_state ~= #self.active then
-- Store the length in
self.active.n = self.active_state
end
end
function state_ops.new_object(self)
local new_object = {}
self.active = new_object
self.active_state = 'object'
self.active_key = nil
self:unset_value()
end
function state_ops.end_object(self)
if self.previous_set or next(self.active) then
-- Not an empty object
self:put_value(true)
end
end
function state_ops.new_call(self, name, func)
-- TODO setup properly
local new_call = {}
new_call.name = name
new_call.func = func
self.active = new_call
self.active_state = 0
self.active_key = nil
self:unset_value()
end
function state_ops.end_call(self)
if self.previous_set or self.active_state ~= 0 then
-- Not an empty array
self:put_value(true)
end
if self.active_state ~= #self.active then
-- Store the length in
self.active.n = self.active_state
end
local func = self.active.func
if func == true then
func = jsonutil.buildCall
end
self.active = func(self.active.name, unpack(self.active, 1, self.active.n or #self.active))
end
function state_ops.unset_value(self)
self.previous_set = false
self.previous = nil
end
function state_ops.grab_value(self)
assert(self.previous_set, "Previous value not set")
self.previous_set = false
return self.previous
end
function state_ops.set_value(self, value)
assert(not self.previous_set, "Value set when one already in slot")
self.previous_set = true
self.previous = value
end
function state_ops.set_key(self)
assert(self.active_state == 'object', "Cannot set key on array")
local value = self:grab_value()
local value_type = type(value)
if self.options.object.number then
assert(value_type == 'string' or value_type == 'number', "As configured, a key must be a number or string")
else
assert(value_type == 'string', "As configured, a key must be a string")
end
self.active_key = value
end
local function create(options)
local ret = {
options = options,
stack = {},
state_stack = {},
key_stack = {},
i = 0,
active = nil,
active_key = nil,
previous = nil,
active_state = nil
}
return setmetatable(ret, state_mt)
end
local state = {
create = create
}
return state