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 |