OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #library("dart:coreimpl"); | |
6 | |
7 #source("../../corelib/src/implementation/dual_pivot_quicksort.dart"); | |
8 #source("../../corelib/src/implementation/duration_implementation.dart"); | |
9 #source("../../corelib/src/implementation/exceptions.dart"); | |
10 #source("../../corelib/src/implementation/collections.dart"); | |
11 #source("../../corelib/src/implementation/future_implementation.dart"); | |
12 #source("../../corelib/src/implementation/hash_map_set.dart"); | |
13 // TODO(jimhug): Re-explore tradeoffs with using builtin JS maps. | |
14 #source("../../corelib/src/implementation/linked_hash_map.dart"); | |
15 #source("../../corelib/src/implementation/maps.dart"); | |
16 #source("../../corelib/src/implementation/options.dart"); | |
17 #source("../../corelib/src/implementation/queue.dart"); | |
18 #source("../../corelib/src/implementation/stopwatch_implementation.dart"); | |
19 #source("../../corelib/src/implementation/splay_tree.dart"); | |
20 | |
21 #source("string_buffer.dart"); | |
22 #source("string_base.dart"); | |
23 #source("string_implementation.dart"); | |
24 #source("arrays.dart"); | |
25 #source("date_implementation.dart"); | |
26 | |
27 #source("function_implementation.dart"); | |
28 | |
29 /** | |
30 * The default implementation of the [List<E>] interface. Essentially a growable | |
31 * array that will expand automatically as more elements are added. | |
32 */ | |
33 class ListFactory<E> implements List<E> native "Array" { | |
34 ListFactory([int length]) native; | |
35 | |
36 // TODO(jmesserly): type parameters aren't working here | |
37 factory ListFactory.from(Iterable other) { | |
38 final list = []; | |
39 for (final e in other) { | |
40 list.add(e); | |
41 } | |
42 return list; | |
43 } | |
44 | |
45 // TODO(jimhug): Only works for Arrays. | |
46 factory ListFactory.fromList(List other, int startIndex, int endIndex) | |
47 native 'return other.slice(startIndex, endIndex);'; | |
48 | |
49 int length; // all fields on natives are implied native. | |
50 | |
51 // List<E> members: | |
52 E operator [](int index) native; | |
53 void operator []=(int index, E value) native; | |
54 void add(E value) native "this.push(value);"; | |
55 void addLast(E value) native "this.push(value);"; | |
56 void addAll(Collection<E> collection) { | |
57 for (E item in collection) add(item); | |
58 } | |
59 void sort(int compare(E a, E b)) native; | |
60 void copyFrom(List<Object> src, int srcStart, int dstStart, int count) native; | |
61 int indexOf(E element, [int start]) native; | |
62 int lastIndexOf(E element, [int start]) native; | |
63 void clear() { length = 0; } | |
64 | |
65 E removeLast() native "return this.pop();"; | |
66 | |
67 E last() => this[this.length-1]; | |
68 | |
69 ListFactory<E> getRange(int start, int rangeLength) { | |
70 if (rangeLength == 0) return []; | |
71 if (rangeLength < 0) throw new IllegalArgumentException('length'); | |
72 if (start < 0 || start + rangeLength > this.length) | |
73 throw new IndexOutOfRangeException(start); | |
74 return this._slice(start, start + rangeLength); | |
75 } | |
76 | |
77 void setRange(int start, int rangeLength, List<E> from, [int startFrom = 0]) { | |
78 // length of 0 prevails and should not throw exceptions. | |
79 if (rangeLength == 0) return; | |
80 if (rangeLength < 0) { | |
81 throw new IllegalArgumentException('length is negative'); | |
82 } | |
83 | |
84 if (start < 0) throw new IndexOutOfRangeException(start); | |
85 | |
86 int end = start + rangeLength; | |
87 if (end > this.length) throw new IndexOutOfRangeException(end); | |
88 | |
89 if (startFrom < 0) throw new IndexOutOfRangeException(startFrom); | |
90 | |
91 int endFrom = startFrom + rangeLength; | |
92 if (endFrom > from.length) throw new IndexOutOfRangeException(endFrom); | |
93 | |
94 for (var i = 0; i < rangeLength; ++i) | |
95 this[start + i] = from[startFrom + i]; | |
96 } | |
97 | |
98 void removeRange(int start, int rangeLength) { | |
99 if (rangeLength == 0) return; | |
100 if (rangeLength < 0) throw new IllegalArgumentException('length'); | |
101 if (start < 0 || start + rangeLength > this.length) | |
102 throw new IndexOutOfRangeException(start); | |
103 this._splice(start, rangeLength); | |
104 } | |
105 | |
106 void insertRange(int start, int rangeLength, [E initialValue]) { | |
107 if (rangeLength == 0) return; | |
108 if (rangeLength < 0) throw new IllegalArgumentException('length'); | |
109 if (start < 0 || start > this.length) | |
110 throw new IndexOutOfRangeException(start); | |
111 | |
112 // Splice in the values with a minimum of array allocations. | |
113 var args = new ListFactory(rangeLength + 2); | |
114 args[0] = start; | |
115 args[1] = 0; | |
116 for (var i = 0; i < rangeLength; i++) { | |
117 args[i + 2] = initialValue; | |
118 } | |
119 this._splice_apply(args); | |
120 } | |
121 | |
122 // Collection<E> members: | |
123 void forEach(void f(E element)) native; | |
124 ListFactory<E> filter(bool f(E element)) native; | |
125 ListFactory map(f(E element)) native; | |
126 bool every(bool f(E element)) native; | |
127 bool some(bool f(E element)) native; | |
128 bool isEmpty() => length == 0; | |
129 | |
130 // Iterable<E> members: | |
131 Iterator<E> iterator() => new ListIterator(this); | |
132 | |
133 String toString() => Collections.collectionToString(this); | |
134 | |
135 // Native methods. | |
136 ListFactory<E> _slice(start, end) native 'slice'; | |
137 void _splice(start, length) native 'splice'; | |
138 void _splice_apply(args) native 'this.splice.apply(this, args)'; | |
139 } | |
140 | |
141 // Iterator for lists. | |
142 class ListIterator<T> implements Iterator<T> { | |
143 ListIterator(List<T> array) | |
144 : _array = array, | |
145 _pos = 0 { | |
146 } | |
147 | |
148 bool hasNext() { | |
149 return _array.length > _pos; | |
150 } | |
151 | |
152 T next() { | |
153 // TODO(jmesserly): this check is redundant in a for-in loop | |
154 // Must we do it? | |
155 if (!hasNext()) { | |
156 throw const NoMoreElementsException(); | |
157 } | |
158 return _array[_pos++]; | |
159 } | |
160 | |
161 final List<T> _array; | |
162 int _pos; | |
163 } | |
164 | |
165 // TODO(jimhug): Enforce immutability on IE | |
166 ImmutableList _constList(List other) native ''' | |
167 other.__proto__ = ImmutableList.prototype; | |
168 return other; | |
169 ''' | |
170 { new ImmutableList(other.length); } | |
171 | |
172 | |
173 /** An immutable list. Attempting to modify the list will throw an exception. */ | |
174 class ImmutableList<E> extends ListFactory<E> { | |
175 // TODO(jimhug): Can this go away now? | |
176 int get length() native "return this.length;"; | |
177 | |
178 void set length(int length) { | |
179 throw const IllegalAccessException(); | |
180 } | |
181 | |
182 ImmutableList(int length) : super(length); | |
183 | |
184 factory ImmutableList.from(List other) { | |
185 return _constList(other); | |
186 } | |
187 | |
188 void operator []=(int index, E value) { | |
189 throw const IllegalAccessException(); | |
190 } | |
191 | |
192 void copyFrom(List src, int srcStart, int dstStart, int count) { | |
193 throw const IllegalAccessException(); | |
194 } | |
195 | |
196 void setRange(int start, int length, List<E> from, [int startFrom = 0]) { | |
197 throw const IllegalAccessException(); | |
198 } | |
199 | |
200 void removeRange(int start, int length) { | |
201 throw const IllegalAccessException(); | |
202 } | |
203 | |
204 void insertRange(int start, int length, [E initialValue = null]) { | |
205 throw const IllegalAccessException(); | |
206 } | |
207 | |
208 void sort(int compare(E a, E b)) { | |
209 throw const IllegalAccessException(); | |
210 } | |
211 | |
212 void add(E element) { | |
213 throw const IllegalAccessException(); | |
214 } | |
215 | |
216 void addLast(E element) { | |
217 throw const IllegalAccessException(); | |
218 } | |
219 | |
220 void addAll(Collection<E> elements) { | |
221 throw const IllegalAccessException(); | |
222 } | |
223 | |
224 void clear() { | |
225 throw const IllegalAccessException(); | |
226 } | |
227 | |
228 E removeLast() { | |
229 throw const IllegalAccessException(); | |
230 } | |
231 | |
232 String toString() => Collections.collectionToString(this); | |
233 } | |
234 | |
235 | |
236 LinkedHashMapImplementation _map(List itemsAndKeys) { | |
237 LinkedHashMapImplementation ret = new LinkedHashMapImplementation(); | |
238 for (int i=0; i < itemsAndKeys.length;) { | |
239 ret[itemsAndKeys[i++]] = itemsAndKeys[i++]; | |
240 } | |
241 return ret; | |
242 } | |
243 | |
244 ImmutableMap _constMap(List itemsAndKeys) { | |
245 return new ImmutableMap(itemsAndKeys); | |
246 } | |
247 | |
248 /** An immutable map. */ | |
249 class ImmutableMap<K, V> implements Map<K, V> { | |
250 final Map<K, V> _internal; | |
251 | |
252 ImmutableMap(List keyValuePairs) : _internal = _map(keyValuePairs); | |
253 | |
254 V operator [](K key) => _internal[key]; | |
255 | |
256 bool isEmpty() => _internal.isEmpty(); | |
257 | |
258 int get length() => _internal.length; | |
259 | |
260 void forEach(void f(K key, V value)) { | |
261 _internal.forEach(f); | |
262 } | |
263 | |
264 Collection<K> getKeys() => _internal.getKeys(); | |
265 | |
266 Collection<V> getValues() => _internal.getValues(); | |
267 | |
268 bool containsKey(K key) => _internal.containsKey(key); | |
269 | |
270 bool containsValue(V value) => _internal.containsValue(value); | |
271 | |
272 void operator []=(K key, V value) { | |
273 throw const IllegalAccessException(); | |
274 } | |
275 | |
276 V putIfAbsent(K key, V ifAbsent()) { | |
277 throw const IllegalAccessException(); | |
278 } | |
279 | |
280 void clear() { | |
281 throw const IllegalAccessException(); | |
282 } | |
283 | |
284 V remove(K key) { | |
285 throw const IllegalAccessException(); | |
286 } | |
287 | |
288 String toString() => Maps.mapToString(this); | |
289 } | |
290 | |
291 | |
292 // TODO(jmesserly): this should wrap real RegExp when we can | |
293 // We can't do it yet because we'd need a way to redirect the const | |
294 // default constructor. | |
295 // TODO(jimhug): One way to resolve this is to make the const constructor | |
296 // very special in order for it to generate JS regex literals into the code | |
297 // and then treat the constructor as a factory. | |
298 class JSSyntaxRegExp implements RegExp { | |
299 final String pattern; | |
300 final bool multiLine; | |
301 final bool ignoreCase; | |
302 | |
303 const JSSyntaxRegExp(String pattern, [bool multiLine, bool ignoreCase]): | |
304 this._create(pattern, | |
305 (multiLine == true ? 'm' : '') + (ignoreCase == true ? 'i' : '')); | |
306 | |
307 const JSSyntaxRegExp._create(String pattern, String flags) native | |
308 '''this.re = new RegExp(pattern, flags); | |
309 this.pattern = pattern; | |
310 this.multiLine = this.re.multiline; | |
311 this.ignoreCase = this.re.ignoreCase;'''; | |
312 | |
313 Match firstMatch(String str) { | |
314 List<String> m = _exec(str); | |
315 return m == null ? null | |
316 : new MatchImplementation(pattern, str, _matchStart(m), _lastIndex, m); | |
317 } | |
318 | |
319 List<String> _exec(String str) native "return this.re.exec(str);" { | |
320 // Note: this code is just a hint to tell the frog compiler the dependencies | |
321 // this native code might have. It is not an implementation. | |
322 return []; | |
323 } | |
324 int _matchStart(m) native "return m.index;"; | |
325 int get _lastIndex() native "return this.re.lastIndex;"; | |
326 | |
327 bool hasMatch(String str) native "return this.re.test(str);"; | |
328 | |
329 String stringMatch(String str) { | |
330 var match = firstMatch(str); | |
331 return match === null ? null : match.group(0); | |
332 } | |
333 | |
334 Iterable<Match> allMatches(String str) => new _AllMatchesIterable(this, str); | |
335 | |
336 /** | |
337 * Returns a new RegExp with the same pattern as this one and with the | |
338 * "global" flag set. This allows us to match this RegExp against a string | |
339 * multiple times, to support things like [allMatches] and | |
340 * [String.replaceAll]. | |
341 * | |
342 * Note that the returned RegExp disobeys the normal API in that it maintains | |
343 * state about the location of the last match. | |
344 */ | |
345 JSSyntaxRegExp get _global() => new JSSyntaxRegExp._create(pattern, | |
346 'g' + (multiLine ? 'm' : '') + (ignoreCase ? 'i' : '')); | |
347 } | |
348 | |
349 class MatchImplementation implements Match { | |
350 const MatchImplementation( | |
351 String this.pattern, | |
352 String this.str, | |
353 int this._start, | |
354 int this._end, | |
355 List<String> this._groups); | |
356 | |
357 final String pattern; | |
358 final String str; | |
359 final int _start; | |
360 final int _end; | |
361 final List<String> _groups; | |
362 | |
363 int start() => _start; | |
364 int end() => _end; | |
365 String group(int groupIndex) => _groups[groupIndex]; | |
366 String operator [](int groupIndex) => _groups[groupIndex]; | |
367 int groupCount() => _groups.length; | |
368 | |
369 List<String> groups(List<int> groupIndices) { | |
370 List<String> out = []; | |
371 groupIndices.forEach((int groupIndex) => out.add(_groups[groupIndex])); | |
372 return out; | |
373 } | |
374 } | |
375 | |
376 class _AllMatchesIterable implements Iterable<Match> { | |
377 final JSSyntaxRegExp _re; | |
378 final String _str; | |
379 | |
380 const _AllMatchesIterable(this._re, this._str); | |
381 | |
382 Iterator<Match> iterator() => new _AllMatchesIterator(_re, _str); | |
383 } | |
384 | |
385 class _AllMatchesIterator implements Iterator<Match> { | |
386 final RegExp _re; | |
387 final String _str; | |
388 Match _next; | |
389 bool _done; | |
390 | |
391 _AllMatchesIterator(JSSyntaxRegExp re, String this._str) | |
392 : _done = false, _re = re._global; | |
393 | |
394 Match next() { | |
395 if (!hasNext()) { | |
396 throw const NoMoreElementsException(); | |
397 } | |
398 | |
399 // _next is set by #hasNext | |
400 var result = _next; | |
401 _next = null; | |
402 return result; | |
403 } | |
404 | |
405 bool hasNext() { | |
406 if (_done) { | |
407 return false; | |
408 } else if (_next != null) { | |
409 return true; | |
410 } | |
411 | |
412 _next = _re.firstMatch(_str); | |
413 if (_next == null) { | |
414 _done = true; | |
415 return false; | |
416 } else { | |
417 return true; | |
418 } | |
419 } | |
420 } | |
421 | |
422 | |
423 class NumImplementation implements int, double native "Number" { | |
424 // Arithmetic operations. | |
425 num operator +(num other) native; | |
426 num operator -(num other) native; | |
427 num operator *(num other) native; | |
428 num operator %(num other) native; | |
429 num operator /(num other) native; | |
430 // Truncating division. | |
431 // TODO(jimhug): Implement | |
432 num operator ~/(num other) native; | |
433 // The unary '-' operator. | |
434 num operator negate() native "'use strict'; return -this;"; | |
435 | |
436 // Relational operations. | |
437 bool operator <(num other) native; | |
438 bool operator <=(num other) native; | |
439 bool operator >(num other) native; | |
440 bool operator >=(num other) native; | |
441 | |
442 bool operator ==(var other) native; | |
443 | |
444 // Bitwise operations | |
445 int operator &(int other) native; | |
446 int operator |(int other) native; | |
447 int operator ^(int other) native; | |
448 int operator ~() native; | |
449 int operator <<(int shiftAmount) native; | |
450 int operator >>(int shiftAmount) native; | |
451 | |
452 | |
453 // TODO(jimhug): Move these out of methods to avoid boxing when not needed. | |
454 // TODO(jmesserly): for now I'm avoiding boxing with "use strict", however, | |
455 // we might want to do something better. It would be nice if operators and | |
456 // methods on String/num were handled in a uniform way. | |
457 num remainder(num other) native "'use strict'; return this % other;"; | |
458 | |
459 bool isEven() native "'use strict'; return ((this & 1) == 0);"; | |
460 bool isOdd() native "'use strict'; return ((this & 1) == 1);"; | |
461 bool isNaN() native "'use strict'; return isNaN(this);"; | |
462 bool isNegative() native | |
463 "'use strict'; return this == 0 ? (1 / this) < 0 : this < 0;"; | |
464 bool isInfinite() native | |
465 "'use strict'; return (this == Infinity) || (this == -Infinity);"; | |
466 | |
467 num abs() native "'use strict'; return Math.abs(this);"; | |
468 num round() native "'use strict'; return Math.round(this);"; | |
469 num floor() native "'use strict'; return Math.floor(this);"; | |
470 num ceil() native "'use strict'; return Math.ceil(this);"; | |
471 num truncate() native | |
472 "'use strict'; return (this < 0) ? Math.ceil(this) : Math.floor(this);"; | |
473 | |
474 int hashCode() native "'use strict'; return this & 0x1FFFFFFF;"; | |
475 | |
476 // If truncated is -0.0 return +0. The test will also trigger for positive | |
477 // 0s but that's not a problem. | |
478 int toInt() native ''' | |
479 'use strict'; | |
480 if (isNaN(this)) \$throw(new BadNumberFormatException("NaN")); | |
481 if ((this == Infinity) || (this == -Infinity)) { | |
482 \$throw(new BadNumberFormatException("Infinity")); | |
483 } | |
484 var truncated = (this < 0) ? Math.ceil(this) : Math.floor(this); | |
485 if (truncated == -0.0) return 0; | |
486 return truncated;''' { throw new BadNumberFormatException(""); } | |
487 | |
488 double toDouble() native "'use strict'; return this + 0;"; | |
489 | |
490 String toStringAsFixed(int fractionDigits) native | |
491 "'use strict'; return this.toFixed(fractionDigits);"; | |
492 String toStringAsExponential(int fractionDigits) native | |
493 "'use strict'; return this.toExponential(fractionDigits)"; | |
494 String toStringAsPrecision(int precision) native | |
495 "'use strict'; return this.toPrecision(precision)"; | |
496 String toRadixString(int radix) native | |
497 "'use strict'; return this.toString(radix)"; | |
498 | |
499 // CompareTo has to give a complete order, including -0/+0, NaN and | |
500 // Infinities. | |
501 // Order is: -Inf < .. < -0.0 < 0.0 .. < +inf < NaN. | |
502 int compareTo(NumImplementation other) { | |
503 // Don't use the 'this' object (which is a JS Number object), but get the | |
504 // primitive JS number by invoking toDouble(). | |
505 num thisValue = toDouble(); | |
506 // Remember that NaN return false for any comparison. | |
507 if (thisValue < other) { | |
508 return -1; | |
509 } else if (thisValue > other) { | |
510 return 1; | |
511 } else if (thisValue == other) { | |
512 if (thisValue == 0) { | |
513 bool thisIsNegative = isNegative(); | |
514 bool otherIsNegative = other.isNegative(); | |
515 if (thisIsNegative == otherIsNegative) return 0; | |
516 if (thisIsNegative) return -1; | |
517 return 1; | |
518 } | |
519 return 0; | |
520 } else if (isNaN()) { | |
521 if (other.isNaN()) { | |
522 return 0; | |
523 } | |
524 return 1; | |
525 } else { | |
526 return -1; | |
527 } | |
528 } | |
529 } | |
OLD | NEW |