| Index: sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
|
| ===================================================================
|
| --- sdk/lib/_internal/compiler/implementation/lib/js_helper.dart (revision 23664)
|
| +++ sdk/lib/_internal/compiler/implementation/lib/js_helper.dart (working copy)
|
| @@ -1,1458 +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 'dart:collection';
|
| -import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
|
| - JS,
|
| - JS_CALL_IN_ISOLATE,
|
| - JS_CURRENT_ISOLATE,
|
| - JS_CURRENT_ISOLATE_CONTEXT,
|
| - JS_DART_OBJECT_CONSTRUCTOR,
|
| - JS_IS_INDEXABLE_FIELD_NAME,
|
| - JS_OBJECT_CLASS_NAME,
|
| - JS_OPERATOR_AS_PREFIX,
|
| - JS_OPERATOR_IS_PREFIX,
|
| - RAW_DART_FUNCTION_REF;
|
| -import 'dart:_interceptors';
|
| -import "dart:_collection-dev" as _symbol_dev;
|
| -
|
| -part 'constant_map.dart';
|
| -part 'native_helper.dart';
|
| -part 'regexp_helper.dart';
|
| -part 'string_helper.dart';
|
| -part 'js_rti.dart';
|
| -
|
| -bool isJsArray(var value) {
|
| - return value != null && JS('bool', r'(#.constructor === Array)', value);
|
| -}
|
| -
|
| -bool isJsIndexable(var object, var record) {
|
| - if (record != null) {
|
| - var result = dispatchRecordIndexability(record);
|
| - if (result != null) return result;
|
| - }
|
| - return object is JavaScriptIndexingBehavior;
|
| -}
|
| -
|
| -String S(value) {
|
| - if (value is String) return value;
|
| - if (value is num) {
|
| - if (value != 0) {
|
| - // ""+x is faster than String(x) for integers on most browsers.
|
| - return JS('String', r'"" + (#)', value);
|
| - }
|
| - } else if (true == value) {
|
| - return 'true';
|
| - } else if (false == value) {
|
| - return 'false';
|
| - } else if (value == null) {
|
| - return 'null';
|
| - }
|
| - var res = value.toString();
|
| - if (res is !String) throw new ArgumentError(value);
|
| - return res;
|
| -}
|
| -
|
| -createInvocationMirror(name, internalName, type, arguments, argumentNames) {
|
| - return new JSInvocationMirror(new _symbol_dev.Symbol.unvalidated(name),
|
| - internalName,
|
| - type,
|
| - arguments,
|
| - argumentNames);
|
| -}
|
| -
|
| -class JSInvocationMirror implements Invocation {
|
| - static const METHOD = 0;
|
| - static const GETTER = 1;
|
| - static const SETTER = 2;
|
| -
|
| - final Symbol memberName;
|
| - final String _internalName;
|
| - final int _kind;
|
| - final List _arguments;
|
| - final List _namedArgumentNames;
|
| - /** Map from argument name to index in _arguments. */
|
| - Map<String,dynamic> _namedIndices = null;
|
| -
|
| - JSInvocationMirror(this.memberName,
|
| - this._internalName,
|
| - this._kind,
|
| - this._arguments,
|
| - this._namedArgumentNames);
|
| -
|
| - bool get isMethod => _kind == METHOD;
|
| - bool get isGetter => _kind == GETTER;
|
| - bool get isSetter => _kind == SETTER;
|
| - bool get isAccessor => _kind != METHOD;
|
| -
|
| - List get positionalArguments {
|
| - if (isGetter) return null;
|
| - var list = [];
|
| - var argumentCount =
|
| - _arguments.length - _namedArgumentNames.length;
|
| - for (var index = 0 ; index < argumentCount ; index++) {
|
| - list.add(_arguments[index]);
|
| - }
|
| - return list;
|
| - }
|
| -
|
| - Map<Symbol,dynamic> get namedArguments {
|
| - if (isAccessor) return null;
|
| - var map = new Map<Symbol, dynamic>();
|
| - int namedArgumentCount = _namedArgumentNames.length;
|
| - int namedArgumentsStartIndex = _arguments.length - namedArgumentCount;
|
| - for (int i = 0; i < namedArgumentCount; i++) {
|
| - map[new _symbol_dev.Symbol.unvalidated(_namedArgumentNames[i])] =
|
| - _arguments[namedArgumentsStartIndex + i];
|
| - }
|
| - return map;
|
| - }
|
| -
|
| - _invokeOn(Object object) {
|
| - var interceptor = getInterceptor(object);
|
| - var receiver = object;
|
| - var name = _internalName;
|
| - var arguments = _arguments;
|
| - // TODO(ngeoffray): If this functionality ever become performance
|
| - // critical, we might want to dynamically change [interceptedNames]
|
| - // to be a JavaScript object with intercepted names as property
|
| - // instead of a JavaScript array.
|
| - if (JS('int', '#.indexOf(#)', interceptedNames, name) == -1) {
|
| - if (!isJsArray(arguments)) arguments = new List.from(arguments);
|
| - } else {
|
| - arguments = [object]..addAll(arguments);
|
| - receiver = interceptor;
|
| - }
|
| - var method = JS('var', '#[#]', receiver, name);
|
| - if (JS('String', 'typeof #', method) == 'function') {
|
| - return JS("var", "#.apply(#, #)", method, receiver, arguments);
|
| - } else {
|
| - // In this case, receiver doesn't implement name. So we should
|
| - // invoke noSuchMethod instead (which will often throw a
|
| - // NoSuchMethodError).
|
| - return receiver.noSuchMethod(this);
|
| - }
|
| - }
|
| -
|
| - /// This method is called by [InstanceMirror.delegate].
|
| - static invokeFromMirror(JSInvocationMirror invocation, victim) {
|
| - return invocation._invokeOn(victim);
|
| - }
|
| -}
|
| -
|
| -class Primitives {
|
| - static int objectHashCode(object) {
|
| - int hash = JS('int|Null', r'#.$identityHash', object);
|
| - if (hash == null) {
|
| - hash = JS('int', '(Math.random() * 0x3fffffff) | 0');
|
| - JS('void', r'#.$identityHash = #', object, hash);
|
| - }
|
| - return JS('int', '#', hash);
|
| - }
|
| -
|
| - /**
|
| - * This is the low-level method that is used to implement
|
| - * [print]. It is possible to override this function from JavaScript
|
| - * by defining a function in JavaScript called "dartPrint".
|
| - */
|
| - static void printString(String string) {
|
| - if (JS('bool', r'typeof dartPrint == "function"')) {
|
| - // Support overriding print from JavaScript.
|
| - JS('void', r'dartPrint(#)', string);
|
| - return;
|
| - }
|
| -
|
| - // Inside browser.
|
| - if (JS('bool', r'typeof window == "object"')) {
|
| - // On IE, the console is only defined if dev tools is open.
|
| - if (JS('bool', r'typeof console == "object"')) {
|
| - JS('void', r'console.log(#)', string);
|
| - }
|
| - return;
|
| - }
|
| -
|
| - // Running in d8, the V8 developer shell, or in Firefox' js-shell.
|
| - if (JS('bool', r'typeof print == "function"')) {
|
| - JS('void', r'print(#)', string);
|
| - return;
|
| - }
|
| -
|
| - // This is somewhat nasty, but we don't want to drag in a bunch of
|
| - // dependencies to handle a situation that cannot happen. So we
|
| - // avoid using Dart [:throw:] and Dart [toString].
|
| - JS('void', 'throw "Unable to print message: " + String(#)', string);
|
| - }
|
| -
|
| - static void _throwFormatException(String string) {
|
| - throw new FormatException(string);
|
| - }
|
| -
|
| - static int parseInt(String source,
|
| - int radix,
|
| - int handleError(String source)) {
|
| - if (handleError == null) handleError = _throwFormatException;
|
| -
|
| - checkString(source);
|
| - var match = JS('=List|Null',
|
| - r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i.exec(#)',
|
| - source);
|
| - int digitsIndex = 1;
|
| - int hexIndex = 2;
|
| - int decimalIndex = 3;
|
| - int nonDecimalHexIndex = 4;
|
| - if (radix == null) {
|
| - radix = 10;
|
| - if (match != null) {
|
| - if (match[hexIndex] != null) {
|
| - // Cannot fail because we know that the digits are all hex.
|
| - return JS('num', r'parseInt(#, 16)', source);
|
| - }
|
| - if (match[decimalIndex] != null) {
|
| - // Cannot fail because we know that the digits are all decimal.
|
| - return JS('num', r'parseInt(#, 10)', source);
|
| - }
|
| - return handleError(source);
|
| - }
|
| - } else {
|
| - if (radix is! int) throw new ArgumentError("Radix is not an integer");
|
| - if (radix < 2 || radix > 36) {
|
| - throw new RangeError("Radix $radix not in range 2..36");
|
| - }
|
| - if (match != null) {
|
| - if (radix == 10 && match[decimalIndex] != null) {
|
| - // Cannot fail because we know that the digits are all decimal.
|
| - return JS('num', r'parseInt(#, 10)', source);
|
| - }
|
| - if (radix < 10 || match[decimalIndex] == null) {
|
| - // We know that the characters must be ASCII as otherwise the
|
| - // regexp wouldn't have matched. Calling toLowerCase is thus
|
| - // guaranteed to be a safe operation. If it wasn't ASCII, then
|
| - // "İ" would become "i", and we would accept it for radices greater
|
| - // than 18.
|
| - int maxCharCode;
|
| - if (radix <= 10) {
|
| - // Allow all digits less than the radix. For example 0, 1, 2 for
|
| - // radix 3.
|
| - // "0".codeUnitAt(0) + radix - 1;
|
| - maxCharCode = 0x30 + radix - 1;
|
| - } else {
|
| - // Characters are located after the digits in ASCII. Therefore we
|
| - // only check for the character code. The regexp above made already
|
| - // sure that the string does not contain anything but digits or
|
| - // characters.
|
| - // "0".codeUnitAt(0) + radix - 1;
|
| - maxCharCode = 0x61 + radix - 10 - 1;
|
| - }
|
| - String digitsPart = match[digitsIndex].toLowerCase();
|
| - for (int i = 0; i < digitsPart.length; i++) {
|
| - if (digitsPart.codeUnitAt(i) > maxCharCode) {
|
| - return handleError(source);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - if (match == null) return handleError(source);
|
| - return JS('num', r'parseInt(#, #)', source, radix);
|
| - }
|
| -
|
| - static double parseDouble(String source, double handleError(String source)) {
|
| - checkString(source);
|
| - if (handleError == null) handleError = _throwFormatException;
|
| - // Notice that JS parseFloat accepts garbage at the end of the string.
|
| - // Accept only:
|
| - // - [+/-]NaN
|
| - // - [+/-]Infinity
|
| - // - a Dart double literal
|
| - // We do allow leading or trailing whitespace.
|
| - if (!JS('bool',
|
| - r'/^\s*[+-]?(?:Infinity|NaN|'
|
| - r'(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(#)',
|
| - source)) {
|
| - return handleError(source);
|
| - }
|
| - var result = JS('num', r'parseFloat(#)', source);
|
| - if (result.isNaN) {
|
| - var trimmed = source.trim();
|
| - if (trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN') {
|
| - return result;
|
| - }
|
| - return handleError(source);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - /** [: r"$".codeUnitAt(0) :] */
|
| - static const int DOLLAR_CHAR_VALUE = 36;
|
| -
|
| - /// Creates a string containing the complete type for the class [className]
|
| - /// with the given type arguments.
|
| - static String formatType(String className, List typeArguments) {
|
| - return '$className${joinArguments(typeArguments, 0)}';
|
| - }
|
| -
|
| - /// Returns the type of [object] as a string (including type arguments).
|
| - static String objectTypeName(Object object) {
|
| - String name = constructorNameFallback(getInterceptor(object));
|
| - if (name == 'Object') {
|
| - // Try to decompile the constructor by turning it into a string
|
| - // and get the name out of that. If the decompiled name is a
|
| - // string, we use that instead of the very generic 'Object'.
|
| - var decompiled = JS('var', r'#.match(/^\s*function\s*(\S*)\s*\(/)[1]',
|
| - JS('var', r'String(#.constructor)', object));
|
| - if (decompiled is String) name = decompiled;
|
| - }
|
| - // TODO(kasperl): If the namer gave us a fresh global name, we may
|
| - // want to remove the numeric suffix that makes it unique too.
|
| - if (identical(name.codeUnitAt(0), DOLLAR_CHAR_VALUE)) {
|
| - name = name.substring(1);
|
| - }
|
| - return formatType(name, getRuntimeTypeInfo(object));
|
| - }
|
| -
|
| - static String objectToString(Object object) {
|
| - String name = objectTypeName(object);
|
| - return "Instance of '$name'";
|
| - }
|
| -
|
| - static List newGrowableList(length) {
|
| - return JS('=List', r'new Array(#)', length);
|
| - }
|
| -
|
| - static List newFixedList(length) {
|
| - var result = JS('=List', r'new Array(#)', length);
|
| - JS('void', r'#.fixed$length = #', result, true);
|
| - return result;
|
| - }
|
| -
|
| - static num dateNow() => JS('num', r'Date.now()');
|
| -
|
| - static num numMicroseconds() {
|
| - if (JS('bool', 'typeof window != "undefined" && window !== null')) {
|
| - var performance = JS('var', 'window.performance');
|
| - if (performance != null &&
|
| - JS('bool', 'typeof #.webkitNow == "function"', performance)) {
|
| - return (1000 * JS('num', '#.webkitNow()', performance)).floor();
|
| - }
|
| - }
|
| - return 1000 * dateNow();
|
| - }
|
| -
|
| - // This is to avoid stack overflows due to very large argument arrays in
|
| - // apply(). It fixes http://dartbug.com/6919
|
| - static String _fromCharCodeApply(List<int> array) {
|
| - String result = "";
|
| - const kMaxApply = 500;
|
| - int end = array.length;
|
| - for (var i = 0; i < end; i += kMaxApply) {
|
| - var subarray;
|
| - if (end <= kMaxApply) {
|
| - subarray = array;
|
| - } else {
|
| - subarray = JS('=List', r'#.slice(#, #)', array,
|
| - i, i + kMaxApply < end ? i + kMaxApply : end);
|
| - }
|
| - result = JS('String', '# + String.fromCharCode.apply(#, #)',
|
| - result, null, subarray);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - static String stringFromCodePoints(codePoints) {
|
| - List<int> a = <int>[];
|
| - for (var i in codePoints) {
|
| - if (i is !int) throw new ArgumentError(i);
|
| - if (i <= 0xffff) {
|
| - a.add(i);
|
| - } else if (i <= 0x10ffff) {
|
| - a.add(0xd800 + ((((i - 0x10000) >> 10) & 0x3ff)));
|
| - a.add(0xdc00 + (i & 0x3ff));
|
| - } else {
|
| - throw new ArgumentError(i);
|
| - }
|
| - }
|
| - return _fromCharCodeApply(a);
|
| - }
|
| -
|
| - static String stringFromCharCodes(charCodes) {
|
| - for (var i in charCodes) {
|
| - if (i is !int) throw new ArgumentError(i);
|
| - if (i < 0) throw new ArgumentError(i);
|
| - if (i > 0xffff) return stringFromCodePoints(charCodes);
|
| - }
|
| - return _fromCharCodeApply(charCodes);
|
| - }
|
| -
|
| - static String stringConcatUnchecked(String string1, String string2) {
|
| - return JS('String', r'# + #', string1, string2);
|
| - }
|
| -
|
| - static String getTimeZoneName(receiver) {
|
| - // When calling toString on a Date it will emit the timezone in parenthesis.
|
| - // Example: "Wed May 16 2012 21:13:00 GMT+0200 (CEST)".
|
| - // We extract this name using a regexp.
|
| - var d = lazyAsJsDate(receiver);
|
| - return JS('String', r'/\((.*)\)/.exec(#.toString())[1]', d);
|
| - }
|
| -
|
| - static int getTimeZoneOffsetInMinutes(receiver) {
|
| - // Note that JS and Dart disagree on the sign of the offset.
|
| - return -JS('int', r'#.getTimezoneOffset()', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static valueFromDecomposedDate(years, month, day, hours, minutes, seconds,
|
| - milliseconds, isUtc) {
|
| - final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
|
| - checkInt(years);
|
| - checkInt(month);
|
| - checkInt(day);
|
| - checkInt(hours);
|
| - checkInt(minutes);
|
| - checkInt(seconds);
|
| - checkInt(milliseconds);
|
| - checkBool(isUtc);
|
| - var jsMonth = month - 1;
|
| - var value;
|
| - if (isUtc) {
|
| - value = JS('num', r'Date.UTC(#, #, #, #, #, #, #)',
|
| - years, jsMonth, day, hours, minutes, seconds, milliseconds);
|
| - } else {
|
| - value = JS('num', r'new Date(#, #, #, #, #, #, #).valueOf()',
|
| - years, jsMonth, day, hours, minutes, seconds, milliseconds);
|
| - }
|
| - if (value.isNaN ||
|
| - value < -MAX_MILLISECONDS_SINCE_EPOCH ||
|
| - value > MAX_MILLISECONDS_SINCE_EPOCH) {
|
| - throw new ArgumentError();
|
| - }
|
| - if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc);
|
| - return value;
|
| - }
|
| -
|
| - static patchUpY2K(value, years, isUtc) {
|
| - var date = JS('', r'new Date(#)', value);
|
| - if (isUtc) {
|
| - JS('num', r'#.setUTCFullYear(#)', date, years);
|
| - } else {
|
| - JS('num', r'#.setFullYear(#)', date, years);
|
| - }
|
| - return JS('num', r'#.valueOf()', date);
|
| - }
|
| -
|
| - // Lazily keep a JS Date stored in the JS object.
|
| - static lazyAsJsDate(receiver) {
|
| - if (JS('bool', r'#.date === (void 0)', receiver)) {
|
| - JS('void', r'#.date = new Date(#)', receiver,
|
| - receiver.millisecondsSinceEpoch);
|
| - }
|
| - return JS('var', r'#.date', receiver);
|
| - }
|
| -
|
| - // The getters for date and time parts below add a positive integer to ensure
|
| - // that the result is really an integer, because the JavaScript implementation
|
| - // may return -0.0 instead of 0.
|
| -
|
| - static getYear(receiver) {
|
| - return (receiver.isUtc)
|
| - ? JS('int', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver))
|
| - : JS('int', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static getMonth(receiver) {
|
| - return (receiver.isUtc)
|
| - ? JS('int', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver))
|
| - : JS('int', r'#.getMonth() + 1', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static getDay(receiver) {
|
| - return (receiver.isUtc)
|
| - ? JS('int', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver))
|
| - : JS('int', r'(#.getDate() + 0)', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static getHours(receiver) {
|
| - return (receiver.isUtc)
|
| - ? JS('int', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver))
|
| - : JS('int', r'(#.getHours() + 0)', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static getMinutes(receiver) {
|
| - return (receiver.isUtc)
|
| - ? JS('int', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver))
|
| - : JS('int', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static getSeconds(receiver) {
|
| - return (receiver.isUtc)
|
| - ? JS('int', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver))
|
| - : JS('int', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static getMilliseconds(receiver) {
|
| - return (receiver.isUtc)
|
| - ? JS('int', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver))
|
| - : JS('int', r'(#.getMilliseconds() + 0)', lazyAsJsDate(receiver));
|
| - }
|
| -
|
| - static getWeekday(receiver) {
|
| - int weekday = (receiver.isUtc)
|
| - ? JS('int', r'#.getUTCDay() + 0', lazyAsJsDate(receiver))
|
| - : JS('int', r'#.getDay() + 0', lazyAsJsDate(receiver));
|
| - // Adjust by one because JS weeks start on Sunday.
|
| - return (weekday + 6) % 7 + 1;
|
| - }
|
| -
|
| - static valueFromDateString(str) {
|
| - if (str is !String) throw new ArgumentError(str);
|
| - var value = JS('num', r'Date.parse(#)', str);
|
| - if (value.isNaN) throw new ArgumentError(str);
|
| - return value;
|
| - }
|
| -
|
| - static getProperty(object, key) {
|
| - if (object == null || object is bool || object is num || object is String) {
|
| - throw new ArgumentError(object);
|
| - }
|
| - return JS('var', '#[#]', object, key);
|
| - }
|
| -
|
| - static void setProperty(object, key, value) {
|
| - if (object == null || object is bool || object is num || object is String) {
|
| - throw new ArgumentError(object);
|
| - }
|
| - JS('void', '#[#] = #', object, key, value);
|
| - }
|
| -
|
| - static applyFunction(Function function,
|
| - List positionalArguments,
|
| - Map<String, dynamic> namedArguments) {
|
| - int argumentCount = 0;
|
| - StringBuffer buffer = new StringBuffer();
|
| - List arguments = [];
|
| -
|
| - if (positionalArguments != null) {
|
| - argumentCount += positionalArguments.length;
|
| - arguments.addAll(positionalArguments);
|
| - }
|
| -
|
| - // Sort the named arguments to get the right selector name and
|
| - // arguments order.
|
| - if (namedArguments != null && !namedArguments.isEmpty) {
|
| - // Call new List.from to make sure we get a JavaScript array.
|
| - List<String> listOfNamedArguments =
|
| - new List<String>.from(namedArguments.keys);
|
| - argumentCount += namedArguments.length;
|
| - // We're sorting on strings, and the behavior is the same between
|
| - // Dart string sort and JS string sort. To avoid needing the Dart
|
| - // sort implementation, we use the JavaScript one instead.
|
| - JS('void', '#.sort()', listOfNamedArguments);
|
| - listOfNamedArguments.forEach((String name) {
|
| - buffer.write('\$$name');
|
| - arguments.add(namedArguments[name]);
|
| - });
|
| - }
|
| -
|
| - String selectorName = 'call\$$argumentCount$buffer';
|
| - var jsFunction = JS('var', '#[#]', function, selectorName);
|
| - if (jsFunction == null) {
|
| - throw new NoSuchMethodError(function, selectorName, arguments, {});
|
| - }
|
| - // We bound 'this' to [function] because of how we compile
|
| - // closures: escaped local variables are stored and accessed through
|
| - // [function].
|
| - return JS('var', '#.apply(#, #)', jsFunction, function, arguments);
|
| - }
|
| -
|
| - static getConstructor(String className) {
|
| - // TODO(ahe): Generalize this and improve test coverage of
|
| - // reflecting on intercepted classes.
|
| - if (JS('bool', '# == "String"', className)) return const JSString();
|
| - if (JS('bool', '# == "int"', className)) return const JSInt();
|
| - if (JS('bool', '# == "double"', className)) return const JSDouble();
|
| - if (JS('bool', '# == "num"', className)) return const JSNumber();
|
| - if (JS('bool', '# == "bool"', className)) return const JSBool();
|
| - if (JS('bool', '# == "List"', className)) return const JSArray();
|
| - return JS('var', '#[#]', JS_CURRENT_ISOLATE(), className);
|
| - }
|
| -
|
| - static bool identicalImplementation(a, b) {
|
| - return JS('bool', '# == null', a)
|
| - ? JS('bool', '# == null', b)
|
| - : JS('bool', '# === #', a, 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 ArgumentError(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. This may also be called when the index is not an integer, in
|
| - * which case it throws an illegal-argument exception instead, like [iae].
|
| - */
|
| -ioore(index) {
|
| - if (index is !int) iae(index);
|
| - throw new RangeError.value(index);
|
| -}
|
| -
|
| -stringLastIndexOfUnchecked(receiver, element, start)
|
| - => JS('int', r'#.lastIndexOf(#, #)', receiver, element, start);
|
| -
|
| -
|
| -checkNull(object) {
|
| - if (object == null) throw new ArgumentError(null);
|
| - return object;
|
| -}
|
| -
|
| -checkNum(value) {
|
| - if (value is !num) {
|
| - throw new ArgumentError(value);
|
| - }
|
| - return value;
|
| -}
|
| -
|
| -checkInt(value) {
|
| - if (value is !int) {
|
| - throw new ArgumentError(value);
|
| - }
|
| - return value;
|
| -}
|
| -
|
| -checkBool(value) {
|
| - if (value is !bool) {
|
| - throw new ArgumentError(value);
|
| - }
|
| - return value;
|
| -}
|
| -
|
| -checkString(value) {
|
| - if (value is !String) {
|
| - throw new ArgumentError(value);
|
| - }
|
| - return value;
|
| -}
|
| -
|
| -/**
|
| - * Wrap the given Dart object and record a stack trace.
|
| - *
|
| - * The code in [unwrapException] deals with getting the original Dart
|
| - * object out of the wrapper again.
|
| - */
|
| -wrapException(ex) {
|
| - if (ex == null) ex = const NullThrownError();
|
| - var wrapper = new DartError(ex);
|
| -
|
| - if (JS('bool', '!!Error.captureStackTrace')) {
|
| - // Use V8 API for recording a "fast" stack trace (this installs a
|
| - // "stack" property getter on [wrapper]).
|
| - JS('void', r'Error.captureStackTrace(#, #)',
|
| - wrapper, RAW_DART_FUNCTION_REF(wrapException));
|
| - } else {
|
| - // Otherwise, produce a stack trace and record it in the wrapper.
|
| - // This is a slower way to create a stack trace which works on
|
| - // some browsers, but may simply evaluate to null.
|
| - String stackTrace = JS('', 'new Error().stack');
|
| - JS('void', '#.stack = #', wrapper, stackTrace);
|
| - }
|
| - return wrapper;
|
| -}
|
| -
|
| -/**
|
| - * This wraps the exception and does the throw. It is possible to call this in
|
| - * a JS expression context, where the throw statement is not allowed. Helpers
|
| - * are never inlined, so we don't risk inlining the throw statement into an
|
| - * expression context.
|
| - */
|
| -throwExpression(ex) {
|
| - JS('void', 'throw #', wrapException(ex));
|
| -}
|
| -
|
| -/**
|
| - * Wrapper class for throwing exceptions.
|
| - */
|
| -class DartError {
|
| - /// The Dart object (or primitive JavaScript value) which was thrown is
|
| - /// attached to this object as a field named 'dartException'. We do this
|
| - /// only in raw JS so that we can use the 'in' operator and so that the
|
| - /// minifier does not rename the field. Therefore it is not declared as a
|
| - /// real field.
|
| -
|
| - DartError(var dartException) {
|
| - JS('void', '#.dartException = #', this, dartException);
|
| - // Install a toString method that the JavaScript system will call
|
| - // to format uncaught exceptions.
|
| - JS('void', '#.toString = #', this, DART_CLOSURE_TO_JS(toStringWrapper));
|
| - }
|
| -
|
| - /**
|
| - * V8/Chrome installs a property getter, "stack", when calling
|
| - * Error.captureStackTrace (see [wrapException]). In [wrapException], we make
|
| - * sure that this property is always set.
|
| - */
|
| - String get stack => JS('', '#.stack', this);
|
| -
|
| - /**
|
| - * This method can be invoked by calling toString from
|
| - * JavaScript. See the constructor of this class.
|
| - *
|
| - * We only expect this method to be called (indirectly) by the
|
| - * browser when an uncaught exception occurs. Instance of this class
|
| - * should never escape into Dart code (except for [wrapException] above).
|
| - */
|
| - String toString() {
|
| - // If Error.captureStackTrace is available, accessing stack from
|
| - // this method would cause recursion because the stack property
|
| - // (on this object) is actually a getter which calls toString on
|
| - // this object (via the wrapper installed in this class'
|
| - // constructor). Fortunately, both Chrome and d8 prints the stack
|
| - // trace and Chrome even applies source maps to the stack
|
| - // trace. Remeber, this method is only ever invoked by the browser
|
| - // when an uncaught exception occurs.
|
| - var dartException = JS('var', r'#.dartException', this);
|
| - if (JS('bool', '!!Error.captureStackTrace') || (stack == null)) {
|
| - return dartException.toString();
|
| - } else {
|
| - return '$dartException\n$stack';
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * This method is installed as JavaScript toString method on
|
| - * [DartError]. So JavaScript 'this' binds to an instance of
|
| - * DartError.
|
| - */
|
| - static toStringWrapper() => JS('', r'this').toString();
|
| -}
|
| -
|
| -makeLiteralListConst(list) {
|
| - JS('bool', r'#.immutable$list = #', list, true);
|
| - JS('bool', r'#.fixed$length = #', list, true);
|
| - return list;
|
| -}
|
| -
|
| -throwRuntimeError(message) {
|
| - throw new RuntimeError(message);
|
| -}
|
| -
|
| -/**
|
| - * The SSA builder generates a call to this method when a malformed type is used
|
| - * in a subtype test.
|
| - */
|
| -throwMalformedSubtypeError(value, type, reasons) {
|
| - throw new TypeErrorImplementation.malformedSubtype(value, type, reasons);
|
| -}
|
| -
|
| -throwAbstractClassInstantiationError(className) {
|
| - throw new AbstractClassInstantiationError(className);
|
| -}
|
| -
|
| -/**
|
| - * Called from catch blocks in generated code to extract the Dart
|
| - * exception from the thrown value. The thrown value may have been
|
| - * created by [wrapException] 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 (ex == null) return null;
|
| - if (JS('bool', 'typeof # !== "object"', ex)) return ex;
|
| -
|
| - if (JS('bool', r'"dartException" in #', ex)) {
|
| - return JS('', r'#.dartException', ex);
|
| - } else if (!JS('bool', r'"message" in #', ex)) {
|
| - return ex;
|
| - }
|
| -
|
| - // Grab hold of the exception message. This field is available on
|
| - // all supported browsers.
|
| - var message = JS('var', r'#.message', ex);
|
| -
|
| - if (JS('bool', r'# instanceof TypeError', ex)) {
|
| - // The type and arguments fields are Chrome specific but they
|
| - // allow us to get very detailed information about what kind of
|
| - // exception occurred.
|
| - var type = JS('var', r'#.type', ex);
|
| - var name = JS('var', r'#.arguments ? #.arguments[0] : ""', ex, ex);
|
| - if (contains(message, 'JSNull') ||
|
| - type == 'property_not_function' ||
|
| - type == 'called_non_callable' ||
|
| - type == 'non_object_property_call' ||
|
| - type == 'non_object_property_load') {
|
| - return new NoSuchMethodError(null, name, [], {});
|
| - } else if (type == 'undefined_method') {
|
| - return new NoSuchMethodError('', name, [], {});
|
| - }
|
| -
|
| - var ieErrorCode = JS('int', '#.number & 0xffff', ex);
|
| - var ieFacilityNumber = JS('int', '#.number>>16 & 0x1FFF', ex);
|
| - // If we cannot use [type] to determine what kind of exception
|
| - // we're dealing with we fall back on looking at the exception
|
| - // message if it is available and a string.
|
| - if (message is String) {
|
| - if (message == 'null has no properties' ||
|
| - message == "'null' is not an object" ||
|
| - message == "'undefined' is not an object" ||
|
| - message.endsWith('is null') ||
|
| - message.endsWith('is undefined') ||
|
| - message.endsWith('is null or undefined') ||
|
| - message.endsWith('of undefined') ||
|
| - message.endsWith('of null')) {
|
| - return new NoSuchMethodError(null, message, [], {});
|
| - } else if (contains(message, ' has no method ') ||
|
| - contains(message, ' is not a function') ||
|
| - (ieErrorCode == 438 && ieFacilityNumber == 10)) {
|
| - // Examples:
|
| - // x.foo is not a function
|
| - // 'undefined' is not a function (evaluating 'x.foo(1,2,3)')
|
| - // Object doesn't support property or method 'foo' which sets the error
|
| - // code 438 in IE.
|
| - // TODO(kasperl): Compute the right name if possible.
|
| - return new NoSuchMethodError('', message, [], {});
|
| - }
|
| - }
|
| -
|
| - // If we cannot determine what kind of error this is, we fall back
|
| - // to reporting this as a generic exception. It's probably better
|
| - // than nothing.
|
| - return new Exception(message is String ? message : '');
|
| - }
|
| -
|
| - if (JS('bool', r'# instanceof RangeError', ex)) {
|
| - if (message is String && contains(message, 'call stack')) {
|
| - return new StackOverflowError();
|
| - }
|
| -
|
| - // In general, a RangeError is thrown when trying to pass a number
|
| - // as an argument to a function that does not allow a range that
|
| - // includes that number.
|
| - return new ArgumentError();
|
| - }
|
| -
|
| - // Check for the Firefox specific stack overflow signal.
|
| - if (JS('bool',
|
| - r'typeof InternalError == "function" && # instanceof InternalError',
|
| - ex)) {
|
| - if (message is String && message == 'too much recursion') {
|
| - return new StackOverflowError();
|
| - }
|
| - }
|
| -
|
| - // Just return the exception. We should not wrap it because in case
|
| - // the exception comes from the DOM, it is a JavaScript
|
| - // object backed by a native Dart class.
|
| - return ex;
|
| -}
|
| -
|
| -/**
|
| - * Called by generated code to fetch the stack trace from an
|
| - * exception.
|
| - */
|
| -StackTrace getTraceFromException(exception) {
|
| - if (exception == null) return null;
|
| - if (JS('bool', 'typeof # !== "object"', exception)) return null;
|
| - if (JS('bool', r'"stack" in #', exception)) {
|
| - return new _StackTrace(JS("var", r"#.stack", exception));
|
| - } else {
|
| - return null;
|
| - }
|
| -}
|
| -
|
| -class _StackTrace implements 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.moveNext()) {
|
| - String key = iterator.current;
|
| - iterator.moveNext();
|
| - var value = iterator.current;
|
| - 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, int arity) {
|
| - if (closure == null) return null;
|
| - var function = JS('var', r'#.$identity', closure);
|
| - if (JS('bool', r'!!#', function)) return function;
|
| -
|
| - // We use $0 and $1 to not clash with variable names used by the
|
| - // compiler and/or minifier.
|
| - function = JS('var',
|
| - r'(function ($2, $3) {'
|
| - r' return function($0, $1) { '
|
| - r'return $3(#, $2, #, $0, $1) }})(#, #)',
|
| - closure,
|
| - arity,
|
| - // Capture the current isolate now. Remember that "#"
|
| - // in JS is simply textual substitution of compiled
|
| - // expressions.
|
| - JS_CURRENT_ISOLATE_CONTEXT(),
|
| - DART_CLOSURE_TO_JS(invokeClosure));
|
| -
|
| - JS('void', r'#.$identity = #', closure, function);
|
| - return function;
|
| -}
|
| -
|
| -/**
|
| - * Super class for Dart closures.
|
| - */
|
| -class Closure implements Function {
|
| - String toString() => "Closure";
|
| -}
|
| -
|
| -/// Represents a 'tear-off' closure, that is an instance method bound
|
| -/// to a specific receiver (instance).
|
| -class BoundClosure extends Closure {
|
| - /// The receiver or interceptor.
|
| - // TODO(ahe): This could just be the interceptor, we always know if
|
| - // we need the interceptor when generating the call method.
|
| - final _self;
|
| -
|
| - /// The method name.
|
| - final String _target;
|
| -
|
| - /// The receiver.
|
| - final _receiver;
|
| -
|
| - bool operator==(other) {
|
| - if (identical(this, other)) return true;
|
| - if (other is! BoundClosure) return false;
|
| - return JS('bool', '# === # && # === # && # === #',
|
| - _self, other._self,
|
| - _target, other._target,
|
| - _receiver, other._receiver);
|
| - }
|
| -
|
| - int get hashCode {
|
| - return JS('int', '(# + # + #) & 0x3ffffff',
|
| - _self.hashCode,
|
| - _target.hashCode,
|
| - _receiver.hashCode);
|
| - }
|
| -
|
| - static selfOf(BoundClosure closure) => closure._self;
|
| -
|
| - static String targetOf(BoundClosure closure) => closure._target;
|
| -
|
| - static revceiverOf(BoundClosure closure) => closure._receiver;
|
| -}
|
| -
|
| -bool jsHasOwnProperty(var jsObject, String property) {
|
| - return JS('bool', r'#.hasOwnProperty(#)', jsObject, property);
|
| -}
|
| -
|
| -jsPropertyAccess(var jsObject, String property) {
|
| - return JS('var', r'#[#]', jsObject, property);
|
| -}
|
| -
|
| -/**
|
| - * Called at the end of unaborted switch cases to get the singleton
|
| - * FallThroughError exception that will be thrown.
|
| - */
|
| -getFallThroughError() => const FallThroughErrorImplementation();
|
| -
|
| -/**
|
| - * Represents the type dynamic. The compiler treats this specially.
|
| - */
|
| -abstract class Dynamic_ {
|
| -}
|
| -
|
| -/**
|
| - * A metadata annotation describing the types instantiated by a native element.
|
| - *
|
| - * The annotation is valid on a native method and a field of a native class.
|
| - *
|
| - * By default, a field of a native class is seen as an instantiation point for
|
| - * all native classes that are a subtype of the field's type, and a native
|
| - * method is seen as an instantiation point fo all native classes that are a
|
| - * subtype of the method's return type, or the argument types of the declared
|
| - * type of the method's callback parameter.
|
| - *
|
| - * An @[Creates] annotation overrides the default set of instantiated types. If
|
| - * one or more @[Creates] annotations are present, the type of the native
|
| - * element is ignored, and the union of @[Creates] annotations is used instead.
|
| - * The names in the strings are resolved and the program will fail to compile
|
| - * with dart2js if they do not name types.
|
| - *
|
| - * The argument to [Creates] is a string. The string is parsed as the names of
|
| - * one or more types, separated by vertical bars `|`. There are some special
|
| - * names:
|
| - *
|
| - * * `=List`. This means 'exactly List', which is the JavaScript Array
|
| - * implementation of [List] and no other implementation.
|
| - *
|
| - * * `=Object`. This means 'exactly Object', which is a plain JavaScript object
|
| - * with properties and none of the subtypes of Object.
|
| - *
|
| - * Example: we may know that a method always returns a specific implementation:
|
| - *
|
| - * @Creates('_NodeList')
|
| - * List<Node> getElementsByTagName(String tag) native;
|
| - *
|
| - * Useful trick: A method can be marked as not instantiating any native classes
|
| - * with the annotation `@Creates('Null')`. This is useful for fields on native
|
| - * classes that are used only in Dart code.
|
| - *
|
| - * @Creates('Null')
|
| - * var _cachedFoo;
|
| - */
|
| -class Creates {
|
| - final String types;
|
| - const Creates(this.types);
|
| -}
|
| -
|
| -/**
|
| - * A metadata annotation describing the types returned or yielded by a native
|
| - * element.
|
| - *
|
| - * The annotation is valid on a native method and a field of a native class.
|
| - *
|
| - * By default, a native method or field is seen as returning or yielding all
|
| - * subtypes if the method return type or field type. This annotation allows a
|
| - * more precise set of types to be specified.
|
| - *
|
| - * See [Creates] for the syntax of the argument.
|
| - *
|
| - * Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
|
| - *
|
| - * @Returns('String|num|=List')
|
| - * dynamic key;
|
| - *
|
| - * // Equivalent:
|
| - * @Returns('String') @Returns('num') @Returns('=List')
|
| - * dynamic key;
|
| - */
|
| -class Returns {
|
| - final String types;
|
| - const Returns(this.types);
|
| -}
|
| -
|
| -/**
|
| - * A metadata annotation placed on native methods and fields of native classes
|
| - * to specify the JavaScript name.
|
| - *
|
| - * This example declares a Dart field + getter + setter called `$dom_title` that
|
| - * corresponds to the JavaScript property `title`.
|
| - *
|
| - * class Docmument native "*Foo" {
|
| - * @JSName('title')
|
| - * String $dom_title;
|
| - * }
|
| - */
|
| -class JSName {
|
| - final String name;
|
| - const JSName(this.name);
|
| -}
|
| -
|
| -/**
|
| - * Represents the type of Null. The compiler treats this specially.
|
| - * TODO(lrn): Null should be defined in core. It's a class, like int.
|
| - * It just happens to act differently in assignability tests and,
|
| - * like int, can't be extended or implemented.
|
| - */
|
| -class Null {
|
| - factory Null() {
|
| - throw new UnsupportedError('new Null()');
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * The following methods are called by the runtime to implement
|
| - * checked mode and casts. We specialize each primitive type (eg int, bool), and
|
| - * use the compiler's convention to do is-checks on regular objects.
|
| - */
|
| -boolConversionCheck(value) {
|
| - boolTypeCheck(value);
|
| - assert(value != null);
|
| - return value;
|
| -}
|
| -
|
| -stringTypeCheck(value) {
|
| - if (value == null) return value;
|
| - if (value is String) return value;
|
| - throw new TypeErrorImplementation(value, 'String');
|
| -}
|
| -
|
| -stringTypeCast(value) {
|
| - if (value is String || value == null) return value;
|
| - // TODO(lrn): When reified types are available, pass value.class and String.
|
| - throw new CastErrorImplementation(
|
| - Primitives.objectTypeName(value), 'String');
|
| -}
|
| -
|
| -doubleTypeCheck(value) {
|
| - if (value == null) return value;
|
| - if (value is double) return value;
|
| - throw new TypeErrorImplementation(value, 'double');
|
| -}
|
| -
|
| -doubleTypeCast(value) {
|
| - if (value is double || value == null) return value;
|
| - throw new CastErrorImplementation(
|
| - Primitives.objectTypeName(value), 'double');
|
| -}
|
| -
|
| -numTypeCheck(value) {
|
| - if (value == null) return value;
|
| - if (value is num) return value;
|
| - throw new TypeErrorImplementation(value, 'num');
|
| -}
|
| -
|
| -numTypeCast(value) {
|
| - if (value is num || value == null) return value;
|
| - throw new CastErrorImplementation(
|
| - Primitives.objectTypeName(value), 'num');
|
| -}
|
| -
|
| -boolTypeCheck(value) {
|
| - if (value == null) return value;
|
| - if (value is bool) return value;
|
| - throw new TypeErrorImplementation(value, 'bool');
|
| -}
|
| -
|
| -boolTypeCast(value) {
|
| - if (value is bool || value == null) return value;
|
| - throw new CastErrorImplementation(
|
| - Primitives.objectTypeName(value), 'bool');
|
| -}
|
| -
|
| -intTypeCheck(value) {
|
| - if (value == null) return value;
|
| - if (value is int) return value;
|
| - throw new TypeErrorImplementation(value, 'int');
|
| -}
|
| -
|
| -intTypeCast(value) {
|
| - if (value is int || value == null) return value;
|
| - throw new CastErrorImplementation(
|
| - Primitives.objectTypeName(value), 'int');
|
| -}
|
| -
|
| -void propertyTypeError(value, property) {
|
| - // Cuts the property name to the class name.
|
| - String name = property.substring(3, property.length);
|
| - throw new TypeErrorImplementation(value, name);
|
| -}
|
| -
|
| -void propertyTypeCastError(value, property) {
|
| - // Cuts the property name to the class name.
|
| - String actualType = Primitives.objectTypeName(value);
|
| - String expectedType = property.substring(3, property.length);
|
| - throw new CastErrorImplementation(actualType, expectedType);
|
| -}
|
| -
|
| -/**
|
| - * For types that are not supertypes of native (eg DOM) types,
|
| - * we emit a simple property check to check that an object implements
|
| - * that type.
|
| - */
|
| -propertyTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if (JS('bool', '!!#[#]', value, property)) return value;
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -/**
|
| - * For types that are not supertypes of native (eg DOM) types,
|
| - * we emit a simple property check to check that an object implements
|
| - * that type.
|
| - */
|
| -propertyTypeCast(value, property) {
|
| - if (value == null || JS('bool', '!!#[#]', value, property)) return value;
|
| - propertyTypeCastError(value, property);
|
| -}
|
| -
|
| -/**
|
| - * For types that are supertypes of native (eg DOM) types, we use the
|
| - * interceptor for the class because we cannot add a JS property to the
|
| - * prototype at load time.
|
| - */
|
| -interceptedTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if ((identical(JS('String', 'typeof #', value), 'object'))
|
| - && JS('bool', '#[#]', getInterceptor(value), property)) {
|
| - return value;
|
| - }
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -/**
|
| - * For types that are supertypes of native (eg DOM) types, we use the
|
| - * interceptor for the class because we cannot add a JS property to the
|
| - * prototype at load time.
|
| - */
|
| -interceptedTypeCast(value, property) {
|
| - if (value == null
|
| - || ((JS('bool', 'typeof # === "object"', value))
|
| - && JS('bool', '#[#]', getInterceptor(value), property))) {
|
| - return value;
|
| - }
|
| - propertyTypeCastError(value, property);
|
| -}
|
| -
|
| -/**
|
| - * Specialization of the type check for num and String and their
|
| - * supertype since [value] can be a JS primitive.
|
| - */
|
| -numberOrStringSuperTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if (value is String) return value;
|
| - if (value is num) return value;
|
| - if (JS('bool', '!!#[#]', value, property)) return value;
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -numberOrStringSuperTypeCast(value, property) {
|
| - if (value is String) return value;
|
| - if (value is num) return value;
|
| - return propertyTypeCast(value, property);
|
| -}
|
| -
|
| -numberOrStringSuperNativeTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if (value is String) return value;
|
| - if (value is num) return value;
|
| - if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -numberOrStringSuperNativeTypeCast(value, property) {
|
| - if (value == null) return value;
|
| - if (value is String) return value;
|
| - if (value is num) return value;
|
| - if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
|
| - propertyTypeCastError(value, property);
|
| -}
|
| -
|
| -/**
|
| - * Specialization of the type check for String and its supertype
|
| - * since [value] can be a JS primitive.
|
| - */
|
| -stringSuperTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if (value is String) return value;
|
| - if (JS('bool', '!!#[#]', value, property)) return value;
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -stringSuperTypeCast(value, property) {
|
| - if (value is String) return value;
|
| - return propertyTypeCast(value, property);
|
| -}
|
| -
|
| -stringSuperNativeTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if (value is String) return value;
|
| - if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -stringSuperNativeTypeCast(value, property) {
|
| - if (value is String || value == null) return value;
|
| - if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
|
| - propertyTypeCastError(value, property);
|
| -}
|
| -
|
| -/**
|
| - * Specialization of the type check for List and its supertypes,
|
| - * since [value] can be a JS array.
|
| - */
|
| -listTypeCheck(value) {
|
| - if (value == null) return value;
|
| - if (value is List) return value;
|
| - throw new TypeErrorImplementation(value, 'List');
|
| -}
|
| -
|
| -listTypeCast(value) {
|
| - if (value is List || value == null) return value;
|
| - throw new CastErrorImplementation(
|
| - Primitives.objectTypeName(value), 'List');
|
| -}
|
| -
|
| -listSuperTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if (value is List) return value;
|
| - if (JS('bool', '!!#[#]', value, property)) return value;
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -listSuperTypeCast(value, property) {
|
| - if (value is List) return value;
|
| - return propertyTypeCast(value, property);
|
| -}
|
| -
|
| -listSuperNativeTypeCheck(value, property) {
|
| - if (value == null) return value;
|
| - if (value is List) return value;
|
| - if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
|
| - propertyTypeError(value, property);
|
| -}
|
| -
|
| -listSuperNativeTypeCast(value, property) {
|
| - if (value is List || value == null) return value;
|
| - if (JS('bool', '#[#]', getInterceptor(value), property)) return value;
|
| - propertyTypeCastError(value, property);
|
| -}
|
| -
|
| -voidTypeCheck(value) {
|
| - if (value == null) return value;
|
| - throw new TypeErrorImplementation(value, 'void');
|
| -}
|
| -
|
| -malformedTypeCheck(value, type, reasons) {
|
| - if (value == null) return value;
|
| - throwMalformedSubtypeError(value, type, reasons);
|
| -}
|
| -
|
| -malformedTypeCast(value, type, reasons) {
|
| - if (value == null) return value;
|
| - throw new CastErrorImplementation.malformedTypeCast(value, type, reasons);
|
| -}
|
| -
|
| -/**
|
| - * Special interface recognized by the compiler and implemented by DOM
|
| - * objects that support integer indexing. This interface is not
|
| - * visible to anyone, and is only injected into special libraries.
|
| - */
|
| -abstract class JavaScriptIndexingBehavior extends JSMutableIndexable {
|
| -}
|
| -
|
| -// TODO(lrn): These exceptions should be implemented in core.
|
| -// When they are, remove the 'Implementation' here.
|
| -
|
| -/** Thrown by type assertions that fail. */
|
| -class TypeErrorImplementation implements TypeError {
|
| - final String message;
|
| -
|
| - /**
|
| - * Normal type error caused by a failed subtype test.
|
| - */
|
| - TypeErrorImplementation(Object value, String type)
|
| - : message = "type '${Primitives.objectTypeName(value)}' is not a subtype "
|
| - "of type '$type'";
|
| -
|
| - /**
|
| - * Type error caused by a subtype test on a malformed type.
|
| - */
|
| - TypeErrorImplementation.malformedSubtype(Object value,
|
| - String type, String reasons)
|
| - : message = "type '${Primitives.objectTypeName(value)}' is not a subtype "
|
| - "of type '$type' because '$type' is malformed: $reasons.";
|
| -
|
| - String toString() => message;
|
| -}
|
| -
|
| -/** Thrown by the 'as' operator if the cast isn't valid. */
|
| -class CastErrorImplementation implements CastError {
|
| - // TODO(lrn): Rename to CastError (and move implementation into core).
|
| - final String message;
|
| -
|
| - /**
|
| - * Normal cast error caused by a failed type cast.
|
| - */
|
| - CastErrorImplementation(Object actualType, Object expectedType)
|
| - : message = "CastError: Casting value of type $actualType to"
|
| - " incompatible type $expectedType";
|
| -
|
| -
|
| - /**
|
| - * Cast error caused by a type cast to a malformed type.
|
| - */
|
| - CastErrorImplementation.malformedTypeCast(Object value,
|
| - String type, String reasons)
|
| - : message = "CastError: Type '${Primitives.objectTypeName(value)}' "
|
| - "cannot be cast to type '$type' because '$type' is "
|
| - "malformed: $reasons.";
|
| -
|
| -
|
| - String toString() => message;
|
| -}
|
| -
|
| -class FallThroughErrorImplementation implements FallThroughError {
|
| - const FallThroughErrorImplementation();
|
| - String toString() => "Switch case fall-through.";
|
| -}
|
| -
|
| -/**
|
| - * Helper function for implementing asserts. The compiler treats this specially.
|
| - */
|
| -void assertHelper(condition) {
|
| - if (condition is Function) condition = condition();
|
| - if (condition is !bool) {
|
| - throw new TypeErrorImplementation(condition, 'bool');
|
| - }
|
| - // Compare to true to avoid boolean conversion check in checked
|
| - // mode.
|
| - if (!identical(condition, true)) throw new AssertionError();
|
| -}
|
| -
|
| -/**
|
| - * Called by generated code when a method that must be statically
|
| - * resolved cannot be found.
|
| - */
|
| -void throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {
|
| - throw new NoSuchMethodError(obj, name, arguments, const {},
|
| - expectedArgumentNames);
|
| -}
|
| -
|
| -/**
|
| - * Called by generated code when a static field's initializer references the
|
| - * field that is currently being initialized.
|
| - */
|
| -void throwCyclicInit(String staticName) {
|
| - throw new CyclicInitializationError(
|
| - "Cyclic initialization for static $staticName");
|
| -}
|
| -
|
| -/**
|
| - * Error thrown when a runtime error occurs.
|
| - */
|
| -class RuntimeError implements Error {
|
| - final message;
|
| - RuntimeError(this.message);
|
| - String toString() => "RuntimeError: $message";
|
| -}
|
|
|