13100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Copyright 2009 the V8 project authors. All rights reserved. 23100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// Redistribution and use in source and binary forms, with or without 33100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// modification, are permitted provided that the following conditions are 43100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// met: 53100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// 63100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// * Redistributions of source code must retain the above copyright 73100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// notice, this list of conditions and the following disclaimer. 83100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// * Redistributions in binary form must reproduce the above 93100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// copyright notice, this list of conditions and the following 103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// disclaimer in the documentation and/or other materials provided 113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// with the distribution. 123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// * Neither the name of Google Inc. nor the names of its 133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// contributors may be used to endorse or promote products derived 143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// from this software without specific prior written permission. 153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// 163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescuvar $JSON = global.JSON; 293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescufunction Revive(holder, name, reviver) { 313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var val = holder[name]; 323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_OBJECT(val)) { 333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_ARRAY(val)) { 343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var length = val.length; 353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu for (var i = 0; i < length; i++) { 363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var newElement = Revive(val, $String(i), reviver); 373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu val[i] = newElement; 383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu for (var p in val) { 411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (%_CallFunction(val, p, ObjectHasOwnProperty)) { 423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var newElement = Revive(val, p, reviver); 433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_UNDEFINED(newElement)) { 443100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu delete val[p]; 453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu val[p] = newElement; 473100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 513100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 52e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch return %_CallFunction(holder, name, val, reviver); 533100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 543100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 553100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescufunction JSONParse(text, reviver) { 569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block var unfiltered = %ParseJson(TO_STRING_INLINE(text)); 573100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_FUNCTION(reviver)) { 583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu return Revive({'': unfiltered}, '', reviver); 593100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu return unfiltered; 613100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 623100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 633100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 643100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescufunction SerializeArray(value, replacer, stack, indent, gap) { 65b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (!%PushIfAbsent(stack, value)) { 66e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch throw MakeTypeError('circular_structure', $Array()); 673100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var stepback = indent; 693100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu indent += gap; 70e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch var partial = new InternalArray(); 713100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var len = value.length; 723100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu for (var i = 0; i < len; i++) { 733100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var strP = JSONSerialize($String(i), value, replacer, stack, 743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu indent, gap); 753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_UNDEFINED(strP)) { 763100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu strP = "null"; 773100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 783100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu partial.push(strP); 793100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 803100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var final; 813100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (gap == "") { 823100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu final = "[" + partial.join(",") + "]"; 833100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else if (partial.length > 0) { 843100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var separator = ",\n" + indent; 853100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu final = "[\n" + indent + partial.join(separator) + "\n" + 863100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu stepback + "]"; 873100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 883100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu final = "[]"; 893100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 903100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu stack.pop(); 913100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu return final; 923100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 933100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 943100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescufunction SerializeObject(value, replacer, stack, indent, gap) { 95b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (!%PushIfAbsent(stack, value)) { 96e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch throw MakeTypeError('circular_structure', $Array()); 973100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 983100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var stepback = indent; 993100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu indent += gap; 100e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch var partial = new InternalArray(); 1013100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_ARRAY(replacer)) { 1023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var length = replacer.length; 1033100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu for (var i = 0; i < length; i++) { 1041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (%_CallFunction(replacer, i, ObjectHasOwnProperty)) { 1053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var p = replacer[i]; 1063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var strP = JSONSerialize(p, value, replacer, stack, indent, gap); 1073100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (!IS_UNDEFINED(strP)) { 108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch var member = %QuoteJSONString(p) + ":"; 1093100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (gap != "") member += " "; 1103100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu member += strP; 1113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu partial.push(member); 1123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 1163100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu for (var p in value) { 1171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block if (%_CallFunction(value, p, ObjectHasOwnProperty)) { 1183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var strP = JSONSerialize(p, value, replacer, stack, indent, gap); 1193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (!IS_UNDEFINED(strP)) { 120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch var member = %QuoteJSONString(p) + ":"; 1213100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (gap != "") member += " "; 1223100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu member += strP; 1233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu partial.push(member); 1243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1253100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var final; 1293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (gap == "") { 1303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu final = "{" + partial.join(",") + "}"; 1313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else if (partial.length > 0) { 1323100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var separator = ",\n" + indent; 1333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu final = "{\n" + indent + partial.join(separator) + "\n" + 1343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu stepback + "}"; 1353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 1363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu final = "{}"; 1373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu stack.pop(); 1393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu return final; 1403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 1413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 1423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescufunction JSONSerialize(key, holder, replacer, stack, indent, gap) { 1433100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var value = holder[key]; 144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (IS_SPEC_OBJECT(value)) { 1453100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var toJSON = value.toJSON; 1463100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_FUNCTION(toJSON)) { 147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch value = %_CallFunction(value, key, toJSON); 1483100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1493100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1503100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_FUNCTION(replacer)) { 151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch value = %_CallFunction(holder, key, value, replacer); 1523100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (IS_STRING(value)) { 154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return %QuoteJSONString(value); 155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_NUMBER(value)) { 1569fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return NUMBER_IS_FINITE(value) ? $String(value) : "null"; 157b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_BOOLEAN(value)) { 158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return value ? "true" : "false"; 159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_NULL(value)) { 160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return "null"; 161b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) { 162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Non-callable object. If it's a primitive wrapper, it must be unwrapped. 163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (IS_ARRAY(value)) { 164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return SerializeArray(value, replacer, stack, indent, gap); 165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_NUMBER_WRAPPER(value)) { 166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch value = ToNumber(value); 1679fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block return NUMBER_IS_FINITE(value) ? ToString(value) : "null"; 1683100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else if (IS_STRING_WRAPPER(value)) { 169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return %QuoteJSONString(ToString(value)); 1703100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else if (IS_BOOLEAN_WRAPPER(value)) { 171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return %_ValueOf(value) ? "true" : "false"; 172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return SerializeObject(value, replacer, stack, indent, gap); 1743100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 1753100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Undefined or a callable object. 177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return void 0; 178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfunction BasicSerializeArray(value, stack, builder) { 182b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch var len = value.length; 183b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (len == 0) { 184b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push("[]"); 185b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch return; 186b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 187b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (!%PushIfAbsent(stack, value)) { 188e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch throw MakeTypeError('circular_structure', $Array()); 189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push("["); 191b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch var val = value[0]; 192b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (IS_STRING(val)) { 193b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // First entry is a string. Remaining entries are likely to be strings too. 194b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(%QuoteJSONString(val)); 195b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch for (var i = 1; i < len; i++) { 196b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch val = value[i]; 197b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (IS_STRING(val)) { 198b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(%QuoteJSONStringComma(val)); 199b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } else { 200b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(","); 201b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch var before = builder.length; 202b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch BasicJSONSerialize(i, value[i], stack, builder); 203b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (before == builder.length) builder[before - 1] = ",null"; 204b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 205b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 206b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } else if (IS_NUMBER(val)) { 207b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch // First entry is a number. Remaining entries are likely to be numbers too. 208b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(NUMBER_IS_FINITE(val) ? %_NumberToString(val) : "null"); 209b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch for (var i = 1; i < len; i++) { 210b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(","); 211b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch val = value[i]; 212b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (IS_NUMBER(val)) { 213b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(NUMBER_IS_FINITE(val) 214b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch ? %_NumberToString(val) 215b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch : "null"); 216b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } else { 217b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch var before = builder.length; 218b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch BasicJSONSerialize(i, value[i], stack, builder); 219b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (before == builder.length) builder[before - 1] = ",null"; 220b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 221b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 222b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } else { 223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch var before = builder.length; 224b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch BasicJSONSerialize(0, val, stack, builder); 225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (before == builder.length) builder.push("null"); 226b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch for (var i = 1; i < len; i++) { 227b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(","); 228b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch before = builder.length; 229b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch val = value[i]; 230b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch BasicJSONSerialize(i, val, stack, builder); 231b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (before == builder.length) builder[before - 1] = ",null"; 232b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch stack.pop(); 235b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push("]"); 236b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 238b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 239b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfunction BasicSerializeObject(value, stack, builder) { 240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (!%PushIfAbsent(stack, value)) { 241e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch throw MakeTypeError('circular_structure', $Array()); 242b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push("{"); 244b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch var first = true; 245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch for (var p in value) { 246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (%HasLocalProperty(value, p)) { 247b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch if (!first) { 248b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(%QuoteJSONStringComma(p)); 249b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } else { 250b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push(%QuoteJSONString(p)); 251b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch } 252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push(":"); 253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch var before = builder.length; 254b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch BasicJSONSerialize(p, value[p], stack, builder); 255b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (before == builder.length) { 256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.pop(); 257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.pop(); 2583100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 259b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch first = false; 2603100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 262b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 263b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch stack.pop(); 264b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch builder.push("}"); 2653100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 2663100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 267b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 268b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdochfunction BasicJSONSerialize(key, value, stack, builder) { 269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (IS_SPEC_OBJECT(value)) { 270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch var toJSON = value.toJSON; 271b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (IS_FUNCTION(toJSON)) { 272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch value = %_CallFunction(value, ToString(key), toJSON); 273b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 274b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 275b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (IS_STRING(value)) { 276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push(%QuoteJSONString(value)); 277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_NUMBER(value)) { 2789fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block builder.push(NUMBER_IS_FINITE(value) ? %_NumberToString(value) : "null"); 279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_BOOLEAN(value)) { 280b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push(value ? "true" : "false"); 281b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_NULL(value)) { 282b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push("null"); 283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) { 284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Value is a non-callable object. 285b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // Unwrap value if necessary 286b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (IS_NUMBER_WRAPPER(value)) { 287b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch value = ToNumber(value); 2889fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block builder.push(NUMBER_IS_FINITE(value) ? %_NumberToString(value) : "null"); 289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_STRING_WRAPPER(value)) { 290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push(%QuoteJSONString(ToString(value))); 291b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_BOOLEAN_WRAPPER(value)) { 292b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch builder.push(%_ValueOf(value) ? "true" : "false"); 293b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else if (IS_ARRAY(value)) { 294b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch BasicSerializeArray(value, stack, builder); 295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } else { 296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch BasicSerializeObject(value, stack, builder); 297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch} 300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 3023100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescufunction JSONStringify(value, replacer, space) { 303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (%_ArgumentsLength() == 1) { 304e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch var builder = new InternalArray(); 305e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch BasicJSONSerialize('', value, new InternalArray(), builder); 306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (builder.length == 0) return; 307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch var result = %_FastAsciiArrayJoin(builder, ""); 308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch if (!IS_UNDEFINED(result)) return result; 309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch return %StringBuilderConcat(builder, builder.length, ""); 310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch } 3113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_OBJECT(space)) { 3123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu // Unwrap 'space' if it is wrapped 3133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_NUMBER_WRAPPER(space)) { 314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch space = ToNumber(space); 3153100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else if (IS_STRING_WRAPPER(space)) { 316b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch space = ToString(space); 3173100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 3183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 3193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu var gap; 3203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (IS_NUMBER(space)) { 321b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch space = MathMax(0, MathMin(ToInteger(space), 10)); 322b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch gap = SubString(" ", 0, space); 3233100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else if (IS_STRING(space)) { 3243100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu if (space.length > 10) { 325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch gap = SubString(space, 0, 10); 3263100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 3273100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu gap = space; 3283100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 3293100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } else { 3303100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu gap = ""; 3313100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu } 332e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); 3333100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 3343100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 3353100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescufunction SetupJSON() { 3363100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu InstallFunctions($JSON, DONT_ENUM, $Array( 3373100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu "parse", JSONParse, 3383100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu "stringify", JSONStringify 3393100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu )); 3403100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 3413100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 3423100271588b61cbc1dc472a3f2f105d2eed8497fAndrei PopescuSetupJSON(); 343