decode+docs+tests: adds support for (array/object/calls).allowEmptyElement to address...
[luajson.git] / lua / json / decode / state.lua
bloba269d7c9220f0c84a2893739d97d115fe2e63e3d
1 --[[
2 Licensed according to the included 'LICENSE' document
3 Author: Thomas Harning Jr <harningt@gmail.com>
4 ]]
6 local setmetatable = setmetatable
7 local jsonutil = require("json.util")
8 local assert = assert
9 local type = type
10 local next = next
11 local unpack = require("table").unpack or unpack
13 local _ENV = nil
15 local state_ops = {}
16 local state_mt = {
17 __index = state_ops
20 function state_ops.pop(self)
21 self.previous_set = true
22 self.previous = self.active
23 local i = self.i
24 -- Load in this array into the active item
25 self.active = self.stack[i]
26 self.active_state = self.state_stack[i]
27 self.active_key = self.key_stack[i]
28 self.stack[i] = nil
29 self.state_stack[i] = nil
30 self.key_stack[i] = nil
32 self.i = i - 1
33 end
35 function state_ops.push(self)
36 local i = self.i + 1
37 self.i = i
39 self.stack[i] = self.active
40 self.state_stack[i] = self.active_state
41 self.key_stack[i] = self.active_key
42 end
44 function state_ops.put_object_value(self, trailing)
45 local object_options = self.options.object
46 if trailing and object_options.trailingComma then
47 if not self.active_key then
48 return
49 end
50 end
51 assert(self.active_key, "Missing key value")
52 object_options.setObjectKey(self.active, self.active_key, self:grab_value(object_options.allowEmptyElement))
53 self.active_key = nil
54 end
56 function state_ops.put_array_value(self, trailing)
57 local array_options = self.options.array
58 -- Safety check
59 if trailing and not self.previous_set and array_options.trailingComma then
60 return
61 end
62 local new_index = self.active_state + 1
63 self.active_state = new_index
64 self.active[new_index] = self:grab_value(array_options.allowEmptyElement)
65 end
67 function state_ops.put_call_value(self, trailing)
68 local call_options = self.options.calls
69 -- Safety check
70 if trailing and not self.previous_set and call_options.trailingComma then
71 return
72 end
73 local new_index = self.active_state + 1
74 self.active_state = new_index
75 self.active[new_index] = self:grab_value(call_options.allowEmptyElement)
76 end
78 function state_ops.put_value(self, trailing)
79 if self.active_state == 'object' then
80 self:put_object_value(trailing)
81 elseif self.active.func then
82 self:put_call_value(trailing)
83 else
84 self:put_array_value(trailing)
85 end
86 end
88 function state_ops.new_array(self)
89 local new_array = {}
90 if jsonutil.InitArray then
91 new_array = jsonutil.InitArray(new_array) or new_array
92 end
93 self.active = new_array
94 self.active_state = 0
95 self.active_key = nil
96 self:unset_value()
97 end
99 function state_ops.end_array(self)
100 if self.previous_set or self.active_state ~= 0 then
101 -- Not an empty array
102 self:put_value(true)
104 if self.active_state ~= #self.active then
105 -- Store the length in
106 self.active.n = self.active_state
110 function state_ops.new_object(self)
111 local new_object = {}
112 self.active = new_object
113 self.active_state = 'object'
114 self.active_key = nil
115 self:unset_value()
118 function state_ops.end_object(self)
119 if self.active_key or self.previous_set or next(self.active) then
120 -- Not an empty object
121 self:put_value(true)
125 function state_ops.new_call(self, name, func)
126 -- TODO setup properly
127 local new_call = {}
128 new_call.name = name
129 new_call.func = func
130 self.active = new_call
131 self.active_state = 0
132 self.active_key = nil
133 self:unset_value()
136 function state_ops.end_call(self)
137 if self.previous_set or self.active_state ~= 0 then
138 -- Not an empty array
139 self:put_value(true)
141 if self.active_state ~= #self.active then
142 -- Store the length in
143 self.active.n = self.active_state
145 local func = self.active.func
146 if func == true then
147 func = jsonutil.buildCall
149 self.active = func(self.active.name, unpack(self.active, 1, self.active.n or #self.active))
153 function state_ops.unset_value(self)
154 self.previous_set = false
155 self.previous = nil
158 function state_ops.grab_value(self, allowEmptyValue)
159 if not self.previous_set and allowEmptyValue then
160 -- Calculate an appropriate empty-value
161 return self.emptyValue
163 assert(self.previous_set, "Previous value not set")
164 self.previous_set = false
165 return self.previous
168 function state_ops.set_value(self, value)
169 assert(not self.previous_set, "Value set when one already in slot")
170 self.previous_set = true
171 self.previous = value
174 function state_ops.set_key(self)
175 assert(self.active_state == 'object', "Cannot set key on array")
176 local value = self:grab_value()
177 local value_type = type(value)
178 if self.options.object.number then
179 assert(value_type == 'string' or value_type == 'number', "As configured, a key must be a number or string")
180 else
181 assert(value_type == 'string', "As configured, a key must be a string")
183 self.active_key = value
187 local function create(options)
188 local emptyValue
189 -- Calculate an empty value up front
190 if options.others.allowUndefined then
191 emptyValue = options.others.undefined or nil
192 else
193 emptyValue = options.others.null or nil
195 local ret = {
196 options = options,
197 stack = {},
198 state_stack = {},
199 key_stack = {},
200 i = 0,
201 active = nil,
202 active_key = nil,
203 previous = nil,
204 active_state = nil,
205 emptyValue = emptyValue
207 return setmetatable(ret, state_mt)
210 local state = {
211 create = create
214 return state