OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // Patch file for dart:convert library. | 5 // Patch file for dart:convert library. |
6 | 6 |
7 import 'dart:_js_helper' show argumentErrorValue, patch; | 7 import 'dart:_js_helper' show argumentErrorValue, patch; |
8 import 'dart:_foreign_helper' show JS; | 8 import 'dart:_foreign_helper' show JS; |
9 import 'dart:_interceptors' show JSExtendableArray; | 9 import 'dart:_interceptors' show JSExtendableArray; |
10 import 'dart:_internal' show MappedIterable, ListIterable; | 10 import 'dart:_internal' show MappedIterable, ListIterable; |
(...skipping 15 matching lines...) Expand all Loading... |
26 * | 26 * |
27 * Throws [FormatException] if the input is not valid JSON text. | 27 * Throws [FormatException] if the input is not valid JSON text. |
28 */ | 28 */ |
29 @patch | 29 @patch |
30 _parseJson(String source, reviver(key, value)) { | 30 _parseJson(String source, reviver(key, value)) { |
31 if (source is! String) throw argumentErrorValue(source); | 31 if (source is! String) throw argumentErrorValue(source); |
32 | 32 |
33 var parsed; | 33 var parsed; |
34 try { | 34 try { |
35 parsed = JS('=Object|JSExtendableArray|Null|bool|num|String', | 35 parsed = JS('=Object|JSExtendableArray|Null|bool|num|String', |
36 'JSON.parse(#)', | 36 'JSON.parse(#)', source); |
37 source); | |
38 } catch (e) { | 37 } catch (e) { |
39 throw new FormatException(JS('String', 'String(#)', e)); | 38 throw new FormatException(JS('String', 'String(#)', e)); |
40 } | 39 } |
41 | 40 |
42 if (reviver == null) { | 41 if (reviver == null) { |
43 return _convertJsonToDartLazy(parsed); | 42 return _convertJsonToDartLazy(parsed); |
44 } else { | 43 } else { |
45 return _convertJsonToDart(parsed, reviver); | 44 return _convertJsonToDart(parsed, reviver); |
46 } | 45 } |
47 } | 46 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 _JsonMap map = new _JsonMap(e); | 80 _JsonMap map = new _JsonMap(e); |
82 var processed = map._processed; | 81 var processed = map._processed; |
83 List<String> keys = map._computeKeys(); | 82 List<String> keys = map._computeKeys(); |
84 for (int i = 0; i < keys.length; i++) { | 83 for (int i = 0; i < keys.length; i++) { |
85 String key = keys[i]; | 84 String key = keys[i]; |
86 var revived = reviver(key, walk(JS('', '#[#]', e, key))); | 85 var revived = reviver(key, walk(JS('', '#[#]', e, key))); |
87 JS('', '#[#]=#', processed, key, revived); | 86 JS('', '#[#]=#', processed, key, revived); |
88 } | 87 } |
89 | 88 |
90 // Update the JSON map structure so future access is cheaper. | 89 // Update the JSON map structure so future access is cheaper. |
91 map._original = processed; // Don't keep two objects around. | 90 map._original = processed; // Don't keep two objects around. |
92 return map; | 91 return map; |
93 } | 92 } |
94 | 93 |
95 return reviver(null, walk(json)); | 94 return reviver(null, walk(json)); |
96 } | 95 } |
97 | 96 |
98 _convertJsonToDartLazy(object) { | 97 _convertJsonToDartLazy(object) { |
99 // JavaScript null and undefined are represented as null. | 98 // JavaScript null and undefined are represented as null. |
100 if (object == null) return null; | 99 if (object == null) return null; |
101 | 100 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 // We keep track of the map entries that we have already | 132 // We keep track of the map entries that we have already |
134 // processed by adding them to a separate JavaScript object. | 133 // processed by adding them to a separate JavaScript object. |
135 var _processed = _newJavaScriptObject(); | 134 var _processed = _newJavaScriptObject(); |
136 | 135 |
137 // If the data slot isn't null, it represents either the list | 136 // If the data slot isn't null, it represents either the list |
138 // of keys (for non-upgraded JSON maps) or the upgraded map. | 137 // of keys (for non-upgraded JSON maps) or the upgraded map. |
139 var _data = null; | 138 var _data = null; |
140 | 139 |
141 _JsonMap(this._original); | 140 _JsonMap(this._original); |
142 | 141 |
143 operator[](key) { | 142 operator [](key) { |
144 if (_isUpgraded) { | 143 if (_isUpgraded) { |
145 return _upgradedMap[key]; | 144 return _upgradedMap[key]; |
146 } else if (key is !String) { | 145 } else if (key is! String) { |
147 return null; | 146 return null; |
148 } else { | 147 } else { |
149 var result = _getProperty(_processed, key); | 148 var result = _getProperty(_processed, key); |
150 if (_isUnprocessed(result)) result = _process(key); | 149 if (_isUnprocessed(result)) result = _process(key); |
151 return result; | 150 return result; |
152 } | 151 } |
153 } | 152 } |
154 | 153 |
155 int get length => _isUpgraded | 154 int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length; |
156 ? _upgradedMap.length | |
157 : _computeKeys().length; | |
158 | 155 |
159 bool get isEmpty => length == 0; | 156 bool get isEmpty => length == 0; |
160 bool get isNotEmpty => length > 0; | 157 bool get isNotEmpty => length > 0; |
161 | 158 |
162 Iterable get keys { | 159 Iterable get keys { |
163 if (_isUpgraded) return _upgradedMap.keys; | 160 if (_isUpgraded) return _upgradedMap.keys; |
164 return new _JsonMapKeyIterable(this); | 161 return new _JsonMapKeyIterable(this); |
165 } | 162 } |
166 | 163 |
167 Iterable get values { | 164 Iterable get values { |
168 if (_isUpgraded) return _upgradedMap.values; | 165 if (_isUpgraded) return _upgradedMap.values; |
169 return new MappedIterable(_computeKeys(), (each) => this[each]); | 166 return new MappedIterable(_computeKeys(), (each) => this[each]); |
170 } | 167 } |
171 | 168 |
172 operator[]=(key, value) { | 169 operator []=(key, value) { |
173 if (_isUpgraded) { | 170 if (_isUpgraded) { |
174 _upgradedMap[key] = value; | 171 _upgradedMap[key] = value; |
175 } else if (containsKey(key)) { | 172 } else if (containsKey(key)) { |
176 var processed = _processed; | 173 var processed = _processed; |
177 _setProperty(processed, key, value); | 174 _setProperty(processed, key, value); |
178 var original = _original; | 175 var original = _original; |
179 if (!identical(original, processed)) { | 176 if (!identical(original, processed)) { |
180 _setProperty(original, key, null); // Reclaim memory. | 177 _setProperty(original, key, null); // Reclaim memory. |
181 } | 178 } |
182 } else { | 179 } else { |
183 _upgrade()[key] = value; | 180 _upgrade()[key] = value; |
184 } | 181 } |
185 } | 182 } |
186 | 183 |
187 void addAll(Map other) { | 184 void addAll(Map other) { |
188 other.forEach((key, value) { | 185 other.forEach((key, value) { |
189 this[key] = value; | 186 this[key] = value; |
190 }); | 187 }); |
191 } | 188 } |
192 | 189 |
193 bool containsValue(value) { | 190 bool containsValue(value) { |
194 if (_isUpgraded) return _upgradedMap.containsValue(value); | 191 if (_isUpgraded) return _upgradedMap.containsValue(value); |
195 List<String> keys = _computeKeys(); | 192 List<String> keys = _computeKeys(); |
196 for (int i = 0; i < keys.length; i++) { | 193 for (int i = 0; i < keys.length; i++) { |
197 String key = keys[i]; | 194 String key = keys[i]; |
198 if (this[key] == value) return true; | 195 if (this[key] == value) return true; |
199 } | 196 } |
200 return false; | 197 return false; |
201 } | 198 } |
202 | 199 |
203 bool containsKey(key) { | 200 bool containsKey(key) { |
204 if (_isUpgraded) return _upgradedMap.containsKey(key); | 201 if (_isUpgraded) return _upgradedMap.containsKey(key); |
205 if (key is !String) return false; | 202 if (key is! String) return false; |
206 return _hasProperty(_original, key); | 203 return _hasProperty(_original, key); |
207 } | 204 } |
208 | 205 |
209 putIfAbsent(key, ifAbsent()) { | 206 putIfAbsent(key, ifAbsent()) { |
210 if (containsKey(key)) return this[key]; | 207 if (containsKey(key)) return this[key]; |
211 var value = ifAbsent(); | 208 var value = ifAbsent(); |
212 this[key] = value; | 209 this[key] = value; |
213 return value; | 210 return value; |
214 } | 211 } |
215 | 212 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 // Check if invoking the callback function changed | 250 // Check if invoking the callback function changed |
254 // the key set. If so, throw an exception. | 251 // the key set. If so, throw an exception. |
255 if (!identical(keys, _data)) { | 252 if (!identical(keys, _data)) { |
256 throw new ConcurrentModificationError(this); | 253 throw new ConcurrentModificationError(this); |
257 } | 254 } |
258 } | 255 } |
259 } | 256 } |
260 | 257 |
261 String toString() => Maps.mapToString(this); | 258 String toString() => Maps.mapToString(this); |
262 | 259 |
263 | |
264 // ------------------------------------------ | 260 // ------------------------------------------ |
265 // Private helper methods. | 261 // Private helper methods. |
266 // ------------------------------------------ | 262 // ------------------------------------------ |
267 | 263 |
268 bool get _isUpgraded => _processed == null; | 264 bool get _isUpgraded => _processed == null; |
269 | 265 |
270 Map get _upgradedMap { | 266 Map get _upgradedMap { |
271 assert(_isUpgraded); | 267 assert(_isUpgraded); |
272 // 'cast' the union type to LinkedHashMap. It would be even better if we | 268 // 'cast' the union type to LinkedHashMap. It would be even better if we |
273 // could 'cast' to the implementation type, since LinkedHashMap includes | 269 // could 'cast' to the implementation type, since LinkedHashMap includes |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 assert(_isUpgraded); | 308 assert(_isUpgraded); |
313 return result; | 309 return result; |
314 } | 310 } |
315 | 311 |
316 _process(String key) { | 312 _process(String key) { |
317 if (!_hasProperty(_original, key)) return null; | 313 if (!_hasProperty(_original, key)) return null; |
318 var result = _convertJsonToDartLazy(_getProperty(_original, key)); | 314 var result = _convertJsonToDartLazy(_getProperty(_original, key)); |
319 return _setProperty(_processed, key, result); | 315 return _setProperty(_processed, key, result); |
320 } | 316 } |
321 | 317 |
322 | |
323 // ------------------------------------------ | 318 // ------------------------------------------ |
324 // Private JavaScript helper methods. | 319 // Private JavaScript helper methods. |
325 // ------------------------------------------ | 320 // ------------------------------------------ |
326 | 321 |
327 static bool _hasProperty(object, String key) | 322 static bool _hasProperty(object, String key) => |
328 => JS('bool', 'Object.prototype.hasOwnProperty.call(#,#)', object, key); | 323 JS('bool', 'Object.prototype.hasOwnProperty.call(#,#)', object, key); |
329 static _getProperty(object, String key) | 324 static _getProperty(object, String key) => JS('', '#[#]', object, key); |
330 => JS('', '#[#]', object, key); | 325 static _setProperty(object, String key, value) => |
331 static _setProperty(object, String key, value) | 326 JS('', '#[#]=#', object, key, value); |
332 => JS('', '#[#]=#', object, key, value); | 327 static List _getPropertyNames(object) => |
333 static List _getPropertyNames(object) | 328 JS('JSExtendableArray', 'Object.keys(#)', object); |
334 => JS('JSExtendableArray', 'Object.keys(#)', object); | 329 static bool _isUnprocessed(object) => |
335 static bool _isUnprocessed(object) | 330 JS('bool', 'typeof(#)=="undefined"', object); |
336 => JS('bool', 'typeof(#)=="undefined"', object); | 331 static _newJavaScriptObject() => JS('=Object', 'Object.create(null)'); |
337 static _newJavaScriptObject() | |
338 => JS('=Object', 'Object.create(null)'); | |
339 } | 332 } |
340 | 333 |
341 class _JsonMapKeyIterable extends ListIterable { | 334 class _JsonMapKeyIterable extends ListIterable { |
342 final _JsonMap _parent; | 335 final _JsonMap _parent; |
343 | 336 |
344 _JsonMapKeyIterable(this._parent); | 337 _JsonMapKeyIterable(this._parent); |
345 | 338 |
346 int get length => _parent.length; | 339 int get length => _parent.length; |
347 | 340 |
348 String elementAt(int index) { | 341 String elementAt(int index) { |
349 return _parent._isUpgraded ? _parent.keys.elementAt(index) | 342 return _parent._isUpgraded |
350 : _parent._computeKeys()[index]; | 343 ? _parent.keys.elementAt(index) |
| 344 : _parent._computeKeys()[index]; |
351 } | 345 } |
352 | 346 |
353 /// Although [ListIterable] defines its own iterator, we return the iterator | 347 /// Although [ListIterable] defines its own iterator, we return the iterator |
354 /// of the underlying list [_keys] in order to propagate | 348 /// of the underlying list [_keys] in order to propagate |
355 /// [ConcurrentModificationError]s. | 349 /// [ConcurrentModificationError]s. |
356 Iterator get iterator { | 350 Iterator get iterator { |
357 return _parent._isUpgraded ? _parent.keys.iterator | 351 return _parent._isUpgraded |
358 : _parent._computeKeys().iterator; | 352 ? _parent.keys.iterator |
| 353 : _parent._computeKeys().iterator; |
359 } | 354 } |
360 | 355 |
361 /// Delegate to [parent.containsKey] to ensure the performance expected | 356 /// Delegate to [parent.containsKey] to ensure the performance expected |
362 /// from [Map.keys.containsKey]. | 357 /// from [Map.keys.containsKey]. |
363 bool contains(Object key) => _parent.containsKey(key); | 358 bool contains(Object key) => _parent.containsKey(key); |
364 } | 359 } |
365 | 360 |
366 @patch class JsonDecoder { | 361 @patch |
| 362 class JsonDecoder { |
367 @patch | 363 @patch |
368 StringConversionSink startChunkedConversion(Sink<Object> sink) { | 364 StringConversionSink startChunkedConversion(Sink<Object> sink) { |
369 return new _JsonDecoderSink(_reviver, sink); | 365 return new _JsonDecoderSink(_reviver, sink); |
370 } | 366 } |
371 } | 367 } |
372 | 368 |
373 /** | 369 /** |
374 * Implements the chunked conversion from a JSON string to its corresponding | 370 * Implements the chunked conversion from a JSON string to its corresponding |
375 * object. | 371 * object. |
376 * | 372 * |
377 * The sink only creates one object, but its input can be chunked. | 373 * The sink only creates one object, but its input can be chunked. |
378 */ | 374 */ |
379 // TODO(floitsch): don't accumulate everything before starting to decode. | 375 // TODO(floitsch): don't accumulate everything before starting to decode. |
380 class _JsonDecoderSink extends _StringSinkConversionSink { | 376 class _JsonDecoderSink extends _StringSinkConversionSink { |
381 final _Reviver _reviver; | 377 final _Reviver _reviver; |
382 final Sink<Object> _sink; | 378 final Sink<Object> _sink; |
383 | 379 |
384 _JsonDecoderSink(this._reviver, this._sink) | 380 _JsonDecoderSink(this._reviver, this._sink) : super(new StringBuffer()); |
385 : super(new StringBuffer()); | |
386 | 381 |
387 void close() { | 382 void close() { |
388 super.close(); | 383 super.close(); |
389 StringBuffer buffer = _stringSink; | 384 StringBuffer buffer = _stringSink; |
390 String accumulated = buffer.toString(); | 385 String accumulated = buffer.toString(); |
391 buffer.clear(); | 386 buffer.clear(); |
392 Object decoded = _parseJson(accumulated, _reviver); | 387 Object decoded = _parseJson(accumulated, _reviver); |
393 _sink.add(decoded); | 388 _sink.add(decoded); |
394 _sink.close(); | 389 _sink.close(); |
395 } | 390 } |
396 } | 391 } |
397 | 392 |
398 @patch class Utf8Decoder { | 393 @patch |
| 394 class Utf8Decoder { |
399 @patch | 395 @patch |
400 Converter<List<int>, dynamic/*=T*/> fuse/*<T>*/( | 396 Converter<List<int>, dynamic/*=T*/ > fuse/*<T>*/( |
401 Converter<String, dynamic/*=T*/> next) { | 397 Converter<String, dynamic/*=T*/ > next) { |
402 return super.fuse/*<T>*/(next); | 398 return super.fuse/*<T>*/(next); |
403 } | 399 } |
404 | 400 |
405 // Currently not intercepting UTF8 decoding. | 401 // Currently not intercepting UTF8 decoding. |
406 @patch | 402 @patch |
407 static String _convertIntercepted(bool allowMalformed, List<int> codeUnits, | 403 static String _convertIntercepted( |
408 int start, int end) { | 404 bool allowMalformed, List<int> codeUnits, int start, int end) { |
409 return null; // This call was not intercepted. | 405 return null; // This call was not intercepted. |
410 } | 406 } |
411 } | 407 } |
OLD | NEW |