| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library _interceptors; | 5 library _interceptors; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 part 'js_array.dart'; |
| 9 part 'js_string.dart'; | 10 part 'js_string.dart'; |
| 10 | 11 |
| 11 /** | 12 /** |
| 12 * The interceptor class for all non-primitive objects. All its | 13 * The interceptor class for all non-primitive objects. All its |
| 13 * members are synthethized by the compiler's emitter. | 14 * members are synthethized by the compiler's emitter. |
| 14 */ | 15 */ |
| 15 class ObjectInterceptor { | 16 class ObjectInterceptor { |
| 16 const ObjectInterceptor(); | 17 const ObjectInterceptor(); |
| 17 } | 18 } |
| 18 | 19 |
| 19 /** | 20 /** |
| 20 * Get the interceptor for [object]. Called by the compiler when it needs | 21 * Get the interceptor for [object]. Called by the compiler when it needs |
| 21 * to emit a call to an intercepted method, that is a method that is | 22 * to emit a call to an intercepted method, that is a method that is |
| 22 * defined in an interceptor class. | 23 * defined in an interceptor class. |
| 23 */ | 24 */ |
| 24 getInterceptor(object) { | 25 getInterceptor(object) { |
| 25 if (object is String) return const JSString(); | 26 if (object is String) return const JSString(); |
| 27 if (isJsArray(object)) return const JSArray(); |
| 26 return const ObjectInterceptor(); | 28 return const ObjectInterceptor(); |
| 27 } | 29 } |
| 28 | 30 |
| 29 add$1(var receiver, var value) { | |
| 30 if (isJsArray(receiver)) { | |
| 31 checkGrowable(receiver, 'add'); | |
| 32 JS('void', r'#.push(#)', receiver, value); | |
| 33 return; | |
| 34 } | |
| 35 return UNINTERCEPTED(receiver.add(value)); | |
| 36 } | |
| 37 | |
| 38 removeAt$1(var receiver, int index) { | |
| 39 if (isJsArray(receiver)) { | |
| 40 if (index is !int) throw new ArgumentError(index); | |
| 41 if (index < 0 || index >= receiver.length) { | |
| 42 throw new RangeError.value(index); | |
| 43 } | |
| 44 checkGrowable(receiver, 'removeAt'); | |
| 45 return JS('var', r'#.splice(#, 1)[0]', receiver, index); | |
| 46 } | |
| 47 return UNINTERCEPTED(receiver.removeAt(index)); | |
| 48 } | |
| 49 | |
| 50 removeLast(var receiver) { | |
| 51 if (isJsArray(receiver)) { | |
| 52 checkGrowable(receiver, 'removeLast'); | |
| 53 if (receiver.length == 0) throw new RangeError.value(-1); | |
| 54 return JS('var', r'#.pop()', receiver); | |
| 55 } | |
| 56 return UNINTERCEPTED(receiver.removeLast()); | |
| 57 } | |
| 58 | |
| 59 filter(var receiver, var predicate) { | |
| 60 if (!isJsArray(receiver)) { | |
| 61 return UNINTERCEPTED(receiver.filter(predicate)); | |
| 62 } else { | |
| 63 return Collections.filter(receiver, [], predicate); | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 get$length(var receiver) { | 31 get$length(var receiver) { |
| 68 if (receiver is String || isJsArray(receiver)) { | 32 if (receiver is String || isJsArray(receiver)) { |
| 69 return JS('num', r'#.length', receiver); // TODO(sra): Use 'int'? | 33 return JS('num', r'#.length', receiver); // TODO(sra): Use 'int'? |
| 70 } else { | 34 } else { |
| 71 return UNINTERCEPTED(receiver.length); | 35 return UNINTERCEPTED(receiver.length); |
| 72 } | 36 } |
| 73 } | 37 } |
| 74 | 38 |
| 75 set$length(receiver, newLength) { | 39 set$length(receiver, newLength) { |
| 76 if (isJsArray(receiver)) { | 40 if (isJsArray(receiver)) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 96 if (JS('bool', r'# === 0 && (1 / #) < 0', value, value)) { | 60 if (JS('bool', r'# === 0 && (1 / #) < 0', value, value)) { |
| 97 return '-0.0'; | 61 return '-0.0'; |
| 98 } | 62 } |
| 99 if (value == null) return 'null'; | 63 if (value == null) return 'null'; |
| 100 if (JS('bool', r'typeof # == "function"', value)) { | 64 if (JS('bool', r'typeof # == "function"', value)) { |
| 101 return 'Closure'; | 65 return 'Closure'; |
| 102 } | 66 } |
| 103 return JS('String', r'String(#)', value); | 67 return JS('String', r'String(#)', value); |
| 104 } | 68 } |
| 105 | 69 |
| 106 iterator(receiver) { | |
| 107 if (isJsArray(receiver)) { | |
| 108 return new ListIterator(receiver); | |
| 109 } | |
| 110 return UNINTERCEPTED(receiver.iterator()); | |
| 111 } | |
| 112 | |
| 113 get$isEmpty(receiver) { | 70 get$isEmpty(receiver) { |
| 114 if (receiver is String || isJsArray(receiver)) { | 71 if (receiver is String || isJsArray(receiver)) { |
| 115 return JS('bool', r'#.length === 0', receiver); | 72 return JS('bool', r'#.length === 0', receiver); |
| 116 } | 73 } |
| 117 return UNINTERCEPTED(receiver.isEmpty); | 74 return UNINTERCEPTED(receiver.isEmpty); |
| 118 } | 75 } |
| 119 | 76 |
| 120 compareTo(a, b) { | 77 compareTo(a, b) { |
| 121 if (checkNumbers(a, b)) { | 78 if (checkNumbers(a, b)) { |
| 122 if (a < b) { | 79 if (a < b) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 142 } | 99 } |
| 143 } else if (a is String) { | 100 } else if (a is String) { |
| 144 if (b is !String) throw new ArgumentError(b); | 101 if (b is !String) throw new ArgumentError(b); |
| 145 return JS('bool', r'# == #', a, b) ? 0 | 102 return JS('bool', r'# == #', a, b) ? 0 |
| 146 : JS('bool', r'# < #', a, b) ? -1 : 1; | 103 : JS('bool', r'# < #', a, b) ? -1 : 1; |
| 147 } else { | 104 } else { |
| 148 return UNINTERCEPTED(a.compareTo(b)); | 105 return UNINTERCEPTED(a.compareTo(b)); |
| 149 } | 106 } |
| 150 } | 107 } |
| 151 | 108 |
| 152 addAll(receiver, collection) { | 109 iterator(receiver) { |
| 153 if (!isJsArray(receiver)) return UNINTERCEPTED(receiver.addAll(collection)); | 110 if (isJsArray(receiver)) { |
| 154 | 111 return new ListIterator(receiver); |
| 155 // TODO(ahe): Use for-in when it is implemented correctly. | |
| 156 var iterator = collection.iterator(); | |
| 157 while (iterator.hasNext) { | |
| 158 receiver.add(iterator.next()); | |
| 159 } | 112 } |
| 160 } | 113 return UNINTERCEPTED(receiver.iterator()); |
| 161 | |
| 162 addLast(receiver, value) { | |
| 163 if (!isJsArray(receiver)) return UNINTERCEPTED(receiver.addLast(value)); | |
| 164 | |
| 165 checkGrowable(receiver, 'addLast'); | |
| 166 JS('void', r'#.push(#)', receiver, value); | |
| 167 } | |
| 168 | |
| 169 clear(receiver) { | |
| 170 if (!isJsArray(receiver)) return UNINTERCEPTED(receiver.clear()); | |
| 171 receiver.length = 0; | |
| 172 } | |
| 173 | |
| 174 forEach(receiver, f) { | |
| 175 if (!isJsArray(receiver)) { | |
| 176 return UNINTERCEPTED(receiver.forEach(f)); | |
| 177 } else { | |
| 178 return Collections.forEach(receiver, f); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 map(receiver, f) { | |
| 183 if (!isJsArray(receiver)) { | |
| 184 return UNINTERCEPTED(receiver.map(f)); | |
| 185 } else { | |
| 186 return Collections.map(receiver, [], f); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 reduce(receiver, initialValue, f) { | |
| 191 if (!isJsArray(receiver)) { | |
| 192 return UNINTERCEPTED(receiver.reduce(initialValue, f)); | |
| 193 } else { | |
| 194 return Collections.reduce(receiver, initialValue, f); | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 getRange(receiver, start, length) { | |
| 199 if (!isJsArray(receiver)) { | |
| 200 return UNINTERCEPTED(receiver.getRange(start, length)); | |
| 201 } | |
| 202 if (0 == length) return []; | |
| 203 checkNull(start); // TODO(ahe): This is not specified but co19 tests it. | |
| 204 checkNull(length); // TODO(ahe): This is not specified but co19 tests it. | |
| 205 if (start is !int) throw new ArgumentError(start); | |
| 206 if (length is !int) throw new ArgumentError(length); | |
| 207 if (length < 0) throw new ArgumentError(length); | |
| 208 if (start < 0) throw new RangeError.value(start); | |
| 209 var end = start + length; | |
| 210 if (end > receiver.length) { | |
| 211 throw new RangeError.value(length); | |
| 212 } | |
| 213 if (length < 0) throw new ArgumentError(length); | |
| 214 // TODO(sra): We need a type that is exactly the JavaScript Array type. | |
| 215 return JS('=List', r'#.slice(#, #)', receiver, start, end); | |
| 216 } | 114 } |
| 217 | 115 |
| 218 indexOf$1(receiver, element) { | 116 indexOf$1(receiver, element) { |
| 219 if (isJsArray(receiver)) { | 117 if (isJsArray(receiver)) { |
| 220 var length = JS('num', r'#.length', receiver); | 118 var length = JS('num', r'#.length', receiver); |
| 221 return Arrays.indexOf(receiver, element, 0, length); | 119 return Arrays.indexOf(receiver, element, 0, length); |
| 222 } else if (receiver is String) { | 120 } else if (receiver is String) { |
| 223 checkNull(element); | 121 checkNull(element); |
| 224 if (element is !String) throw new ArgumentError(element); | 122 if (element is !String) throw new ArgumentError(element); |
| 225 return JS('int', r'#.indexOf(#)', receiver, element); | 123 return JS('int', r'#.indexOf(#)', receiver, element); |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 } else if (isJsArray(receiver)) { | 480 } else if (isJsArray(receiver)) { |
| 583 return createRuntimeType('List'); | 481 return createRuntimeType('List'); |
| 584 } else { | 482 } else { |
| 585 return UNINTERCEPTED(receiver.runtimeType); | 483 return UNINTERCEPTED(receiver.runtimeType); |
| 586 } | 484 } |
| 587 } | 485 } |
| 588 | 486 |
| 589 // TODO(lrn): These getters should be generated automatically for all | 487 // TODO(lrn): These getters should be generated automatically for all |
| 590 // intercepted methods. | 488 // intercepted methods. |
| 591 get$toString(receiver) => () => toString(receiver); | 489 get$toString(receiver) => () => toString(receiver); |
| OLD | NEW |