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