| 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 |