Index: frog/leg/lib/js_helper.dart |
=================================================================== |
--- frog/leg/lib/js_helper.dart (revision 5925) |
+++ frog/leg/lib/js_helper.dart (working copy) |
@@ -1,1376 +0,0 @@ |
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-#library('js_helper'); |
- |
-#import('coreimpl.dart'); |
- |
-#source('constant_map.dart'); |
-#source('native_helper.dart'); |
-#source('regexp_helper.dart'); |
-#source('string_helper.dart'); |
- |
-/** |
- * Returns true if both arguments are numbers. |
- * |
- * If only the first argument is a number, an |
- * [IllegalArgumentException] with the other argument is thrown. |
- */ |
-bool checkNumbers(var a, var b) { |
- if (a is num) { |
- if (b is num) { |
- return true; |
- } else { |
- checkNull(b); |
- throw new IllegalArgumentException(b); |
- } |
- } |
- return false; |
-} |
- |
- |
-bool isJsArray(var value) { |
- return value !== null && JS('bool', @'#.constructor === Array', value); |
-} |
- |
- |
-add(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# + #', a, b); |
- } else if (a is String) { |
- // TODO(lrn): Remove when we disable String.operator+ |
- b = b.toString(); |
- if (b is String) { |
- return JS('String', @'# + #', a, b); |
- } |
- checkNull(b); |
- throw new IllegalArgumentException(b); |
- } |
- return UNINTERCEPTED(a + b); |
-} |
- |
-div(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# / #', a, b); |
- } |
- return UNINTERCEPTED(a / b); |
-} |
- |
-mul(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# * #', a, b); |
- } |
- return UNINTERCEPTED(a * b); |
-} |
- |
-sub(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# - #', a, b); |
- } |
- return UNINTERCEPTED(a - b); |
-} |
- |
-mod(var a, var b) { |
- if (checkNumbers(a, b)) { |
- // Euclidean Modulo. |
- int result = JS('num', @'# % #', a, b); |
- if (result == 0) return 0; // Make sure we don't return -0.0. |
- if (result > 0) return result; |
- if (b < 0) { |
- return result - b; |
- } else { |
- return result + b; |
- } |
- } |
- return UNINTERCEPTED(a % b); |
-} |
- |
-tdiv(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return (a / b).truncate(); |
- } |
- return UNINTERCEPTED(a ~/ b); |
-} |
- |
-eq(var a, var b) { |
- if (JS('bool', @'typeof # === "object"', a)) { |
- if (JS_HAS_EQUALS(a)) { |
- return UNINTERCEPTED(a == b) === true; |
- } else { |
- return JS('bool', @'# === #', a, b); |
- } |
- } |
- // TODO(lrn): is NaN === NaN ? Is -0.0 === 0.0 ? |
- return JS('bool', @'# === #', a, b); |
-} |
- |
-eqq(var a, var b) { |
- return JS('bool', @'# === #', a, b); |
-} |
- |
-eqNull(var a) { |
- if (JS('bool', @'typeof # === "object"', a)) { |
- if (JS_HAS_EQUALS(a)) { |
- return UNINTERCEPTED(a == null) === true; |
- } else { |
- return false; |
- } |
- } else { |
- return JS('bool', @'typeof # === "undefined"', a); |
- } |
-} |
- |
-gt(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('bool', @'# > #', a, b); |
- } |
- return UNINTERCEPTED(a > b); |
-} |
- |
-ge(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('bool', @'# >= #', a, b); |
- } |
- return UNINTERCEPTED(a >= b); |
-} |
- |
-lt(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('bool', @'# < #', a, b); |
- } |
- return UNINTERCEPTED(a < b); |
-} |
- |
-le(var a, var b) { |
- if (checkNumbers(a, b)) { |
- return JS('bool', @'# <= #', a, b); |
- } |
- return UNINTERCEPTED(a <= b); |
-} |
- |
-shl(var a, var b) { |
- // TODO(floitsch): inputs must be integers. |
- if (checkNumbers(a, b)) { |
- if (b < 0) throw new IllegalArgumentException(b); |
- return JS('num', @'# << #', a, b); |
- } |
- return UNINTERCEPTED(a << b); |
-} |
- |
-shr(var a, var b) { |
- // TODO(floitsch): inputs must be integers. |
- if (checkNumbers(a, b)) { |
- if (b < 0) throw new IllegalArgumentException(b); |
- return JS('num', @'# >> #', a, b); |
- } |
- return UNINTERCEPTED(a >> b); |
-} |
- |
-and(var a, var b) { |
- // TODO(floitsch): inputs must be integers. |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# & #', a, b); |
- } |
- return UNINTERCEPTED(a & b); |
-} |
- |
-or(var a, var b) { |
- // TODO(floitsch): inputs must be integers. |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# | #', a, b); |
- } |
- return UNINTERCEPTED(a | b); |
-} |
- |
-xor(var a, var b) { |
- // TODO(floitsch): inputs must be integers. |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# ^ #', a, b); |
- } |
- return UNINTERCEPTED(a ^ b); |
-} |
- |
-not(var a) { |
- if (JS('bool', @'typeof # === "number"', a)) return JS('num', @'~#', a); |
- return UNINTERCEPTED(~a); |
-} |
- |
-neg(var a) { |
- if (JS('bool', @'typeof # === "number"', a)) return JS('num', @'-#', a); |
- return UNINTERCEPTED(-a); |
-} |
- |
-index(var a, var index) { |
- if (a is String || isJsArray(a)) { |
- if (index is !int) { |
- if (index is !num) throw new IllegalArgumentException(index); |
- if (index.truncate() !== index) throw new IllegalArgumentException(index); |
- } |
- if (index < 0 || index >= a.length) { |
- throw new IndexOutOfRangeException(index); |
- } |
- return JS('Object', @'#[#]', a, index); |
- } |
- return UNINTERCEPTED(a[index]); |
-} |
- |
-void indexSet(var a, var index, var value) { |
- if (isJsArray(a)) { |
- if (!(index is int)) { |
- throw new IllegalArgumentException(index); |
- } |
- if (index < 0 || index >= a.length) { |
- throw new IndexOutOfRangeException(index); |
- } |
- checkMutable(a, 'indexed set'); |
- JS('Object', @'#[#] = #', a, index, value); |
- return; |
- } |
- UNINTERCEPTED(a[index] = value); |
-} |
- |
-checkMutable(list, reason) { |
- if (JS('bool', @'!!(#.immutable$list)', list)) { |
- throw new UnsupportedOperationException(reason); |
- } |
-} |
- |
-builtin$add$1(var receiver, var value) { |
- if (isJsArray(receiver)) { |
- checkGrowable(receiver, 'add'); |
- JS('Object', @'#.push(#)', receiver, value); |
- return; |
- } |
- return UNINTERCEPTED(receiver.add(value)); |
-} |
- |
-builtin$removeLast$0(var receiver) { |
- if (isJsArray(receiver)) { |
- checkGrowable(receiver, 'removeLast'); |
- if (receiver.length === 0) throw new IndexOutOfRangeException(-1); |
- return JS('Object', @'#.pop()', receiver); |
- } |
- return UNINTERCEPTED(receiver.removeLast()); |
-} |
- |
-builtin$filter$1(var receiver, var predicate) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.filter(predicate)); |
- } else { |
- return Collections.filter(receiver, [], predicate); |
- } |
-} |
- |
- |
-builtin$get$length(var receiver) { |
- if (receiver is String || isJsArray(receiver)) { |
- return JS('num', @'#.length', receiver); |
- } else { |
- return UNINTERCEPTED(receiver.length); |
- } |
-} |
- |
-builtin$set$length(receiver, newLength) { |
- if (isJsArray(receiver)) { |
- checkNull(newLength); // TODO(ahe): This is not specified but co19 tests it. |
- if (newLength is !int) throw new IllegalArgumentException(newLength); |
- if (newLength < 0) throw new IndexOutOfRangeException(newLength); |
- checkGrowable(receiver, 'set length'); |
- JS('void', @'#.length = #', receiver, newLength); |
- } else { |
- UNINTERCEPTED(receiver.length = newLength); |
- } |
- return newLength; |
-} |
- |
-checkGrowable(list, reason) { |
- if (JS('bool', @'!!(#.fixed$length)', list)) { |
- throw new UnsupportedOperationException(reason); |
- } |
-} |
- |
-builtin$toString$0(var value) { |
- if (JS('bool', @'typeof # == "object"', value)) { |
- if (isJsArray(value)) { |
- return Collections.collectionToString(value); |
- } else { |
- return UNINTERCEPTED(value.toString()); |
- } |
- } |
- if (JS('bool', @'# === 0 && (1 / #) < 0', value, value)) { |
- return '-0.0'; |
- } |
- if (value === null) return 'null'; |
- if (JS('bool', @'typeof # == "function"', value)) { |
- return 'Closure'; |
- } |
- return JS('string', @'String(#)', value); |
-} |
- |
- |
-builtin$iterator$0(receiver) { |
- if (isJsArray(receiver)) { |
- return new ListIterator(receiver); |
- } |
- return UNINTERCEPTED(receiver.iterator()); |
-} |
- |
-class ListIterator<T> implements Iterator<T> { |
- int i; |
- List<T> list; |
- ListIterator(List<T> this.list) : i = 0; |
- bool hasNext() => i < JS('int', @'#.length', list); |
- T next() { |
- if (!hasNext()) throw new NoMoreElementsException(); |
- var value = JS('Object', @'#[#]', list, i); |
- i += 1; |
- return value; |
- } |
-} |
- |
-builtin$charCodeAt$1(var receiver, int index) { |
- if (receiver is String) { |
- if (index is !num) throw new IllegalArgumentException(index); |
- if (index < 0) throw new IndexOutOfRangeException(index); |
- if (index >= receiver.length) throw new IndexOutOfRangeException(index); |
- return JS('int', @'#.charCodeAt(#)', receiver, index); |
- } else { |
- return UNINTERCEPTED(receiver.charCodeAt(index)); |
- } |
-} |
- |
-builtin$isEmpty$0(receiver) { |
- if (receiver is String || isJsArray(receiver)) { |
- return JS('bool', @'#.length === 0', receiver); |
- } |
- return UNINTERCEPTED(receiver.isEmpty()); |
-} |
- |
-class Primitives { |
- static void printString(String string) { |
- var hasConsole = JS('bool', @'typeof console == "object"'); |
- if (hasConsole) { |
- JS('void', @'console.log(#)', string); |
- } else { |
- JS('void', @'write(#)', string); |
- JS('void', @'write("\n")'); |
- } |
- } |
- |
- /** [: @"$".charCodeAt(0) :] */ |
- static final int DOLLAR_CHAR_VALUE = 36; |
- |
- static String objectToString(Object object) { |
- String name = JS('String', @'#.constructor.name', object); |
- if (name === null) { |
- name = JS('String', @'#.match(/^\s*function\s*\$?(\S*)\s*\(/)[1]', |
- JS('String', @'#.constructor.toString()', object)); |
- } else { |
- if (name.charCodeAt(0) === DOLLAR_CHAR_VALUE) name = name.substring(1); |
- } |
- return "Instance of '$name'"; |
- } |
- |
- static List newList(length) { |
- if (length === null) return JS('Object', @'new Array()'); |
- if ((length is !int) || (length < 0)) { |
- throw new IllegalArgumentException(length); |
- } |
- var result = JS('Object', @'new Array(#)', length); |
- JS('void', @'#.fixed$length = #', result, true); |
- return result; |
- } |
- |
- static num dateNow() => JS('num', @'Date.now()'); |
- |
- static String stringFromCharCodes(charCodes) { |
- for (var i in charCodes) { |
- if (i is !int) throw new IllegalArgumentException(i); |
- } |
- return JS('String', @'String.fromCharCode.apply(#, #)', null, charCodes); |
- } |
- |
- static valueFromDecomposedDate(years, month, day, hours, minutes, seconds, |
- milliseconds, isUtc) { |
- checkInt(years); |
- checkInt(month); |
- if (month < 1 || 12 < month) throw new IllegalArgumentException(month); |
- checkInt(day); |
- if (day < 1 || 31 < day) throw new IllegalArgumentException(day); |
- checkInt(hours); |
- if (hours < 0 || 24 < hours) throw new IllegalArgumentException(hours); |
- checkInt(minutes); |
- if (minutes < 0 || 59 < minutes) { |
- throw new IllegalArgumentException(minutes); |
- } |
- checkInt(seconds); |
- if (seconds < 0 || 59 < seconds) { |
- // TODO(ahe): Leap seconds? |
- throw new IllegalArgumentException(seconds); |
- } |
- checkInt(milliseconds); |
- if (milliseconds < 0 || 999 < milliseconds) { |
- throw new IllegalArgumentException(milliseconds); |
- } |
- checkBool(isUtc); |
- var jsMonth = month - 1; |
- var value; |
- if (isUtc) { |
- value = JS('num', @'Date.UTC(#, #, #, #, #, #, #)', |
- years, jsMonth, day, hours, minutes, seconds, milliseconds); |
- } else { |
- value = JS('num', @'new Date(#, #, #, #, #, #, #).valueOf()', |
- years, jsMonth, day, hours, minutes, seconds, milliseconds); |
- } |
- if (value.isNaN()) throw new IllegalArgumentException(''); |
- if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc); |
- return value; |
- } |
- |
- static patchUpY2K(value, years, isUtc) { |
- var date = JS('Object', @'new Date(#)', value); |
- if (isUtc) { |
- JS('num', @'#.setUTCFullYear(#)', date, years); |
- } else { |
- JS('num', @'#.setFullYear(#)', date, years); |
- } |
- return JS('num', @'#.valueOf()', date); |
- } |
- |
- // Lazily keep a JS Date stored in the JS object. |
- static lazyAsJsDate(receiver) { |
- if (JS('bool', @'#.date === (void 0)', receiver)) { |
- JS('void', @'#.date = new Date(#)', receiver, receiver.value); |
- } |
- return JS('Date', @'#.date', receiver); |
- } |
- |
- static getYear(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCFullYear()', lazyAsJsDate(receiver)) |
- : JS('int', @'#.getFullYear()', lazyAsJsDate(receiver)); |
- } |
- |
- static getMonth(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCMonth()', lazyAsJsDate(receiver)) + 1 |
- : JS('int', @'#.getMonth()', lazyAsJsDate(receiver)) + 1; |
- } |
- |
- static getDay(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCDate()', lazyAsJsDate(receiver)) |
- : JS('int', @'#.getDate()', lazyAsJsDate(receiver)); |
- } |
- |
- static getHours(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCHours()', lazyAsJsDate(receiver)) |
- : JS('int', @'#.getHours()', lazyAsJsDate(receiver)); |
- } |
- |
- static getMinutes(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCMinutes()', lazyAsJsDate(receiver)) |
- : JS('int', @'#.getMinutes()', lazyAsJsDate(receiver)); |
- } |
- |
- static getSeconds(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCSeconds()', lazyAsJsDate(receiver)) |
- : JS('int', @'#.getSeconds()', lazyAsJsDate(receiver)); |
- } |
- |
- static getMilliseconds(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCMilliseconds()', lazyAsJsDate(receiver)) |
- : JS('int', @'#.getMilliseconds()', lazyAsJsDate(receiver)); |
- } |
- |
- static getWeekday(receiver) { |
- return (receiver.timeZone.isUtc) |
- ? JS('int', @'#.getUTCDay()', lazyAsJsDate(receiver)) |
- : JS('int', @'#.getDay()', lazyAsJsDate(receiver)); |
- } |
- |
- static valueFromDateString(str) { |
- checkNull(str); |
- if (str is !String) throw new IllegalArgumentException(str); |
- var value = JS('num', @'Date.parse(#)', str); |
- if (value.isNaN()) throw new IllegalArgumentException(str); |
- return value; |
- } |
-} |
- |
-builtin$compareTo$1(a, b) { |
- if (checkNumbers(a, b)) { |
- if (a < b) { |
- return -1; |
- } else if (a > b) { |
- return 1; |
- } else if (a == b) { |
- if (a == 0) { |
- bool aIsNegative = a.isNegative(); |
- bool bIsNegative = b.isNegative(); |
- if (aIsNegative == bIsNegative) return 0; |
- if (aIsNegative) return -1; |
- return 1; |
- } |
- return 0; |
- } else if (a.isNaN()) { |
- if (b.isNaN()) { |
- return 0; |
- } |
- return 1; |
- } else { |
- return -1; |
- } |
- } else if (a is String) { |
- if (b is !String) throw new IllegalArgumentException(b); |
- return JS('bool', @'# == #', a, b) ? 0 |
- : JS('bool', @'# < #', a, b) ? -1 : 1; |
- } else { |
- return UNINTERCEPTED(a.compareTo(b)); |
- } |
-} |
- |
-/** |
- * Called by generated code to throw an illegal-argument exception, |
- * for example, if a non-integer index is given to an optimized |
- * indexed access. |
- */ |
-iae(argument) { |
- throw new IllegalArgumentException(argument); |
-} |
- |
-/** |
- * Called by generated code to throw an index-out-of-range exception, |
- * for example, if a bounds check fails in an optimized indexed |
- * access. |
- */ |
-ioore(index) { |
- throw new IndexOutOfRangeException(index); |
-} |
- |
-builtin$addAll$1(receiver, collection) { |
- if (!isJsArray(receiver)) return UNINTERCEPTED(receiver.addAll(collection)); |
- |
- // TODO(ahe): Use for-in when it is implemented correctly. |
- var iterator = collection.iterator(); |
- while (iterator.hasNext()) { |
- receiver.add(iterator.next()); |
- } |
-} |
- |
-builtin$addLast$1(receiver, value) { |
- if (!isJsArray(receiver)) return UNINTERCEPTED(receiver.addLast(value)); |
- |
- checkGrowable(receiver, 'addLast'); |
- JS('Object', @'#.push(#)', receiver, value); |
-} |
- |
-builtin$clear$0(receiver) { |
- if (!isJsArray(receiver)) return UNINTERCEPTED(receiver.clear()); |
- receiver.length = 0; |
-} |
- |
-builtin$forEach$1(receiver, f) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.forEach(f)); |
- } else { |
- return Collections.forEach(receiver, f); |
- } |
-} |
- |
-builtin$map$1(receiver, f) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.map(f)); |
- } else { |
- return Collections.map(receiver, [], f); |
- } |
-} |
- |
-builtin$getRange$2(receiver, start, length) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.getRange(start, length)); |
- } |
- if (0 === length) return []; |
- checkNull(start); // TODO(ahe): This is not specified but co19 tests it. |
- checkNull(length); // TODO(ahe): This is not specified but co19 tests it. |
- if (start is !int) throw new IllegalArgumentException(start); |
- if (length is !int) throw new IllegalArgumentException(length); |
- if (length < 0) throw new IllegalArgumentException(length); |
- if (start < 0) throw new IndexOutOfRangeException(start); |
- var end = start + length; |
- if (end > receiver.length) { |
- throw new IndexOutOfRangeException(length); |
- } |
- if (length < 0) throw new IllegalArgumentException(length); |
- return JS('Object', @'#.slice(#, #)', receiver, start, end); |
-} |
- |
-builtin$indexOf$1(receiver, element) { |
- if (isJsArray(receiver) || receiver is String) { |
- return builtin$indexOf$2(receiver, element, 0); |
- } |
- return UNINTERCEPTED(receiver.indexOf(element)); |
-} |
- |
-builtin$indexOf$2(receiver, element, start) { |
- if (isJsArray(receiver)) { |
- if (start is !int) throw new IllegalArgumentException(start); |
- var length = JS('num', @'#.length', receiver); |
- return Arrays.indexOf(receiver, element, start, length); |
- } else if (receiver is String) { |
- checkNull(element); |
- if (start is !int) throw new IllegalArgumentException(start); |
- if (element is !String) throw new IllegalArgumentException(element); |
- if (start < 0) return -1; // TODO(ahe): Is this correct? |
- return JS('int', @'#.indexOf(#, #)', receiver, element, start); |
- } |
- return UNINTERCEPTED(receiver.indexOf(element, start)); |
-} |
- |
-builtin$insertRange$2(receiver, start, length) { |
- if (isJsArray(receiver)) { |
- return builtin$insertRange$3(receiver, start, length, null); |
- } |
- return UNINTERCEPTED(receiver.insertRange(start, length)); |
-} |
- |
-builtin$insertRange$3(receiver, start, length, initialValue) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.insertRange(start, length, initialValue)); |
- } |
- return listInsertRange(receiver, start, length, initialValue); |
-} |
- |
-listInsertRange(receiver, start, length, initialValue) { |
- if (length === 0) { |
- return; |
- } |
- checkNull(start); // TODO(ahe): This is not specified but co19 tests it. |
- checkNull(length); // TODO(ahe): This is not specified but co19 tests it. |
- if (length is !int) throw new IllegalArgumentException(length); |
- if (length < 0) throw new IllegalArgumentException(length); |
- if (start is !int) throw new IllegalArgumentException(start); |
- |
- var receiverLength = JS('num', @'#.length', receiver); |
- if (start < 0 || start > receiverLength) { |
- throw new IndexOutOfRangeException(start); |
- } |
- receiver.length = receiverLength + length; |
- Arrays.copy(receiver, |
- start, |
- receiver, |
- start + length, |
- receiverLength - start); |
- if (initialValue !== null) { |
- for (int i = start; i < start + length; i++) { |
- receiver[i] = initialValue; |
- } |
- } |
- receiver.length = receiverLength + length; |
-} |
- |
-builtin$last$0(receiver) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.last()); |
- } |
- return receiver[receiver.length - 1]; |
-} |
- |
-builtin$lastIndexOf$1(receiver, element) { |
- if (isJsArray(receiver)) { |
- var start = JS('num', @'#.length', receiver); |
- return Arrays.lastIndexOf(receiver, element, start); |
- } else if (receiver is String) { |
- checkNull(element); |
- if (element is !String) throw new IllegalArgumentException(element); |
- return JS('int', @'#.lastIndexOf(#)', receiver, element); |
- } |
- return UNINTERCEPTED(receiver.lastIndexOf(element)); |
-} |
- |
-builtin$lastIndexOf$2(receiver, element, start) { |
- if (isJsArray(receiver)) { |
- return Arrays.lastIndexOf(receiver, element, start); |
- } else if (receiver is String) { |
- checkNull(element); |
- if (element is !String) throw new IllegalArgumentException(element); |
- if (start !== null) { |
- if (start is !num) throw new IllegalArgumentException(start); |
- if (start < 0) return -1; |
- if (start >= receiver.length) { |
- if (element == "") return receiver.length; |
- start = receiver.length - 1; |
- } |
- } |
- return stringLastIndexOfUnchecked(receiver, element, start); |
- } |
- return UNINTERCEPTED(receiver.lastIndexOf(element, start)); |
-} |
- |
-stringLastIndexOfUnchecked(receiver, element, start) |
- => JS('int', @'#.lastIndexOf(#, #)', receiver, element, start); |
- |
-builtin$removeRange$2(receiver, start, length) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.removeRange(start, length)); |
- } |
- checkGrowable(receiver, 'removeRange'); |
- if (length == 0) { |
- return; |
- } |
- checkNull(start); // TODO(ahe): This is not specified but co19 tests it. |
- checkNull(length); // TODO(ahe): This is not specified but co19 tests it. |
- if (start is !int) throw new IllegalArgumentException(start); |
- if (length is !int) throw new IllegalArgumentException(length); |
- if (length < 0) throw new IllegalArgumentException(length); |
- var receiverLength = JS('num', @'#.length', receiver); |
- if (start < 0 || start >= receiverLength) { |
- throw new IndexOutOfRangeException(start); |
- } |
- if (start + length > receiverLength) { |
- throw new IndexOutOfRangeException(start + length); |
- } |
- Arrays.copy(receiver, |
- start + length, |
- receiver, |
- start, |
- receiverLength - length - start); |
- receiver.length = receiverLength - length; |
-} |
- |
-builtin$setRange$3(receiver, start, length, from) { |
- if (isJsArray(receiver)) { |
- return builtin$setRange$4(receiver, start, length, from, 0); |
- } |
- return UNINTERCEPTED(receiver.setRange(start, length, from)); |
-} |
- |
-builtin$setRange$4(receiver, start, length, from, startFrom) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.setRange(start, length, from, startFrom)); |
- } |
- |
- checkMutable(receiver, 'indexed set'); |
- if (length === 0) return; |
- checkNull(start); // TODO(ahe): This is not specified but co19 tests it. |
- checkNull(length); // TODO(ahe): This is not specified but co19 tests it. |
- checkNull(from); // TODO(ahe): This is not specified but co19 tests it. |
- checkNull(startFrom); // TODO(ahe): This is not specified but co19 tests it. |
- if (start is !int) throw new IllegalArgumentException(start); |
- if (length is !int) throw new IllegalArgumentException(length); |
- if (startFrom is !int) throw new IllegalArgumentException(startFrom); |
- if (length < 0) throw new IllegalArgumentException(length); |
- if (start < 0) throw new IndexOutOfRangeException(start); |
- if (start + length > receiver.length) { |
- throw new IndexOutOfRangeException(start + length); |
- } |
- |
- Arrays.copy(from, startFrom, receiver, start, length); |
-} |
- |
-builtin$some$1(receiver, f) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.some(f)); |
- } else { |
- return Collections.some(receiver, f); |
- } |
-} |
- |
-builtin$every$1(receiver, f) { |
- if (!isJsArray(receiver)) { |
- return UNINTERCEPTED(receiver.every(f)); |
- } else { |
- return Collections.every(receiver, f); |
- } |
-} |
- |
-builtin$sort$1(receiver, compare) { |
- if (!isJsArray(receiver)) return UNINTERCEPTED(receiver.sort(compare)); |
- |
- checkMutable(receiver, 'sort'); |
- DualPivotQuicksort.sort(receiver, compare); |
-} |
- |
-checkNull(object) { |
- if (object === null) throw new NullPointerException(); |
- return object; |
-} |
- |
-checkNum(value) { |
- if (value is !num) { |
- checkNull(value); |
- throw new IllegalArgumentException(value); |
- } |
- return value; |
-} |
- |
-checkInt(value) { |
- if (value is !int) { |
- checkNull(value); |
- throw new IllegalArgumentException(value); |
- } |
- return value; |
-} |
- |
-checkBool(value) { |
- if (value is !bool) { |
- checkNull(value); |
- throw new IllegalArgumentException(value); |
- } |
- return value; |
-} |
- |
-checkString(value) { |
- if (value is !String) { |
- checkNull(value); |
- throw new IllegalArgumentException(value); |
- } |
- return value; |
-} |
- |
-builtin$isNegative$0(receiver) { |
- if (receiver is num) { |
- return (receiver === 0) ? (1 / receiver) < 0 : receiver < 0; |
- } else { |
- return UNINTERCEPTED(receiver.isNegative()); |
- } |
-} |
- |
-builtin$isNaN$0(receiver) { |
- if (receiver is num) { |
- return JS('bool', @'isNaN(#)', receiver); |
- } else { |
- return UNINTERCEPTED(receiver.isNegative()); |
- } |
-} |
- |
-builtin$remainder$1(a, b) { |
- if (checkNumbers(a, b)) { |
- return JS('num', @'# % #', a, b); |
- } else { |
- return UNINTERCEPTED(a.remainder(b)); |
- } |
-} |
- |
-builtin$abs$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.abs()); |
- |
- return JS('num', @'Math.abs(#)', receiver); |
-} |
- |
-builtin$toInt$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.toInt()); |
- |
- if (receiver.isNaN()) throw new BadNumberFormatException('NaN'); |
- |
- if (receiver.isInfinite()) throw new BadNumberFormatException('Infinity'); |
- |
- var truncated = receiver.truncate(); |
- return JS('bool', @'# == -0.0', truncated) ? 0 : truncated; |
-} |
- |
-builtin$ceil$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.ceil()); |
- |
- return JS('num', @'Math.ceil(#)', receiver); |
-} |
- |
-builtin$floor$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.floor()); |
- |
- return JS('num', @'Math.floor(#)', receiver); |
-} |
- |
-builtin$isInfinite$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.isInfinite()); |
- |
- return JS('bool', @'# == Infinity', receiver) |
- || JS('bool', @'# == -Infinity', receiver); |
-} |
- |
-builtin$negate$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.negate()); |
- |
- return JS('num', @'-#', receiver); |
-} |
- |
-builtin$round$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.round()); |
- |
- if (JS('bool', @'# < 0', receiver)) { |
- return JS('num', @'-Math.round(-#)', receiver); |
- } else { |
- return JS('num', @'Math.round(#)', receiver); |
- } |
-} |
- |
-builtin$toDouble$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.toDouble()); |
- |
- // TODO(ahe): Just return receiver? |
- return JS('double', @'# + 0', receiver); |
-} |
- |
-builtin$truncate$0(receiver) { |
- if (receiver is !num) return UNINTERCEPTED(receiver.truncate()); |
- |
- return receiver < 0 ? receiver.ceil() : receiver.floor(); |
-} |
- |
-builtin$toStringAsFixed$1(receiver, fractionDigits) { |
- if (receiver is !num) { |
- return UNINTERCEPTED(receiver.toStringAsFixed(fractionDigits)); |
- } |
- checkNum(fractionDigits); |
- |
- String result = JS('String', @'#.toFixed(#)', receiver, fractionDigits); |
- if (receiver == 0 && receiver.isNegative()) return "-$result"; |
- return result; |
-} |
- |
-builtin$toStringAsExponential$1(receiver, fractionDigits) { |
- if (receiver is !num) { |
- return UNINTERCEPTED(receiver.toStringAsExponential(fractionDigits)); |
- } |
- if (fractionDigits !== null) checkNum(fractionDigits); |
- |
- String result = JS('String', @'#.toExponential(#)', |
- receiver, fractionDigits); |
- if (receiver == 0 && receiver.isNegative()) return "-$result"; |
- return result; |
-} |
- |
-builtin$toStringAsPrecision$1(receiver, fractionDigits) { |
- if (receiver is !num) { |
- return UNINTERCEPTED(receiver.toStringAsPrecision(fractionDigits)); |
- } |
- checkNum(fractionDigits); |
- |
- String result = JS('String', @'#.toPrecision(#)', |
- receiver, fractionDigits); |
- if (receiver == 0 && receiver.isNegative()) return "-$result"; |
- return result; |
-} |
- |
-builtin$toRadixString$1(receiver, radix) { |
- if (receiver is !num) { |
- return UNINTERCEPTED(receiver.toRadixString(radix)); |
- } |
- checkNum(radix); |
- |
- return JS('String', @'#.toString(#)', receiver, radix); |
-} |
- |
-builtin$allMatches$1(receiver, str) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.allMatches(str)); |
- checkString(str); |
- return allMatchesInStringUnchecked(receiver, str); |
-} |
- |
-builtin$concat$1(receiver, other) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.concat(other)); |
- |
- if (other is !String) throw new IllegalArgumentException(other); |
- return JS('String', @'# + #', receiver, other); |
-} |
- |
-builtin$contains$1(receiver, other) { |
- if (receiver is !String) { |
- return UNINTERCEPTED(receiver.contains(other)); |
- } |
- return builtin$contains$2(receiver, other, 0); |
-} |
- |
-builtin$contains$2(receiver, other, startIndex) { |
- if (receiver is !String) { |
- return UNINTERCEPTED(receiver.contains(other, startIndex)); |
- } |
- checkNull(other); |
- return stringContainsUnchecked(receiver, other, startIndex); |
-} |
- |
-builtin$endsWith$1(receiver, other) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.endsWith(other)); |
- |
- checkString(other); |
- int receiverLength = receiver.length; |
- int otherLength = other.length; |
- if (otherLength > receiverLength) return false; |
- return other == receiver.substring(receiverLength - otherLength); |
-} |
- |
-builtin$replaceAll$2(receiver, from, to) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.replaceAll(from, to)); |
- |
- checkString(to); |
- return stringReplaceAllUnchecked(receiver, from, to); |
-} |
- |
-builtin$replaceFirst$2(receiver, from, to) { |
- if (receiver is !String) { |
- return UNINTERCEPTED(receiver.replaceFirst(from, to)); |
- } |
- checkString(to); |
- return stringReplaceFirstUnchecked(receiver, from, to); |
-} |
- |
-builtin$split$1(receiver, pattern) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.split(pattern)); |
- checkNull(pattern); |
- return stringSplitUnchecked(receiver, pattern); |
-} |
- |
-builtin$splitChars$0(receiver) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.splitChars()); |
- |
- return JS('List', @'#.split("")', receiver); |
-} |
- |
-builtin$startsWith$1(receiver, other) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.startsWith(other)); |
- checkString(other); |
- |
- int length = other.length; |
- if (length > receiver.length) return false; |
- return JS('bool', @'# == #', other, |
- JS('String', @'#.substring(0, #)', receiver, length)); |
-} |
- |
-builtin$substring$1(receiver, startIndex) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.substring(startIndex)); |
- |
- return builtin$substring$2(receiver, startIndex, null); |
-} |
- |
-builtin$substring$2(receiver, startIndex, endIndex) { |
- if (receiver is !String) { |
- return UNINTERCEPTED(receiver.substring(startIndex, endIndex)); |
- } |
- checkNum(startIndex); |
- var length = receiver.length; |
- if (endIndex === null) endIndex = length; |
- checkNum(endIndex); |
- if (startIndex < 0 ) throw new IndexOutOfRangeException(startIndex); |
- if (startIndex > endIndex) throw new IndexOutOfRangeException(startIndex); |
- if (endIndex > length) throw new IndexOutOfRangeException(endIndex); |
- return substringUnchecked(receiver, startIndex, endIndex); |
-} |
- |
-substringUnchecked(receiver, startIndex, endIndex) |
- => JS('String', @'#.substring(#, #)', receiver, startIndex, endIndex); |
- |
- |
-builtin$toLowerCase$0(receiver) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.toLowerCase()); |
- |
- return JS('String', @'#.toLowerCase()', receiver); |
-} |
- |
-builtin$toUpperCase$0(receiver) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.toUpperCase()); |
- |
- return JS('String', @'#.toUpperCase()', receiver); |
-} |
- |
-builtin$trim$0(receiver) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.trim()); |
- |
- return JS('String', @'#.trim()', receiver); |
-} |
- |
-class MathNatives { |
- static int parseInt(str) { |
- checkString(str); |
- if (!JS('bool', |
- @'/^\s*[+-]?(?:0[xX][abcdefABCDEF0-9]+|\d+)\s*$/.test(#)', |
- str)) { |
- throw new BadNumberFormatException(str); |
- } |
- var trimmed = str.trim(); |
- var base = 10;; |
- if ((trimmed.length > 2 && (trimmed[1] == 'x' || trimmed[1] == 'X')) || |
- (trimmed.length > 3 && (trimmed[2] == 'x' || trimmed[2] == 'X'))) { |
- base = 16; |
- } |
- var ret = JS('num', @'parseInt(#, #)', trimmed, base); |
- if (ret.isNaN()) throw new BadNumberFormatException(str); |
- return ret; |
- } |
- |
- static double parseDouble(String str) { |
- checkString(str); |
- var ret = JS('num', @'parseFloat(#)', str); |
- if (ret == 0 && (str.startsWith("0x") || str.startsWith("0X"))) { |
- // TODO(ahe): This is unspecified, but tested by co19. |
- ret = JS('num', @'parseInt(#)', str); |
- } |
- if (ret.isNaN() && str != 'NaN' && str != '-NaN') { |
- throw new BadNumberFormatException(str); |
- } |
- return ret; |
- } |
- |
- static double sqrt(num value) |
- => JS('double', @'Math.sqrt(#)', checkNum(value)); |
- |
- static double sin(num value) |
- => JS('double', @'Math.sin(#)', checkNum(value)); |
- |
- static double cos(num value) |
- => JS('double', @'Math.cos(#)', checkNum(value)); |
- |
- static double tan(num value) |
- => JS('double', @'Math.tan(#)', checkNum(value)); |
- |
- static double acos(num value) |
- => JS('double', @'Math.acos(#)', checkNum(value)); |
- |
- static double asin(num value) |
- => JS('double', @'Math.asin(#)', checkNum(value)); |
- |
- static double atan(num value) |
- => JS('double', @'Math.atan(#)', checkNum(value)); |
- |
- static double atan2(num a, num b) |
- => JS('double', @'Math.atan2(#, #)', checkNum(a), checkNum(b)); |
- |
- static double exp(num value) |
- => JS('double', @'Math.exp(#)', checkNum(value)); |
- |
- static double log(num value) |
- => JS('double', @'Math.log(#)', checkNum(value)); |
- |
- static num pow(num value, num exponent) { |
- checkNum(value); |
- checkNum(exponent); |
- return JS('num', @'Math.pow(#, #)', value, exponent); |
- } |
- |
- static double random() => JS('double', @'Math.random()'); |
-} |
- |
-/** |
- * This is the [Jenkins hash function][1] but using masking to keep |
- * values in SMI range. This was inspired by jmesserly's work in |
- * Frog. |
- * |
- * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function |
- */ |
-builtin$hashCode$0(receiver) { |
- // TODO(ahe): This method shouldn't have to use JS. Update when our |
- // optimizations are smarter. |
- if (receiver is num) return JS('int', @'# & 0x1FFFFFFF', receiver); |
- if (receiver is !String) return UNINTERCEPTED(receiver.hashCode()); |
- int hash = 0; |
- int length = JS('int', @'#.length', receiver); |
- for (int i = 0; i < length; i++) { |
- hash = 0x1fffffff & (hash + JS('int', @'#.charCodeAt(#)', receiver, i)); |
- hash = 0x1fffffff & (hash + JS('int', @'# << #', 0x0007ffff & hash, 10)); |
- hash ^= hash >> 6; |
- } |
- hash = 0x1fffffff & (hash + JS('int', @'# << #', 0x03ffffff & hash, 3)); |
- hash ^= hash >> 11; |
- return 0x1fffffff & (hash + JS('int', @'# << #', 0x00003fff & hash, 15)); |
-} |
- |
-// TODO(ahe): Dynamic may be overridden. |
-builtin$get$dynamic(receiver) => receiver; |
- |
-/** |
- * Called by generated code to capture the stacktrace before throwing |
- * an exception. |
- */ |
-captureStackTrace(ex) { |
- var jsError = JS('Object', @'new Error()'); |
- JS('void', @'#.dartException = #', jsError, ex); |
- JS('void', @'''#.toString = #''', jsError, DART_CLOSURE_TO_JS(toStringWrapper)); |
- return jsError; |
-} |
- |
-/** |
- * This method is installed as JavaScript toString method on exception |
- * objects in [captureStackTrace]. So JavaScript 'this' binds to an |
- * instance of JavaScript Error to which we have added a property |
- * 'dartException' which holds a Dart object. |
- */ |
-toStringWrapper() => JS('Object', @'this.dartException').toString(); |
- |
-builtin$charCodes$0(receiver) { |
- if (receiver is !String) return UNINTERCEPTED(receiver.charCodes()); |
- int len = receiver.length; |
- List<int> result = new List<int>(len); |
- for (int i = 0; i < len; i++) { |
- result[i] = receiver.charCodeAt(i); |
- } |
- return result; |
-} |
- |
-makeLiteralListConst(list) { |
- JS('bool', @'#.immutable$list = #', list, true); |
- JS('bool', @'#.fixed$length = #', list, true); |
- return list; |
-} |
- |
-/** |
- * Called from catch blocks in generated code to extract the Dart |
- * exception from the thrown value. The thrown value may have been |
- * created by [captureStackTrace] or it may be a 'native' JS |
- * exception. |
- * |
- * Some native exceptions are mapped to new Dart instances, others are |
- * returned unmodified. |
- */ |
-unwrapException(ex) { |
- // Note that we are checking if the object has the property. If it |
- // has, it could be set to null if the thrown value is null. |
- if (JS('bool', @'"dartException" in #', ex)) { |
- return JS('Object', @'#.dartException', ex); |
- } else if (JS('bool', @'# instanceof TypeError', ex)) { |
- // TODO(ahe): ex.type is Chrome specific. |
- var type = JS('String', @'#.type', ex); |
- var jsArguments = JS('Object', @'#.arguments', ex); |
- var name = jsArguments[0]; |
- if (type == 'property_not_function' || |
- type == 'called_non_callable' || |
- type == 'non_object_property_call' || |
- type == 'non_object_property_load') { |
- if (name !== null && name.startsWith(@'$call$')) { |
- return new ObjectNotClosureException(); |
- } else { |
- return new NullPointerException(); |
- } |
- } else if (type == 'undefined_method') { |
- if (name is String && name.startsWith(@'$call$')) { |
- return new ObjectNotClosureException(); |
- } else { |
- return new NoSuchMethodException('', name, []); |
- } |
- } |
- } else if (JS('bool', @'# instanceof RangeError', ex)) { |
- var message = JS('String', @'#.message', ex); |
- if (message.contains('call stack')) { |
- return new StackOverflowException(); |
- } |
- } |
- return ex; |
-} |
- |
-/** |
- * Called by generated code to fetch the stack trace from an |
- * exception. |
- */ |
-StackTrace getTraceFromException(exception) { |
- return new StackTrace(JS("var", @"#.stack", exception)); |
-} |
- |
-class StackTrace { |
- var stack; |
- StackTrace(this.stack); |
- String toString() => stack != null ? stack : ''; |
-} |
- |
- |
-/** |
- * Called by generated code to build a map literal. [keyValuePairs] is |
- * a list of key, value, key, value, ..., etc. |
- */ |
-makeLiteralMap(List keyValuePairs) { |
- Iterator iterator = keyValuePairs.iterator(); |
- Map result = new LinkedHashMap(); |
- while (iterator.hasNext()) { |
- String key = iterator.next(); |
- var value = iterator.next(); |
- result[key] = value; |
- } |
- return result; |
-} |
- |
-invokeClosure(Function closure, |
- var isolate, |
- int numberOfArguments, |
- var arg1, |
- var arg2) { |
- if (numberOfArguments == 0) { |
- return JS_CALL_IN_ISOLATE(isolate, () => closure()); |
- } else if (numberOfArguments == 1) { |
- return JS_CALL_IN_ISOLATE(isolate, () => closure(arg1)); |
- } else if (numberOfArguments == 2) { |
- return JS_CALL_IN_ISOLATE(isolate, () => closure(arg1, arg2)); |
- } else { |
- throw new Exception( |
- 'Unsupported number of arguments for wrapped closure'); |
- } |
-} |
- |
-/** |
- * Called by generated code to convert a Dart closure to a JS |
- * closure when the Dart closure is passed to the DOM. |
- */ |
-convertDartClosureToJS(closure) { |
- if (closure === null) return null; |
- var function = JS('var', @'#.$identity', closure); |
- if (JS('bool', @'!!#', function)) return function; |
- |
- function = JS("var", @"""function() { |
- return #(#, #, arguments.length, arguments[0], arguments[1]); |
- }""", |
- DART_CLOSURE_TO_JS(invokeClosure), |
- closure, |
- JS_CURRENT_ISOLATE()); |
- |
- JS('void', @'#.$identity = #', closure, function); |
- return function; |
-} |
- |
-/** |
- * Super class for Dart closures. |
- */ |
-class Closure implements Function { |
- String toString() => "Closure"; |
-} |
- |
-bool jsHasOwnProperty(var jsObject, String property) { |
- return JS('bool', @'#.hasOwnProperty(#)', jsObject, property); |
-} |
- |
-jsPropertyAccess(var jsObject, String property) { |
- return JS('var', @'#[#]', jsObject, property); |
-} |
- |
-/** |
- * Called at the end of unaborted switch cases to get the singleton |
- * FallThroughError exception that will be thrown. |
- */ |
-getFallThroughError() => const FallThroughError(); |
- |
-builtin$isEven$0(receiver) { |
- if (receiver is !int) return UNINTERCEPTED(receiver.isEven()); |
- return (receiver & 1) === 0; |
-} |
- |
-builtin$isOdd$0(receiver) { |
- if (receiver is !int) return UNINTERCEPTED(receiver.isOdd()); |
- return (receiver & 1) === 1; |
-} |
- |
-/** |
- * Represents the type Dynamic. The compiler treats this specially. |
- */ |
-interface Dynamic { |
-} |
- |
-/** |
- * Represents the type of Null. The compiler treats this specially. |
- */ |
-class Null { |
- factory Null() { |
- throw new UnsupportedOperationException('new Null()'); |
- } |
-} |
- |
-builtin$get$toString(receiver) => () => builtin$toString$0(receiver); |