OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 160 matching lines...) Loading... |
171 return %_ValueOf(value) ? "true" : "false"; | 171 return %_ValueOf(value) ? "true" : "false"; |
172 } else { | 172 } else { |
173 return SerializeObject(value, replacer, stack, indent, gap); | 173 return SerializeObject(value, replacer, stack, indent, gap); |
174 } | 174 } |
175 } | 175 } |
176 // Undefined or a callable object. | 176 // Undefined or a callable object. |
177 return void 0; | 177 return void 0; |
178 } | 178 } |
179 | 179 |
180 | 180 |
181 function BasicSerializeArray(value, stack, builder) { | |
182 var len = value.length; | |
183 if (len == 0) { | |
184 builder.push("[]"); | |
185 return; | |
186 } | |
187 if (!%PushIfAbsent(stack, value)) { | |
188 throw MakeTypeError('circular_structure', $Array()); | |
189 } | |
190 builder.push("["); | |
191 var val = value[0]; | |
192 if (IS_STRING(val)) { | |
193 // First entry is a string. Remaining entries are likely to be strings too. | |
194 var array_string = %QuoteJSONStringArray(value); | |
195 if (!IS_UNDEFINED(array_string)) { | |
196 // array_string also includes bracket characters so we are done. | |
197 builder[builder.length - 1] = array_string; | |
198 stack.pop(); | |
199 return; | |
200 } else { | |
201 builder.push(%QuoteJSONString(val)); | |
202 for (var i = 1; i < len; i++) { | |
203 val = value[i]; | |
204 if (IS_STRING(val)) { | |
205 builder.push(%QuoteJSONStringComma(val)); | |
206 } else { | |
207 builder.push(","); | |
208 var before = builder.length; | |
209 BasicJSONSerialize(i, val, stack, builder); | |
210 if (before == builder.length) builder[before - 1] = ",null"; | |
211 } | |
212 } | |
213 } | |
214 } else if (IS_NUMBER(val)) { | |
215 // First entry is a number. Remaining entries are likely to be numbers too. | |
216 builder.push(JSON_NUMBER_TO_STRING(val)); | |
217 for (var i = 1; i < len; i++) { | |
218 builder.push(","); | |
219 val = value[i]; | |
220 if (IS_NUMBER(val)) { | |
221 builder.push(JSON_NUMBER_TO_STRING(val)); | |
222 } else { | |
223 var before = builder.length; | |
224 BasicJSONSerialize(i, val, stack, builder); | |
225 if (before == builder.length) builder[before - 1] = ",null"; | |
226 } | |
227 } | |
228 } else { | |
229 var before = builder.length; | |
230 BasicJSONSerialize(0, val, stack, builder); | |
231 if (before == builder.length) builder.push("null"); | |
232 for (var i = 1; i < len; i++) { | |
233 builder.push(","); | |
234 before = builder.length; | |
235 BasicJSONSerialize(i, value[i], stack, builder); | |
236 if (before == builder.length) builder[before - 1] = ",null"; | |
237 } | |
238 } | |
239 stack.pop(); | |
240 builder.push("]"); | |
241 } | |
242 | |
243 | |
244 function BasicSerializeObject(value, stack, builder) { | |
245 if (!%PushIfAbsent(stack, value)) { | |
246 throw MakeTypeError('circular_structure', $Array()); | |
247 } | |
248 builder.push("{"); | |
249 var first = true; | |
250 var keys = %ObjectKeys(value); | |
251 var len = keys.length; | |
252 for (var i = 0; i < len; i++) { | |
253 var p = keys[i]; | |
254 if (!first) { | |
255 builder.push(%QuoteJSONStringComma(p)); | |
256 } else { | |
257 builder.push(%QuoteJSONString(p)); | |
258 } | |
259 builder.push(":"); | |
260 var before = builder.length; | |
261 BasicJSONSerialize(p, value[p], stack, builder); | |
262 if (before == builder.length) { | |
263 builder.pop(); | |
264 builder.pop(); | |
265 } else { | |
266 first = false; | |
267 } | |
268 } | |
269 stack.pop(); | |
270 builder.push("}"); | |
271 } | |
272 | |
273 | |
274 function BasicJSONSerialize(key, value, stack, builder) { | |
275 if (IS_SPEC_OBJECT(value)) { | |
276 var toJSON = value.toJSON; | |
277 if (IS_SPEC_FUNCTION(toJSON)) { | |
278 value = %_CallFunction(value, ToString(key), toJSON); | |
279 } | |
280 } | |
281 if (IS_STRING(value)) { | |
282 builder.push(value !== "" ? %QuoteJSONString(value) : '""'); | |
283 } else if (IS_NUMBER(value)) { | |
284 builder.push(JSON_NUMBER_TO_STRING(value)); | |
285 } else if (IS_BOOLEAN(value)) { | |
286 builder.push(value ? "true" : "false"); | |
287 } else if (IS_NULL(value)) { | |
288 builder.push("null"); | |
289 } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) { | |
290 // Value is a non-callable object. | |
291 // Unwrap value if necessary | |
292 if (IS_NUMBER_WRAPPER(value)) { | |
293 value = ToNumber(value); | |
294 builder.push(JSON_NUMBER_TO_STRING(value)); | |
295 } else if (IS_STRING_WRAPPER(value)) { | |
296 builder.push(%QuoteJSONString(ToString(value))); | |
297 } else if (IS_BOOLEAN_WRAPPER(value)) { | |
298 builder.push(%_ValueOf(value) ? "true" : "false"); | |
299 } else if (IS_ARRAY(value)) { | |
300 BasicSerializeArray(value, stack, builder); | |
301 } else { | |
302 BasicSerializeObject(value, stack, builder); | |
303 } | |
304 } | |
305 } | |
306 | |
307 | |
308 function JSONStringify(value, replacer, space) { | 181 function JSONStringify(value, replacer, space) { |
309 if (%_ArgumentsLength() == 1) { | 182 if (%_ArgumentsLength() == 1) { |
310 var result = %BasicJSONStringify(value); | 183 return %BasicJSONStringify(value); |
311 if (result != 0) return result; | |
312 var builder = new InternalArray(); | |
313 BasicJSONSerialize('', value, new InternalArray(), builder); | |
314 if (builder.length == 0) return; | |
315 result = %_FastAsciiArrayJoin(builder, ""); | |
316 if (!IS_UNDEFINED(result)) return result; | |
317 return %StringBuilderConcat(builder, builder.length, ""); | |
318 } | 184 } |
319 if (IS_OBJECT(space)) { | 185 if (IS_OBJECT(space)) { |
320 // Unwrap 'space' if it is wrapped | 186 // Unwrap 'space' if it is wrapped |
321 if (IS_NUMBER_WRAPPER(space)) { | 187 if (IS_NUMBER_WRAPPER(space)) { |
322 space = ToNumber(space); | 188 space = ToNumber(space); |
323 } else if (IS_STRING_WRAPPER(space)) { | 189 } else if (IS_STRING_WRAPPER(space)) { |
324 space = ToString(space); | 190 space = ToString(space); |
325 } | 191 } |
326 } | 192 } |
327 var gap; | 193 var gap; |
328 if (IS_NUMBER(space)) { | 194 if (IS_NUMBER(space)) { |
329 space = MathMax(0, MathMin(ToInteger(space), 10)); | 195 space = MathMax(0, MathMin(ToInteger(space), 10)); |
330 gap = SubString(" ", 0, space); | 196 gap = SubString(" ", 0, space); |
331 } else if (IS_STRING(space)) { | 197 } else if (IS_STRING(space)) { |
332 if (space.length > 10) { | 198 if (space.length > 10) { |
333 gap = SubString(space, 0, 10); | 199 gap = SubString(space, 0, 10); |
334 } else { | 200 } else { |
335 gap = space; | 201 gap = space; |
336 } | 202 } |
337 } else { | 203 } else { |
338 gap = ""; | 204 gap = ""; |
339 } | 205 } |
340 return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); | 206 return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); |
341 } | 207 } |
342 | 208 |
| 209 |
343 function SetUpJSON() { | 210 function SetUpJSON() { |
344 %CheckIsBootstrapping(); | 211 %CheckIsBootstrapping(); |
345 InstallFunctions($JSON, DONT_ENUM, $Array( | 212 InstallFunctions($JSON, DONT_ENUM, $Array( |
346 "parse", JSONParse, | 213 "parse", JSONParse, |
347 "stringify", JSONStringify | 214 "stringify", JSONStringify |
348 )); | 215 )); |
349 } | 216 } |
350 | 217 |
351 SetUpJSON(); | 218 SetUpJSON(); |
OLD | NEW |