| Index: sdk/lib/js/dartium/js_dartium.dart
|
| diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
|
| index e7f3004c686d8efbc0b5bdc038bbb28178f2f5d2..57243c5349bb2bdcdf98185cf55bc865e4897d5a 100644
|
| --- a/sdk/lib/js/dartium/js_dartium.dart
|
| +++ b/sdk/lib/js/dartium/js_dartium.dart
|
| @@ -89,11 +89,386 @@ library dart.js;
|
|
|
| import 'dart:collection' show ListMixin;
|
| import 'dart:nativewrappers';
|
| +import 'dart:math' as math;
|
| +import 'dart:mirrors' as mirrors;
|
| +
|
| +// Pretend we are always in checked mode as we aren't interested in users
|
| +// running Dartium code outside of checked mode.
|
| +final bool CHECK_JS_INVOCATIONS = true;
|
| +
|
| +final _allowedMethods = new Map<Symbol, _DeclarationSet>();
|
| +final _allowedGetters = new Map<Symbol, _DeclarationSet>();
|
| +final _allowedSetters = new Map<Symbol, _DeclarationSet>();
|
| +
|
| +final _jsInterfaceTypes = new Set<Type>();
|
| +Iterable<Type> get jsInterfaceTypes => _jsInterfaceTypes;
|
| +
|
| +/// A collection of methods where all methods have the same name.
|
| +/// This class is intended to optimize whether a specific invocation is
|
| +/// appropritate for at least some of the methods in the collection.
|
| +class _DeclarationSet {
|
| + _DeclarationSet() : _members = <mirrors.DeclarationMirror>[];
|
| +
|
| + static bool _checkType(obj, mirrors.TypeMirror type) {
|
| + if (obj == null) return true;
|
| + return mirrors.reflectType(obj.runtimeType).isSubtypeOf(type);
|
| + }
|
| +
|
| + /// Returns whether the return [value] has a type is consistent with the
|
| + /// return type from at least one of the members matching the DeclarationSet.
|
| + bool _checkReturnType(value) {
|
| + if (value == null) return true;
|
| + var valueMirror = mirrors.reflectType(value.runtimeType);
|
| + for (var member in _members) {
|
| + if (member is mirrors.VariableMirror || member.isGetter) {
|
| + // TODO(jacobr): actually check return types for getters that return
|
| + // function types.
|
| + return true;
|
| + } else {
|
| + if (valueMirror.isSubtypeOf(member.returnType)) return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Check whether the [invocation] is consistent with the [member] mirror.
|
| + */
|
| + bool _checkDeclaration(
|
| + Invocation invocation, mirrors.DeclarationMirror member) {
|
| + if (member is mirrors.VariableMirror || member.isGetter) {
|
| + // TODO(jacobr): actually check method types against the function type
|
| + // returned by the getter or field.
|
| + return true;
|
| + }
|
| + var parameters = member.parameters;
|
| + var positionalArguments = invocation.positionalArguments;
|
| + // Too many arguments
|
| + if (parameters.length < positionalArguments.length) return false;
|
| + // Too few required arguments.
|
| + if (parameters.length > positionalArguments.length &&
|
| + !parameters[positionalArguments.length].isOptional) return false;
|
| + for (var i = 0; i < positionalArguments.length; i++) {
|
| + if (parameters[i].isNamed) {
|
| + // Not enough positional arguments.
|
| + return false;
|
| + }
|
| + if (!_checkType(
|
| + invocation.positionalArguments[i], parameters[i].type)) return false;
|
| + }
|
| + if (invocation.namedArguments.isNotEmpty) {
|
| + var startNamed;
|
| + for (startNamed = parameters.length - 1; startNamed >= 0; startNamed--) {
|
| + if (!parameters[startNamed].isNamed) break;
|
| + }
|
| + startNamed++;
|
| +
|
| + // TODO(jacobr): we are unneccessarily using an O(n^2) algorithm here.
|
| + // If we have JS APIs with a lange number of named parameters we should
|
| + // optimize this. Either use a HashSet or invert this, walking over
|
| + // parameters, querying invocation, and making sure we match
|
| + //invocation.namedArguments.size keys.
|
| + for (var name in invocation.namedArguments.keys) {
|
| + bool match = false;
|
| + for (var j = startNamed; j < parameters.length; j++) {
|
| + var p = parameters[j];
|
| + if (p.simpleName == name) {
|
| + if (!_checkType(invocation.namedArguments[name],
|
| + parameters[j].type)) return false;
|
| + match = true;
|
| + break;
|
| + }
|
| + }
|
| + if (match == false) return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + bool checkInvocation(Invocation invocation) {
|
| + for (var member in _members) {
|
| + if (_checkDeclaration(invocation, member)) return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + void add(mirrors.DeclarationMirror mirror) {
|
| + _members.add(mirror);
|
| + }
|
| +
|
| + final List<mirrors.DeclarationMirror> _members;
|
| +}
|
| +
|
| +/**
|
| + * Temporary method that we hope to remove at some point. This method should
|
| + * generally only be called by machine generated code.
|
| + */
|
| +void registerJsInterfaces(List<Type> classes) {
|
| + if (_finalized == true) {
|
| + throw 'JSInterop class registration already finalized';
|
| + }
|
| + for (Type type in classes) {
|
| + if (!_jsInterfaceTypes.add(type)) continue; // Already registered.
|
| + mirrors.ClassMirror typeMirror = mirrors.reflectType(type);
|
| + typeMirror.declarations.forEach((symbol, declaration) {
|
| + if (declaration is mirrors.MethodMirror ||
|
| + declaration is mirrors.VariableMirror && !declaration.isStatic) {
|
| + bool treatAsGetter = false;
|
| + bool treatAsSetter = false;
|
| + if (declaration is mirrors.VariableMirror) {
|
| + treatAsGetter = true;
|
| + if (!declaration.isConst && !declaration.isFinal) {
|
| + treatAsSetter = true;
|
| + }
|
| + } else {
|
| + if (declaration.isGetter) {
|
| + treatAsGetter = true;
|
| + } else if (declaration.isSetter) {
|
| + treatAsSetter = true;
|
| + } else if (!declaration.isConstructor) {
|
| + _allowedMethods
|
| + .putIfAbsent(symbol, () => new _DeclarationSet())
|
| + .add(declaration);
|
| + }
|
| + }
|
| + if (treatAsGetter) {
|
| + _allowedGetters
|
| + .putIfAbsent(symbol, () => new _DeclarationSet())
|
| + .add(declaration);
|
| + _allowedMethods
|
| + .putIfAbsent(symbol, () => new _DeclarationSet())
|
| + .add(declaration);
|
| + }
|
| + if (treatAsSetter) {
|
| + _allowedSetters
|
| + .putIfAbsent(symbol, () => new _DeclarationSet())
|
| + .add(declaration);
|
| + }
|
| + }
|
| + });
|
| + }
|
| +}
|
| +
|
| +_finalizeJsInterfaces() native "Js_finalizeJsInterfaces";
|
| +
|
| +/**
|
| + * Generates a part file defining source code for JsObjectImpl and related
|
| + * classes. This calass is needed so that type checks for all registered JavaScript
|
| + * interop classes pass.
|
| + */
|
| +String _generateJsObjectImplPart() {
|
| + Iterable<Type> types = jsInterfaceTypes;
|
| + var libraryPrefixes = new Map<mirrors.LibraryMirror, String>();
|
| + var prefixNames = new Set<String>();
|
| + var sb = new StringBuffer();
|
| +
|
| + var implements = <String>[];
|
| + for (var type in types) {
|
| + mirrors.ClassMirror typeMirror = mirrors.reflectType(type);
|
| + mirrors.LibraryMirror libraryMirror = typeMirror.owner;
|
| + var prefixName;
|
| + if (libraryPrefixes.containsKey(libraryMirror)) {
|
| + prefixName = libraryPrefixes[libraryMirror];
|
| + } else {
|
| + var basePrefixName =
|
| + mirrors.MirrorSystem.getName(libraryMirror.simpleName);
|
| + basePrefixName = basePrefixName.replaceAll('.', '_');
|
| + if (basePrefixName.isEmpty) basePrefixName = "lib";
|
| + prefixName = basePrefixName;
|
| + var i = 1;
|
| + while (prefixNames.contains(prefixName)) {
|
| + prefixName = '$basePrefixName$i';
|
| + i++;
|
| + }
|
| + prefixNames.add(prefixName);
|
| + libraryPrefixes[libraryMirror] = prefixName;
|
| + }
|
| + implements.add(
|
| + '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}');
|
| + }
|
| + libraryPrefixes.forEach((libraryMirror, prefix) {
|
| + sb.writeln('import "${libraryMirror.uri}" as $prefix;');
|
| + });
|
| + var implementsClause =
|
| + implements.isEmpty ? "" : "implements ${implements.join(', ')}";
|
| + // TODO(jacobr): only certain classes need to be implemented by
|
| + // Function and Array.
|
| + sb.write('''
|
| +class JsObjectImpl extends JsObject $implementsClause {
|
| + JsObjectImpl.internal() : super.internal();
|
| +}
|
| +
|
| +class JsFunctionImpl extends JsFunction $implementsClause {
|
| + JsFunctionImpl.internal() : super.internal();
|
| +}
|
| +
|
| +class JsArrayImpl<E> extends JsArray<E> $implementsClause {
|
| + JsArrayImpl.internal() : super.internal();
|
| +}
|
| +''');
|
| + return sb.toString();
|
| +}
|
| +
|
| +// Start of block of helper methods facilitating emulating JavaScript Array
|
| +// methods on Dart List objects passed to JavaScript via JS interop.
|
| +// TODO(jacobr): match JS more closely.
|
| +String _toStringJs(obj) => '$obj';
|
| +
|
| +// TODO(jacobr): this might not exactly match JS semantics but should be
|
| +// adequate for now.
|
| +int _toIntJs(obj) {
|
| + if (obj is int) return obj;
|
| + if (obj is num) return obj.toInt();
|
| + return num.parse('$obj'.trim(), (_) => 0).toInt();
|
| +}
|
| +
|
| +// TODO(jacobr): this might not exactly match JS semantics but should be
|
| +// adequate for now.
|
| +num _toNumJs(obj) {
|
| + return obj is num ? obj : num.parse('$obj'.trim(), (_) => 0);
|
| +}
|
| +
|
| +/// Match the behavior of setting List length in JavaScript with the exception
|
| +/// that Dart does not distinguish undefined and null.
|
| +_setListLength(List list, rawlen) {
|
| + num len = _toNumJs(rawlen);
|
| + if (len is! int || len < 0) {
|
| + throw new RangeError("Invalid array length");
|
| + }
|
| + if (len > list.length) {
|
| + _arrayExtend(list, len);
|
| + } else if (len < list.length) {
|
| + list.removeRange(len, list.length);
|
| + }
|
| + return rawlen;
|
| +}
|
| +
|
| +// TODO(jacobr): should we really bother with this method instead of just
|
| +// shallow copying to a JS array and calling the JavaScript join method?
|
| +String _arrayJoin(List list, sep) {
|
| + if (sep == null) {
|
| + sep = ",";
|
| + }
|
| + return list.map((e) => e == null ? "" : e.toString()).join(sep.toString());
|
| +}
|
| +
|
| +// TODO(jacobr): should we really bother with this method instead of just
|
| +// shallow copying to a JS array and using the toString method?
|
| +String _arrayToString(List list) => _arrayJoin(list, ",");
|
| +
|
| +int _arrayPush(List list, e) {
|
| + list.add(e);
|
| + return list.length;
|
| +}
|
| +
|
| +_arrayPop(List list) {
|
| + if (list.length > 0) return list.removeLast();
|
| +}
|
| +
|
| +// TODO(jacobr): would it be better to just copy input to a JS List
|
| +// and call Array.concat?
|
| +List _arrayConcat(List input, List args) {
|
| + var ret = new List.from(input);
|
| + for (var e in args) {
|
| + // TODO(jacobr): technically in ES6 we should use
|
| + // Symbol.isConcatSpreadable to determine whether call addAll. Once v8
|
| + // supports it, we can make all Dart classes implementing Iterable
|
| + // specify isConcatSpreadable and tweak this behavior to allow Iterable.
|
| + if (e is List) {
|
| + ret.addAll(e);
|
| + } else {
|
| + ret.add(e);
|
| + }
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +List _arraySplice(List input, List args) {
|
| + int start = 0;
|
| + if (args.length > 0) {
|
| + var rawStart = _toIntJs(args[0]);
|
| + if (rawStart < 0) {
|
| + start = math.max(0, input.length - rawStart);
|
| + } else {
|
| + start = math.min(input.length, rawStart);
|
| + }
|
| + }
|
| + var end = start;
|
| + if (args.length > 1) {
|
| + var rawDeleteCount = _toIntJs(args[1]);
|
| + if (rawDeleteCount < 0) rawDeleteCount = 0;
|
| + end = math.min(input.length, start + rawDeleteCount);
|
| + }
|
| + var replacement = [];
|
| + var removedElements = input.getRange(start, end).toList();
|
| + if (args.length > 2) {
|
| + replacement = args.getRange(2, args.length);
|
| + }
|
| + input.replaceRange(start, end, replacement);
|
| + return removedElements;
|
| +}
|
| +
|
| +List _arrayReverse(List l) {
|
| + for (var i = 0, j = l.length - 1; i < j; i++, j--) {
|
| + var tmp = l[i];
|
| + l[i] = l[j];
|
| + l[j] = tmp;
|
| + }
|
| + return l;
|
| +}
|
| +
|
| +_arrayShift(List l) {
|
| + if (l.isEmpty) return null; // Technically we should return undefined.
|
| + return l.removeAt(0);
|
| +}
|
| +
|
| +int _arrayUnshift(List l, List args) {
|
| + l.insertAll(0, args);
|
| + return l.length;
|
| +}
|
| +
|
| +_arrayExtend(List l, int newLength) {
|
| + for (var i = l.length; i < newLength; i++) {
|
| + // TODO(jacobr): we'd really like to add undefined to better match
|
| + // JavaScript semantics.
|
| + l.add(null);
|
| + }
|
| +}
|
| +
|
| +List _arraySort(List l, rawCompare) {
|
| + // TODO(jacobr): alternately we could just copy the Array to JavaScript,
|
| + // invoke the JS sort method and then copy the result back to Dart.
|
| + Comparator compare;
|
| + if (rawCompare == null) {
|
| + compare = (a, b) => _toStringJs(a).compareTo(_toStringJs(b));
|
| + } else if (rawCompare is JsFunction) {
|
| + compare = (a, b) => rawCompare.apply([a, b]);
|
| + } else {
|
| + compare = rawCompare;
|
| + }
|
| + l.sort(compare);
|
| + return l;
|
| +}
|
| +// End of block of helper methods to emulate JavaScript Array methods on Dart List.
|
| +
|
| +/**
|
| + * Can be called to provide a predictable point where no more JS interfaces can
|
| + * be added. Creating an instance of JsObject will also automatically trigger
|
| + * all JsObjects to be finalized.
|
| + */
|
| +void finalizeJsInterfaces() {
|
| + if (_finalized == true) {
|
| + throw 'JSInterop class registration already finalized';
|
| + }
|
| + _finalizeJsInterfaces();
|
| +}
|
|
|
| JsObject _cachedContext;
|
|
|
| JsObject get _context native "Js_context_Callback";
|
|
|
| +bool get _finalized native "Js_interfacesFinalized_Callback";
|
| +
|
| JsObject get context {
|
| if (_cachedContext == null) {
|
| _cachedContext = _context;
|
| @@ -114,9 +489,24 @@ class JsObject extends NativeFieldWrapperClass2 {
|
| * Constructs a new JavaScript object from [constructor] and returns a proxy
|
| * to it.
|
| */
|
| - factory JsObject(JsFunction constructor, [List arguments]) => _create(constructor, arguments);
|
| -
|
| - static JsObject _create(JsFunction constructor, arguments) native "JsObject_constructorCallback";
|
| + factory JsObject(JsFunction constructor, [List arguments]) =>
|
| + _create(constructor, arguments);
|
| +
|
| + static JsObject _create(
|
| + JsFunction constructor, arguments) native "JsObject_constructorCallback";
|
| +
|
| + _buildArgs(Invocation invocation) {
|
| + if (invocation.namedArguments.isEmpty) {
|
| + return invocation.positionalArguments;
|
| + } else {
|
| + var varArgs = new Map<String, Object>();
|
| + invocation.namedArguments.forEach((symbol, val) {
|
| + varArgs[mirrors.MirrorSystem.getName(symbol)] = val;
|
| + });
|
| + return invocation.positionalArguments.toList()
|
| + ..add(new JsObject.jsify(varArgs));
|
| + }
|
| + }
|
|
|
| /**
|
| * Constructs a [JsObject] that proxies a native Dart object; _for expert use
|
| @@ -131,8 +521,7 @@ class JsObject extends NativeFieldWrapperClass2 {
|
| */
|
| factory JsObject.fromBrowserObject(object) {
|
| if (object is num || object is String || object is bool || object == null) {
|
| - throw new ArgumentError(
|
| - "object cannot be a num, string, bool, or null");
|
| + throw new ArgumentError("object cannot be a num, string, bool, or null");
|
| }
|
| return _fromBrowserObject(object);
|
| }
|
| @@ -155,7 +544,8 @@ class JsObject extends NativeFieldWrapperClass2 {
|
|
|
| static JsObject _jsify(object) native "JsObject_jsify";
|
|
|
| - static JsObject _fromBrowserObject(object) native "JsObject_fromBrowserObject";
|
| + static JsObject _fromBrowserObject(
|
| + object) native "JsObject_fromBrowserObject";
|
|
|
| /**
|
| * Returns the value associated with [property] from the proxied JavaScript
|
| @@ -163,7 +553,7 @@ class JsObject extends NativeFieldWrapperClass2 {
|
| *
|
| * The type of [property] must be either [String] or [num].
|
| */
|
| - operator[](property) native "JsObject_[]";
|
| + operator [](property) native "JsObject_[]";
|
|
|
| /**
|
| * Sets the value associated with [property] on the proxied JavaScript
|
| @@ -171,13 +561,14 @@ class JsObject extends NativeFieldWrapperClass2 {
|
| *
|
| * The type of [property] must be either [String] or [num].
|
| */
|
| - operator[]=(property, value) native "JsObject_[]=";
|
| + operator []=(property, value) native "JsObject_[]=";
|
|
|
| int get hashCode native "JsObject_hashCode";
|
|
|
| - operator==(other) => other is JsObject && _identityEquality(this, other);
|
| + operator ==(other) => other is JsObject && _identityEquality(this, other);
|
|
|
| - static bool _identityEquality(JsObject a, JsObject b) native "JsObject_identityEquality";
|
| + static bool _identityEquality(
|
| + JsObject a, JsObject b) native "JsObject_identityEquality";
|
|
|
| /**
|
| * Returns `true` if the JavaScript object contains the specified property
|
| @@ -207,7 +598,7 @@ class JsObject extends NativeFieldWrapperClass2 {
|
| String toString() {
|
| try {
|
| return _toString();
|
| - } catch(e) {
|
| + } catch (e) {
|
| return super.toString();
|
| }
|
| }
|
| @@ -223,7 +614,7 @@ class JsObject extends NativeFieldWrapperClass2 {
|
| callMethod(String method, [List args]) {
|
| try {
|
| return _callMethod(method, args);
|
| - } catch(e) {
|
| + } catch (e) {
|
| if (hasProperty(method)) {
|
| rethrow;
|
| } else {
|
| @@ -232,13 +623,63 @@ class JsObject extends NativeFieldWrapperClass2 {
|
| }
|
| }
|
|
|
| + noSuchMethod(Invocation invocation) {
|
| + throwError() {
|
| + throw new NoSuchMethodError(this, invocation.memberName,
|
| + invocation.positionalArguments, invocation.namedArguments);
|
| + }
|
| +
|
| + String name = mirrors.MirrorSystem.getName(invocation.memberName);
|
| + if (invocation.isGetter) {
|
| + if (CHECK_JS_INVOCATIONS) {
|
| + var matches = _allowedGetters[invocation.memberName];
|
| + if (matches == null &&
|
| + !_allowedMethods.containsKey(invocation.memberName)) {
|
| + throwError();
|
| + }
|
| + var ret = this[name];
|
| + if (matches != null && matches._checkReturnType(ret)) return ret;
|
| + if (ret is Function ||
|
| + (ret is JsFunction /* shouldn't be needed in the future*/) &&
|
| + _allowedMethods.containsKey(
|
| + invocation.memberName)) return ret; // Warning: we have not bound "this"... we could type check on the Function but that is of little value in Dart.
|
| + throwError();
|
| + } else {
|
| + // TODO(jacobr): should we throw if the JavaScript object doesn't have the property?
|
| + return this[name];
|
| + }
|
| + } else if (invocation.isSetter) {
|
| + if (CHECK_JS_INVOCATIONS) {
|
| + var matches = _allowedSetters[invocation.memberName];
|
| + if (matches == null ||
|
| + !matches.checkInvocation(invocation)) throwError();
|
| + }
|
| + assert(name.endsWith("="));
|
| + name = name.substring(0, name.length - 1);
|
| + return this[name] = invocation.positionalArguments.first;
|
| + } else {
|
| + // TODO(jacobr): also allow calling getters that look like functions.
|
| + var matches;
|
| + if (CHECK_JS_INVOCATIONS) {
|
| + matches = _allowedMethods[invocation.memberName];
|
| + if (matches == null ||
|
| + !matches.checkInvocation(invocation)) throwError();
|
| + }
|
| + var ret = this.callMethod(name, _buildArgs(invocation));
|
| + if (CHECK_JS_INVOCATIONS) {
|
| + if (!matches._checkReturnType(ret)) throwError();
|
| + }
|
| + return ret;
|
| + }
|
| + }
|
| +
|
| _callMethod(String name, List args) native "JsObject_callMethod";
|
| }
|
|
|
| /**
|
| * Proxies a JavaScript Function object.
|
| */
|
| -class JsFunction extends JsObject {
|
| +class JsFunction extends JsObject implements Function {
|
| JsFunction.internal() : super.internal();
|
|
|
| /**
|
| @@ -253,13 +694,21 @@ class JsFunction extends JsObject {
|
| */
|
| dynamic apply(List args, {thisArg}) native "JsFunction_apply";
|
|
|
| + noSuchMethod(Invocation invocation) {
|
| + if (invocation.isMethod && invocation.memberName == #call) {
|
| + return apply(_buildArgs(invocation));
|
| + }
|
| + return super.noSuchMethod(invocation);
|
| + }
|
| +
|
| /**
|
| * Internal only version of apply which uses debugger proxies of Dart objects
|
| * rather than opaque handles. This method is private because it cannot be
|
| * efficiently implemented in Dart2Js so should only be used by internal
|
| * tools.
|
| */
|
| - _applyDebuggerOnly(List args, {thisArg}) native "JsFunction_applyDebuggerOnly";
|
| + _applyDebuggerOnly(List args,
|
| + {thisArg}) native "JsFunction_applyDebuggerOnly";
|
|
|
| static JsFunction _withThis(Function f) native "JsFunction_withThis";
|
| }
|
| @@ -268,14 +717,17 @@ class JsFunction extends JsObject {
|
| * A [List] proxying a JavaScript Array.
|
| */
|
| class JsArray<E> extends JsObject with ListMixin<E> {
|
| + JsArray.internal() : super.internal();
|
|
|
| factory JsArray() => _newJsArray();
|
|
|
| static JsArray _newJsArray() native "JsArray_newJsArray";
|
|
|
| - factory JsArray.from(Iterable<E> other) => _newJsArrayFromSafeList(new List.from(other));
|
| + factory JsArray.from(Iterable<E> other) =>
|
| + _newJsArrayFromSafeList(new List.from(other));
|
|
|
| - static JsArray _newJsArrayFromSafeList(List list) native "JsArray_newJsArrayFromSafeList";
|
| + static JsArray _newJsArrayFromSafeList(
|
| + List list) native "JsArray_newJsArrayFromSafeList";
|
|
|
| _checkIndex(int index, {bool insert: false}) {
|
| int length = insert ? this.length + 1 : this.length;
|
| @@ -304,7 +756,7 @@ class JsArray<E> extends JsObject with ListMixin<E> {
|
| }
|
|
|
| void operator []=(index, E value) {
|
| - if(index is int) {
|
| + if (index is int) {
|
| _checkIndex(index);
|
| }
|
| super[index] = value;
|
| @@ -312,7 +764,9 @@ class JsArray<E> extends JsObject with ListMixin<E> {
|
|
|
| int get length native "JsArray_length";
|
|
|
| - void set length(int length) { super['length'] = length; }
|
| + void set length(int length) {
|
| + super['length'] = length;
|
| + }
|
|
|
| // Methods overriden for better performance
|
|
|
| @@ -326,7 +780,7 @@ class JsArray<E> extends JsObject with ListMixin<E> {
|
| }
|
|
|
| void insert(int index, E element) {
|
| - _checkIndex(index, insert:true);
|
| + _checkIndex(index, insert: true);
|
| callMethod('splice', [index, 0, element]);
|
| }
|
|
|
| @@ -365,7 +819,7 @@ class JsArray<E> extends JsObject with ListMixin<E> {
|
| */
|
| const _UNDEFINED = const Object();
|
|
|
| -// FIXME(jacobr): this method is a hack to work around the lack of proper dart
|
| +// TODO(jacobr): this method is a hack to work around the lack of proper dart
|
| // support for varargs methods.
|
| List _stripUndefinedArgs(List args) =>
|
| args.takeWhile((i) => i != _UNDEFINED).toList();
|
| @@ -375,8 +829,7 @@ List _stripUndefinedArgs(List args) =>
|
| * than 11) of arguments without violating Dart type checks.
|
| */
|
| Function _wrapAsDebuggerVarArgsFunction(JsFunction jsFunction) =>
|
| - ([a1=_UNDEFINED, a2=_UNDEFINED, a3=_UNDEFINED, a4=_UNDEFINED,
|
| - a5=_UNDEFINED, a6=_UNDEFINED, a7=_UNDEFINED, a8=_UNDEFINED,
|
| - a9=_UNDEFINED, a10=_UNDEFINED]) =>
|
| - jsFunction._applyDebuggerOnly(_stripUndefinedArgs(
|
| - [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10]));
|
| + ([a1 = _UNDEFINED, a2 = _UNDEFINED, a3 = _UNDEFINED, a4 = _UNDEFINED,
|
| + a5 = _UNDEFINED, a6 = _UNDEFINED, a7 = _UNDEFINED, a8 = _UNDEFINED,
|
| + a9 = _UNDEFINED, a10 = _UNDEFINED]) => jsFunction._applyDebuggerOnly(
|
| + _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
|
|
|