File: state.lua

package info (click to toggle)
lua-json 1.3.4-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 688 kB
  • sloc: makefile: 71; php: 3
file content (214 lines) | stat: -rw-r--r-- 5,178 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
--[[
	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(object_options.allowEmptyElement))
	self.active_key = nil
end

function state_ops.put_array_value(self, trailing)
	local array_options = self.options.array
	-- Safety check
	if trailing and not self.previous_set and array_options.trailingComma then
		return
	end
	local new_index = self.active_state + 1
	self.active_state = new_index
	self.active[new_index] = self:grab_value(array_options.allowEmptyElement)
end

function state_ops.put_call_value(self, trailing)
	local call_options = self.options.calls
	-- Safety check
	if trailing and not self.previous_set and call_options.trailingComma then
		return
	end
	local new_index = self.active_state + 1
	self.active_state = new_index
	self.active[new_index] = self:grab_value(call_options.allowEmptyElement)
end

function state_ops.put_value(self, trailing)
	if self.active_state == 'object' then
		self:put_object_value(trailing)
	elseif self.active.func then
		self:put_call_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.active_key or 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, allowEmptyValue)
	if not self.previous_set and allowEmptyValue then
		-- Calculate an appropriate empty-value
		return self.emptyValue
	end
	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 emptyValue
	-- Calculate an empty value up front
	if options.others.allowUndefined then
		emptyValue = options.others.undefined or nil
	else
		emptyValue = options.others.null or nil
	end
	local ret = {
		options = options,
		stack = {},
		state_stack = {},
		key_stack = {},
		i = 0,
		active = nil,
		active_key = nil,
		previous = nil,
		active_state = nil,
		emptyValue = emptyValue
	}
	return setmetatable(ret, state_mt)
end

local state = {
	create = create
}

return state