190 lines
4.2 KiB
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
|