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; | |
26 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | 18 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
27 | 19 |
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 | |
39 // ------------------------------------------------------------------- | 20 // ------------------------------------------------------------------- |
40 | 21 |
41 function CreateDataProperty(o, p, v) { | 22 function CreateDataProperty(o, p, v) { |
42 var desc = {value: v, enumerable: true, writable: true, configurable: true}; | 23 var desc = {value: v, enumerable: true, writable: true, configurable: true}; |
43 return %reflect_define_property(o, p, desc); | 24 return %reflect_define_property(o, p, desc); |
44 } | 25 } |
45 | 26 |
46 | 27 |
47 function InternalizeJSONProperty(holder, name, reviver) { | 28 function InternalizeJSONProperty(holder, name, reviver) { |
48 var val = holder[name]; | 29 var val = holder[name]; |
(...skipping 28 matching lines...) Expand all Loading... |
77 | 58 |
78 function JSONParse(text, reviver) { | 59 function JSONParse(text, reviver) { |
79 var unfiltered = %ParseJson(text); | 60 var unfiltered = %ParseJson(text); |
80 if (IS_CALLABLE(reviver)) { | 61 if (IS_CALLABLE(reviver)) { |
81 return InternalizeJSONProperty({'': unfiltered}, '', reviver); | 62 return InternalizeJSONProperty({'': unfiltered}, '', reviver); |
82 } else { | 63 } else { |
83 return unfiltered; | 64 return unfiltered; |
84 } | 65 } |
85 } | 66 } |
86 | 67 |
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 | |
218 // ------------------------------------------------------------------- | 68 // ------------------------------------------------------------------- |
219 | 69 |
220 %AddNamedProperty(GlobalJSON, toStringTagSymbol, "JSON", READ_ONLY | DONT_ENUM); | 70 %AddNamedProperty(GlobalJSON, toStringTagSymbol, "JSON", READ_ONLY | DONT_ENUM); |
221 | 71 |
222 // Set up non-enumerable properties of the JSON object. | 72 // Set up non-enumerable properties of the JSON object. |
223 utils.InstallFunctions(GlobalJSON, DONT_ENUM, [ | 73 utils.InstallFunctions(GlobalJSON, DONT_ENUM, [ |
224 "parse", JSONParse, | 74 "parse", JSONParse, |
225 "stringify", JSONStringify | |
226 ]); | 75 ]); |
227 | 76 |
228 // ------------------------------------------------------------------- | 77 // ------------------------------------------------------------------- |
229 // Date.toJSON | 78 // Date.toJSON |
230 | 79 |
231 // 20.3.4.37 Date.prototype.toJSON ( key ) | 80 // 20.3.4.37 Date.prototype.toJSON ( key ) |
232 function DateToJSON(key) { | 81 function DateToJSON(key) { |
233 var o = TO_OBJECT(this); | 82 var o = TO_OBJECT(this); |
234 var tv = TO_PRIMITIVE_NUMBER(o); | 83 var tv = TO_PRIMITIVE_NUMBER(o); |
235 if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) { | 84 if (IS_NUMBER(tv) && !NUMBER_IS_FINITE(tv)) { |
236 return null; | 85 return null; |
237 } | 86 } |
238 return o.toISOString(); | 87 return o.toISOString(); |
239 } | 88 } |
240 | 89 |
241 // Set up non-enumerable functions of the Date prototype object. | 90 // Set up non-enumerable functions of the Date prototype object. |
242 utils.InstallFunctions(GlobalDate.prototype, DONT_ENUM, [ | 91 utils.InstallFunctions(GlobalDate.prototype, DONT_ENUM, [ |
243 "toJSON", DateToJSON | 92 "toJSON", DateToJSON |
244 ]); | 93 ]); |
245 | 94 |
246 }) | 95 }) |
OLD | NEW |