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