| OLD | NEW |
| (Empty) |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 (function(global, utils) { | |
| 6 | |
| 7 "use strict"; | |
| 8 | |
| 9 %CheckIsBootstrapping(); | |
| 10 | |
| 11 // ------------------------------------------------------------------- | |
| 12 // Imports | |
| 13 | |
| 14 var GlobalJSON = global.JSON; | |
| 15 var InternalArray = utils.InternalArray; | |
| 16 var MathMax; | |
| 17 var MathMin; | |
| 18 var ObjectHasOwnProperty; | |
| 19 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | |
| 20 | |
| 21 utils.Import(function(from) { | |
| 22 MathMax = from.MathMax; | |
| 23 MathMin = from.MathMin; | |
| 24 ObjectHasOwnProperty = from.ObjectHasOwnProperty; | |
| 25 }); | |
| 26 | |
| 27 // ------------------------------------------------------------------- | |
| 28 | |
| 29 function Revive(holder, name, reviver) { | |
| 30 var val = holder[name]; | |
| 31 if (IS_OBJECT(val)) { | |
| 32 if (IS_ARRAY(val)) { | |
| 33 var length = val.length; | |
| 34 for (var i = 0; i < length; i++) { | |
| 35 var newElement = Revive(val, %_NumberToString(i), reviver); | |
| 36 val[i] = newElement; | |
| 37 } | |
| 38 } else { | |
| 39 for (var p in val) { | |
| 40 if (HAS_OWN_PROPERTY(val, p)) { | |
| 41 var newElement = Revive(val, p, reviver); | |
| 42 if (IS_UNDEFINED(newElement)) { | |
| 43 delete val[p]; | |
| 44 } else { | |
| 45 val[p] = newElement; | |
| 46 } | |
| 47 } | |
| 48 } | |
| 49 } | |
| 50 } | |
| 51 return %_Call(reviver, holder, name, val); | |
| 52 } | |
| 53 | |
| 54 | |
| 55 function JSONParse(text, reviver) { | |
| 56 var unfiltered = %ParseJson(text); | |
| 57 if (IS_CALLABLE(reviver)) { | |
| 58 return Revive({'': unfiltered}, '', reviver); | |
| 59 } else { | |
| 60 return unfiltered; | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 | |
| 65 function SerializeArray(value, replacer, stack, indent, gap) { | |
| 66 if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure); | |
| 67 var stepback = indent; | |
| 68 indent += gap; | |
| 69 var partial = new InternalArray(); | |
| 70 var len = value.length; | |
| 71 for (var i = 0; i < len; i++) { | |
| 72 var strP = JSONSerialize(%_NumberToString(i), value, replacer, stack, | |
| 73 indent, gap); | |
| 74 if (IS_UNDEFINED(strP)) { | |
| 75 strP = "null"; | |
| 76 } | |
| 77 partial.push(strP); | |
| 78 } | |
| 79 var final; | |
| 80 if (gap == "") { | |
| 81 final = "[" + partial.join(",") + "]"; | |
| 82 } else if (partial.length > 0) { | |
| 83 var separator = ",\n" + indent; | |
| 84 final = "[\n" + indent + partial.join(separator) + "\n" + | |
| 85 stepback + "]"; | |
| 86 } else { | |
| 87 final = "[]"; | |
| 88 } | |
| 89 stack.pop(); | |
| 90 return final; | |
| 91 } | |
| 92 | |
| 93 | |
| 94 function SerializeObject(value, replacer, stack, indent, gap) { | |
| 95 if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure); | |
| 96 var stepback = indent; | |
| 97 indent += gap; | |
| 98 var partial = new InternalArray(); | |
| 99 if (IS_ARRAY(replacer)) { | |
| 100 var length = replacer.length; | |
| 101 for (var i = 0; i < length; i++) { | |
| 102 if (HAS_OWN_PROPERTY(replacer, i)) { | |
| 103 var p = replacer[i]; | |
| 104 var strP = JSONSerialize(p, value, replacer, stack, indent, gap); | |
| 105 if (!IS_UNDEFINED(strP)) { | |
| 106 var member = %QuoteJSONString(p) + ":"; | |
| 107 if (gap != "") member += " "; | |
| 108 member += strP; | |
| 109 partial.push(member); | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 } else { | |
| 114 for (var p in value) { | |
| 115 if (HAS_OWN_PROPERTY(value, p)) { | |
| 116 var strP = JSONSerialize(p, value, replacer, stack, indent, gap); | |
| 117 if (!IS_UNDEFINED(strP)) { | |
| 118 var member = %QuoteJSONString(p) + ":"; | |
| 119 if (gap != "") member += " "; | |
| 120 member += strP; | |
| 121 partial.push(member); | |
| 122 } | |
| 123 } | |
| 124 } | |
| 125 } | |
| 126 var final; | |
| 127 if (gap == "") { | |
| 128 final = "{" + partial.join(",") + "}"; | |
| 129 } else if (partial.length > 0) { | |
| 130 var separator = ",\n" + indent; | |
| 131 final = "{\n" + indent + partial.join(separator) + "\n" + | |
| 132 stepback + "}"; | |
| 133 } else { | |
| 134 final = "{}"; | |
| 135 } | |
| 136 stack.pop(); | |
| 137 return final; | |
| 138 } | |
| 139 | |
| 140 | |
| 141 function JSONSerialize(key, holder, replacer, stack, indent, gap) { | |
| 142 var value = holder[key]; | |
| 143 if (IS_SPEC_OBJECT(value)) { | |
| 144 var toJSON = value.toJSON; | |
| 145 if (IS_CALLABLE(toJSON)) { | |
| 146 value = %_Call(toJSON, value, key); | |
| 147 } | |
| 148 } | |
| 149 if (IS_CALLABLE(replacer)) { | |
| 150 value = %_Call(replacer, holder, key, value); | |
| 151 } | |
| 152 if (IS_STRING(value)) { | |
| 153 return %QuoteJSONString(value); | |
| 154 } else if (IS_NUMBER(value)) { | |
| 155 return JSON_NUMBER_TO_STRING(value); | |
| 156 } else if (IS_BOOLEAN(value)) { | |
| 157 return value ? "true" : "false"; | |
| 158 } else if (IS_NULL(value)) { | |
| 159 return "null"; | |
| 160 } else if (IS_SPEC_OBJECT(value) && !IS_CALLABLE(value)) { | |
| 161 // Non-callable object. If it's a primitive wrapper, it must be unwrapped. | |
| 162 if (IS_ARRAY(value)) { | |
| 163 return SerializeArray(value, replacer, stack, indent, gap); | |
| 164 } else if (IS_NUMBER_WRAPPER(value)) { | |
| 165 value = TO_NUMBER(value); | |
| 166 return JSON_NUMBER_TO_STRING(value); | |
| 167 } else if (IS_STRING_WRAPPER(value)) { | |
| 168 return %QuoteJSONString(TO_STRING(value)); | |
| 169 } else if (IS_BOOLEAN_WRAPPER(value)) { | |
| 170 return %_ValueOf(value) ? "true" : "false"; | |
| 171 } else { | |
| 172 return SerializeObject(value, replacer, stack, indent, gap); | |
| 173 } | |
| 174 } | |
| 175 // Undefined or a callable object. | |
| 176 return UNDEFINED; | |
| 177 } | |
| 178 | |
| 179 | |
| 180 function JSONStringify(value, replacer, space) { | |
| 181 if (%_ArgumentsLength() == 1) { | |
| 182 return %BasicJSONStringify(value); | |
| 183 } | |
| 184 if (IS_ARRAY(replacer)) { | |
| 185 // Deduplicate replacer array items. | |
| 186 var property_list = new InternalArray(); | |
| 187 var seen_properties = { __proto__: null }; | |
| 188 var length = replacer.length; | |
| 189 for (var i = 0; i < length; i++) { | |
| 190 var v = replacer[i]; | |
| 191 var item; | |
| 192 if (IS_STRING(v)) { | |
| 193 item = v; | |
| 194 } else if (IS_NUMBER(v)) { | |
| 195 item = %_NumberToString(v); | |
| 196 } else if (IS_STRING_WRAPPER(v) || IS_NUMBER_WRAPPER(v)) { | |
| 197 item = TO_STRING(v); | |
| 198 } else { | |
| 199 continue; | |
| 200 } | |
| 201 if (!seen_properties[item]) { | |
| 202 property_list.push(item); | |
| 203 seen_properties[item] = true; | |
| 204 } | |
| 205 } | |
| 206 replacer = property_list; | |
| 207 } | |
| 208 if (IS_OBJECT(space)) { | |
| 209 // Unwrap 'space' if it is wrapped | |
| 210 if (IS_NUMBER_WRAPPER(space)) { | |
| 211 space = TO_NUMBER(space); | |
| 212 } else if (IS_STRING_WRAPPER(space)) { | |
| 213 space = TO_STRING(space); | |
| 214 } | |
| 215 } | |
| 216 var gap; | |
| 217 if (IS_NUMBER(space)) { | |
| 218 space = MathMax(0, MathMin(TO_INTEGER(space), 10)); | |
| 219 gap = %_SubString(" ", 0, space); | |
| 220 } else if (IS_STRING(space)) { | |
| 221 if (space.length > 10) { | |
| 222 gap = %_SubString(space, 0, 10); | |
| 223 } else { | |
| 224 gap = space; | |
| 225 } | |
| 226 } else { | |
| 227 gap = ""; | |
| 228 } | |
| 229 return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap); | |
| 230 } | |
| 231 | |
| 232 // ------------------------------------------------------------------- | |
| 233 | |
| 234 %AddNamedProperty(GlobalJSON, toStringTagSymbol, "JSON", READ_ONLY | DONT_ENUM); | |
| 235 | |
| 236 // Set up non-enumerable properties of the JSON object. | |
| 237 utils.InstallFunctions(GlobalJSON, DONT_ENUM, [ | |
| 238 "parse", JSONParse, | |
| 239 "stringify", JSONStringify | |
| 240 ]); | |
| 241 | |
| 242 // ------------------------------------------------------------------- | |
| 243 // JSON Builtins | |
| 244 | |
| 245 function JsonSerializeAdapter(key, object) { | |
| 246 var holder = {}; | |
| 247 holder[key] = object; | |
| 248 // No need to pass the actual holder since there is no replacer function. | |
| 249 return JSONSerialize(key, holder, UNDEFINED, new InternalArray(), "", ""); | |
| 250 } | |
| 251 | |
| 252 %InstallToContext(["json_serialize_adapter", JsonSerializeAdapter]); | |
| 253 | |
| 254 }) | |
| OLD | NEW |