@@ -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
0 commit comments