@@ -51,20 +51,16 @@ local function escape_char(c)
5151end
5252
5353
54- local function encode_nil (val )
55- return " null"
54+ local function encode_nil (rope )
55+ rope [ # rope + 1 ] = " null"
5656end
5757
5858
59- local function encode_table (val , stack )
60- local res = {}
61- stack = stack or {}
62-
59+ local function encode_table (rope , val , stack )
6360 -- Circular reference?
6461 if stack [val ] then error (" circular reference" ) end
6562
6663 stack [val ] = true
67-
6864 if rawget (val , 1 ) ~= nil or next (val ) == nil then
6965 -- Treat as array -- check keys are valid and it is not sparse
7066 local n = 0
@@ -78,61 +74,80 @@ local function encode_table(val, stack)
7874 error (" invalid table: sparse array" )
7975 end
8076 -- Encode
77+ rope [# rope + 1 ] = " ["
8178 for i , v in ipairs (val ) do
82- table.insert (res , encode (v , stack ))
79+ if i > 1 then
80+ rope [# rope + 1 ] = " ,"
81+ end
82+ encode (rope , v , stack )
8383 end
84- stack [val ] = nil
85- return " [" .. table.concat (res , " ," ) .. " ]"
86-
84+ rope [# rope + 1 ] = " ]"
8785 else
8886 -- Treat as an object
87+ rope [# rope + 1 ] = " {"
88+ local first = true
8989 for k , v in pairs (val ) do
9090 if type (k ) ~= " string" then
9191 error (" invalid table: mixed or invalid key types" )
9292 end
93- table.insert (res , encode (k , stack ) .. " :" .. encode (v , stack ))
93+ if not first then
94+ rope [# rope + 1 ] = " ,"
95+ end
96+ encode (rope , k , stack )
97+ rope [# rope + 1 ] = " :"
98+ encode (rope , v , stack )
99+ first = false
94100 end
95- stack [val ] = nil
96- return " {" .. table.concat (res , " ," ) .. " }"
101+ rope [# rope + 1 ] = " }"
97102 end
103+ stack [val ] = nil
98104end
99105
100106
101- local function encode_string (val )
102- return ' "' .. val :gsub (' [%z\1 -\31 \\ "]' , escape_char ) .. ' "'
107+ local function encode_string (rope , val )
108+ rope [# rope + 1 ] = ' "'
109+ rope [# rope + 1 ] = val :gsub (' [%z\1 -\31 \\ "]' , escape_char )
110+ rope [# rope + 1 ] = ' "'
103111end
104112
105113
106- local function encode_number (val )
114+ local function encode_number (rope , val )
107115 -- Check for NaN, -inf and inf
108116 if val ~= val or val <= - math.huge or val >= math.huge then
109117 error (" unexpected number value '" .. tostring (val ) .. " '" )
110118 end
111- return string.format (" %.14g" , val )
119+ -- See www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF
120+ -- 17 digits suffice to losslessly represent 64-bit IEEE754 floats
121+ rope [# rope + 1 ] = (" %.17g" ):format (val )
112122end
113123
124+ local function encode_boolean (rope , val )
125+ rope [# rope + 1 ] = val and " true" or " false"
126+ end
114127
115128local type_func_map = {
116129 [ " nil" ] = encode_nil ,
117130 [ " table" ] = encode_table ,
118131 [ " string" ] = encode_string ,
119132 [ " number" ] = encode_number ,
120- [ " boolean" ] = tostring ,
133+ [ " boolean" ] = encode_boolean ,
121134}
122135
123136
124- encode = function ( val , stack )
137+ function encode ( rope , val , stack )
125138 local t = type (val )
126- local f = type_func_map [t ]
127- if f then
128- return f ( val , stack )
139+ local encoder = type_func_map [t ]
140+ if encoder then
141+ return encoder ( rope , val , stack )
129142 end
130143 error (" unexpected type '" .. t .. " '" )
131144end
132145
133146
134147function json .encode (val )
135- return ( encode (val ) )
148+ local rope = {}
149+ encode (rope , val , {})
150+ return table.concat (rope )
136151end
137152
138153
216231
217232
218233local function parse_string (str , i )
219- local res = " "
234+ local res = {}
220235 local j = i + 1
221236 local k = j
222237
@@ -227,32 +242,33 @@ local function parse_string(str, i)
227242 decode_error (str , j , " control character in string" )
228243
229244 elseif x == 92 then -- `\`: Escape
230- res = res .. str :sub (k , j - 1 )
245+ res [ # res + 1 ] = str :sub (k , j - 1 )
231246 j = j + 1
232247 local c = str :sub (j , j )
233248 if c == " u" then
234249 local hex = str :match (" ^[dD][89aAbB]%x%x\\ u%x%x%x%x" , j + 1 )
235250 or str :match (" ^%x%x%x%x" , j + 1 )
236251 or decode_error (str , j - 1 , " invalid unicode escape in string" )
237- res = res .. parse_unicode_escape (hex )
252+ res [ # res + 1 ] = parse_unicode_escape (hex )
238253 j = j + # hex
239254 else
240255 if not escape_chars [c ] then
241256 decode_error (str , j - 1 , " invalid escape char '" .. c .. " ' in string" )
242257 end
243- res = res .. escape_char_map_inv [c ]
258+ res [ # res + 1 ] = escape_char_map_inv [c ]
244259 end
245260 k = j + 1
246261
247262 elseif x == 34 then -- `"`: End of string
248- res = res .. str :sub (k , j - 1 )
249- return res , j + 1
263+ res [ # res + 1 ] = str :sub (k , j - 1 )
264+ return table.concat ( res ) , j + 1
250265 end
251266
252267 j = j + 1
253268 end
254269
255270 decode_error (str , i , " expected closing quote for string" )
271+ return table.concat (res )
256272end
257273
258274
@@ -385,4 +401,4 @@ function json.decode(str)
385401end
386402
387403
388- return json
404+ return json
0 commit comments