| Index: lib/runtime/dart/_operations.js
|
| diff --git a/lib/runtime/dart/_operations.js b/lib/runtime/dart/_operations.js
|
| index 082a0f4b2ed2f5e9c4782a61ca3bd194433a819b..d09154d6e3e455e0b0f85e4b8615803abda45b17 100644
|
| --- a/lib/runtime/dart/_operations.js
|
| +++ b/lib/runtime/dart/_operations.js
|
| @@ -1,71 +1,41 @@
|
| -// Copyright (c) 2015, 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.
|
| -
|
| -/* This library defines runtime operations on objects used by the code
|
| - * generator.
|
| - */
|
| dart_library.library('dart/_operations', null, /* Imports */[
|
| -], /* Lazy Imports */[
|
| - 'dart/_utils',
|
| - 'dart/async',
|
| - 'dart/collection',
|
| - 'dart/core',
|
| - 'dart/_js_helper',
|
| + 'dart/_utils'
|
| +], /* Lazy imports */[
|
| 'dart/_classes',
|
| 'dart/_errors',
|
| 'dart/_rtti',
|
| - 'dart/_types'
|
| -], function(exports, dart_utils, async, collection, core, _js_helper, classes, errors, rtti,
|
| - types) {
|
| + 'dart/_types',
|
| + 'dart/core',
|
| + 'dart/async',
|
| + 'dart/collection',
|
| + 'dart/_js_helper'
|
| +], function(exports, utils, classes, _errors, rtti, _types, core, async, collection, _js_helper) {
|
| 'use strict';
|
| -
|
| - const getOwnNamesAndSymbols = dart_utils.getOwnNamesAndSymbols;
|
| - const throwError = dart_utils.throwError;
|
| -
|
| + const getOwnNamesAndSymbols = utils.getOwnNamesAndSymbols;
|
| const getOwnPropertyNames = Object.getOwnPropertyNames;
|
| const hasOwnProperty = Object.prototype.hasOwnProperty;
|
| -
|
| function _canonicalFieldName(obj, name, args, displayName) {
|
| name = classes.canonicalMember(obj, name);
|
| if (name) return name;
|
| - // TODO(jmesserly): in the future we might have types that "overlay" Dart
|
| - // methods while also exposing the full native API, e.g. dart:html vs
|
| - // dart:dom. To support that we'd need to fall back to the normal name
|
| - // if an extension method wasn't found.
|
| - errors.throwNoSuchMethod(obj, displayName, args);
|
| + throwNoSuchMethod(obj, displayName, args);
|
| }
|
| -
|
| function dload(obj, field) {
|
| field = _canonicalFieldName(obj, field, [], field);
|
| if (classes.hasMethod(obj, field)) {
|
| return classes.bind(obj, field);
|
| }
|
| - // TODO(vsm): Implement NSM robustly. An 'in' check breaks on certain
|
| - // types. hasOwnProperty doesn't chase the proto chain.
|
| - // Also, do we want an NSM on regular JS objects?
|
| - // See: https://github.com/dart-lang/dev_compiler/issues/169
|
| let result = obj[field];
|
| return result;
|
| }
|
| - exports.dload = dload;
|
| -
|
| function dput(obj, field, value) {
|
| field = _canonicalFieldName(obj, field, [value], field);
|
| - // TODO(vsm): Implement NSM and type checks.
|
| - // See: https://github.com/dart-lang/dev_compiler/issues/170
|
| obj[field] = value;
|
| return value;
|
| }
|
| - exports.dput = dput;
|
| -
|
| -
|
| - /// Check that a function of a given type can be applied to
|
| - /// actuals.
|
| function checkApply(type, actuals) {
|
| if (actuals.length < type.args.length) return false;
|
| let index = 0;
|
| - for(let i = 0; i < type.args.length; ++i) {
|
| + for (let i = 0; i < type.args.length; ++i) {
|
| if (!instanceOfOrNull(actuals[i], type.args[i])) return false;
|
| ++index;
|
| }
|
| @@ -73,39 +43,30 @@ dart_library.library('dart/_operations', null, /* Imports */[
|
| let extras = actuals.length - type.args.length;
|
| if (type.optionals.length > 0) {
|
| if (extras > type.optionals.length) return false;
|
| - for(let i = 0, j=index; i < extras; ++i, ++j) {
|
| + for (let i = 0, j = index; i < extras; ++i, ++j) {
|
| if (!instanceOfOrNull(actuals[j], type.optionals[i])) return false;
|
| }
|
| return true;
|
| }
|
| - // TODO(leafp): We can't tell when someone might be calling
|
| - // something expecting an optional argument with named arguments
|
| -
|
| if (extras != 1) return false;
|
| - // An empty named list means no named arguments
|
| if (getOwnPropertyNames(type.named).length == 0) return false;
|
| let opts = actuals[index];
|
| let names = getOwnPropertyNames(opts);
|
| - // Type is something other than a map
|
| if (names.length == 0) return false;
|
| for (var name of names) {
|
| - if (!(hasOwnProperty.call(type.named, name))) {
|
| + if (!hasOwnProperty.call(type.named, name)) {
|
| return false;
|
| }
|
| if (!instanceOfOrNull(opts[name], type.named[name])) return false;
|
| }
|
| return true;
|
| }
|
| -
|
| function throwNoSuchMethod(obj, name, args, opt_func) {
|
| if (obj === void 0) obj = opt_func;
|
| - errors.throwNoSuchMethod(obj, name, args);
|
| + _errors.throwNoSuchMethod(obj, name, args);
|
| }
|
| -
|
| function checkAndCall(f, ftype, obj, args, name) {
|
| if (!(f instanceof Function)) {
|
| - // We're not a function (and hence not a method either)
|
| - // Grab the `call` method if it's not a function.
|
| if (f != null) {
|
| ftype = classes.getMethodType(f, 'call');
|
| f = f.call;
|
| @@ -114,167 +75,91 @@ dart_library.library('dart/_operations', null, /* Imports */[
|
| throwNoSuchMethod(obj, name, args);
|
| }
|
| }
|
| - // If f is a function, but not a method (no method type)
|
| - // then it should have been a function valued field, so
|
| - // get the type from the function.
|
| if (ftype === void 0) {
|
| ftype = rtti.read(f);
|
| }
|
| -
|
| if (!ftype) {
|
| - // TODO(leafp): Allow JS objects to go through?
|
| - // This includes the DOM.
|
| return f.apply(obj, args);
|
| }
|
| -
|
| if (checkApply(ftype, args)) {
|
| return f.apply(obj, args);
|
| }
|
| -
|
| - // TODO(leafp): throw a type error (rather than NSM)
|
| - // if the arity matches but the types are wrong.
|
| throwNoSuchMethod(obj, name, args, f);
|
| }
|
| -
|
| function dcall(f, ...args) {
|
| let ftype = rtti.read(f);
|
| return checkAndCall(f, ftype, void 0, args, 'call');
|
| }
|
| - exports.dcall = dcall;
|
| -
|
| - /** Shared code for dsend, dindex, and dsetindex. */
|
| function callMethod(obj, name, args, displayName) {
|
| let symbol = _canonicalFieldName(obj, name, args, displayName);
|
| let f = obj != null ? obj[symbol] : null;
|
| let ftype = classes.getMethodType(obj, name);
|
| return checkAndCall(f, ftype, obj, args, displayName);
|
| }
|
| -
|
| function dsend(obj, method, ...args) {
|
| return callMethod(obj, method, args, method);
|
| }
|
| - exports.dsend = dsend;
|
| -
|
| function dindex(obj, index) {
|
| return callMethod(obj, 'get', [index], '[]');
|
| }
|
| - exports.dindex = dindex;
|
| -
|
| function dsetindex(obj, index, value) {
|
| callMethod(obj, 'set', [index, value], '[]=');
|
| return value;
|
| }
|
| - exports.dsetindex = dsetindex;
|
| -
|
| function _ignoreTypeFailure(actual, type) {
|
| - // TODO(vsm): Remove this hack ...
|
| - // This is primarily due to the lack of generic methods,
|
| - // but we need to triage all the errors.
|
| - let isSubtype = types.isSubtype;
|
| - if (isSubtype(type, core.Iterable) && isSubtype(actual, core.Iterable) ||
|
| - isSubtype(type, async.Future) && isSubtype(actual, async.Future) ||
|
| - isSubtype(type, core.Map) && isSubtype(actual, core.Map) ||
|
| - isSubtype(type, core.Function) && isSubtype(actual, core.Function) ||
|
| - isSubtype(type, async.Stream) && isSubtype(actual, async.Stream) ||
|
| - isSubtype(type, async.StreamSubscription) &&
|
| - isSubtype(actual, async.StreamSubscription)) {
|
| - console.warn('Ignoring cast fail from ' + types.typeName(actual) +
|
| - ' to ' + types.typeName(type));
|
| + let isSubtype = _types.isSubtype;
|
| + if (isSubtype(type, core.Iterable) && isSubtype(actual, core.Iterable) || isSubtype(type, async.Future) && isSubtype(actual, async.Future) || isSubtype(type, core.Map) && isSubtype(actual, core.Map) || isSubtype(type, core.Function) && isSubtype(actual, core.Function) || isSubtype(type, async.Stream) && isSubtype(actual, async.Stream) || isSubtype(type, async.StreamSubscription) && isSubtype(actual, async.StreamSubscription)) {
|
| + console.warn('Ignoring cast fail from ' + _types.typeName(actual) + ' to ' + _types.typeName(type));
|
| return true;
|
| }
|
| return false;
|
| }
|
| -
|
| function strongInstanceOf(obj, type, ignoreFromWhiteList) {
|
| let actual = rtti.realRuntimeType(obj);
|
| - if (types.isSubtype(actual, type) || actual == types.jsobject) return true;
|
| + if (_types.isSubtype(actual, type) || actual == _types.jsobject) return true;
|
| if (ignoreFromWhiteList == void 0) return false;
|
| - if (types.isGroundType(type)) return false;
|
| + if (_types.isGroundType(type)) return false;
|
| if (_ignoreTypeFailure(actual, type)) return true;
|
| return false;
|
| }
|
| - exports.strongInstanceOf = strongInstanceOf;
|
| -
|
| function instanceOfOrNull(obj, type) {
|
| - if ((obj == null) || strongInstanceOf(obj, type, true)) return true;
|
| + if (obj == null || strongInstanceOf(obj, type, true)) return true;
|
| return false;
|
| }
|
| -
|
| function instanceOf(obj, type) {
|
| if (strongInstanceOf(obj, type)) return true;
|
| - // TODO(#296): This is perhaps too eager to throw a StrongModeError?
|
| - // It will throw on <int>[] is List<String>.
|
| - // TODO(vsm): We can statically detect many cases where this
|
| - // check is unnecessary.
|
| - if (types.isGroundType(type)) return false;
|
| + if (_types.isGroundType(type)) return false;
|
| let actual = rtti.realRuntimeType(obj);
|
| - dart_utils.throwStrongModeError('Strong mode is check failure: ' +
|
| - types.typeName(actual) + ' does not soundly subtype ' +
|
| - types.typeName(type));
|
| + utils.throwStrongModeError('Strong mode is check failure: ' + _types.typeName(actual) + ' does not soundly subtype ' + _types.typeName(type));
|
| }
|
| - exports.instanceOf = instanceOf;
|
| -
|
| function cast(obj, type) {
|
| - // TODO(#296): This is perhaps too eager to throw a StrongModeError?
|
| - // TODO(vsm): handle non-nullable types
|
| if (instanceOfOrNull(obj, type)) return obj;
|
| let actual = rtti.realRuntimeType(obj);
|
| - if (types.isGroundType(type)) errors.throwCastError(actual, type);
|
| -
|
| + if (_types.isGroundType(type)) _errors.throwCastError(actual, type);
|
| if (_ignoreTypeFailure(actual, type)) return obj;
|
| -
|
| - dart_utils.throwStrongModeError('Strong mode cast failure from ' +
|
| - types.typeName(actual) + ' to ' + types.typeName(type));
|
| + utils.throwStrongModeError('Strong mode cast failure from ' + _types.typeName(actual) + ' to ' + _types.typeName(type));
|
| }
|
| - exports.cast = cast;
|
| -
|
| function asInt(obj) {
|
| if (obj == null) {
|
| return null;
|
| }
|
| if (Math.floor(obj) != obj) {
|
| - // Note: null will also be caught by this check
|
| - errors.throwCastError(rtti.realRuntimeType(obj), core.int);
|
| + _errors.throwCastError(rtti.realRuntimeType(obj), core.int);
|
| }
|
| return obj;
|
| }
|
| - exports.asInt = asInt;
|
| -
|
| function arity(f) {
|
| - // TODO(jmesserly): need to parse optional params.
|
| - // In ES6, length is the number of required arguments.
|
| - return { min: f.length, max: f.length };
|
| + return {min: f.length, max: f.length};
|
| }
|
| - exports.arity = arity;
|
| -
|
| function equals(x, y) {
|
| if (x == null || y == null) return x == y;
|
| let eq = x['=='];
|
| return eq ? eq.call(x, y) : x === y;
|
| }
|
| - exports.equals = equals;
|
| -
|
| - /** Checks that `x` is not null or undefined. */
|
| function notNull(x) {
|
| - if (x == null) errors.throwNullValueError();
|
| + if (x == null) _errors.throwNullValueError();
|
| return x;
|
| }
|
| - exports.notNull = notNull;
|
| -
|
| - /**
|
| - * Creates a dart:collection LinkedHashMap.
|
| - *
|
| - * For a map with string keys an object literal can be used, for example
|
| - * `map({'hi': 1, 'there': 2})`.
|
| - *
|
| - * Otherwise an array should be used, for example `map([1, 2, 3, 4])` will
|
| - * create a map with keys [1, 3] and values [2, 4]. Each key-value pair
|
| - * should be adjacent entries in the array.
|
| - *
|
| - * For a map with no keys the function can be called with no arguments, for
|
| - * example `map()`.
|
| - */
|
| - // TODO(jmesserly): this could be faster
|
| function map(values) {
|
| let map = collection.LinkedHashMap.new();
|
| if (Array.isArray(values)) {
|
| @@ -290,50 +175,28 @@ dart_library.library('dart/_operations', null, /* Imports */[
|
| }
|
| return map;
|
| }
|
| - exports.map = map;
|
| -
|
| function assert(condition) {
|
| - if (!condition) errors.throwAssertionError();
|
| + if (!condition) _errors.throwAssertionError();
|
| }
|
| - exports.assert = assert;
|
| -
|
| - let _stack = new WeakMap();
|
| - function throw_(obj) {
|
| + const _stack = new WeakMap();
|
| + function throw$(obj) {
|
| if (obj != null && (typeof obj == 'object' || typeof obj == 'function')) {
|
| - // TODO(jmesserly): couldn't we store the most recent stack in a single
|
| - // variable? There should only be one active stack trace. That would
|
| - // allow it to work for things like strings and numbers.
|
| _stack.set(obj, new Error());
|
| }
|
| throw obj;
|
| }
|
| - exports.throw = throw_;
|
| -
|
| function getError(exception) {
|
| var stack = _stack.get(exception);
|
| return stack !== void 0 ? stack : exception;
|
| }
|
| -
|
| - // This is a utility function: it is only intended to be called from dev
|
| - // tools.
|
| function stackPrint(exception) {
|
| var error = getError(exception);
|
| console.log(error.stack ? error.stack : 'No stack trace for: ' + error);
|
| }
|
| - exports.stackPrint = stackPrint;
|
| -
|
| function stackTrace(exception) {
|
| var error = getError(exception);
|
| return _js_helper.getTraceFromException(error);
|
| }
|
| - exports.stackTrace = stackTrace;
|
| -
|
| - /**
|
| - * Implements a sequence of .? operations.
|
| - *
|
| - * Will call each successive callback, unless one returns null, which stops
|
| - * the sequence.
|
| - */
|
| function nullSafe(obj, ...callbacks) {
|
| if (obj == null) return obj;
|
| for (const callback of callbacks) {
|
| @@ -342,27 +205,11 @@ dart_library.library('dart/_operations', null, /* Imports */[
|
| }
|
| return obj;
|
| }
|
| - exports.nullSafe = nullSafe;
|
| -
|
| - let _value = Symbol('_value');
|
| - /**
|
| - * Looks up a sequence of [keys] in [map], recursively, and
|
| - * returns the result. If the value is not found, [valueFn] will be called to
|
| - * add it. For example:
|
| - *
|
| - * let map = new Map();
|
| - * putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world');
|
| - *
|
| - * ... will create a Map with a structure like:
|
| - *
|
| - * { 1: { 2: { 'hi ': { 'there ': 'world' } } } }
|
| - */
|
| + const _value = Symbol("_value");
|
| function multiKeyPutIfAbsent(map, keys, valueFn) {
|
| for (let k of keys) {
|
| let value = map.get(k);
|
| if (!value) {
|
| - // TODO(jmesserly): most of these maps are very small (e.g. 1 item),
|
| - // so it may be worth optimizing for that.
|
| map.set(k, value = new Map());
|
| }
|
| map = value;
|
| @@ -372,93 +219,96 @@ dart_library.library('dart/_operations', null, /* Imports */[
|
| map.set(_value, value);
|
| return value;
|
| }
|
| -
|
| - /** The global constant table. */
|
| const constants = new Map();
|
| -
|
| - /**
|
| - * Canonicalize a constant object.
|
| - *
|
| - * Preconditions:
|
| - * - `obj` is an objects or array, not a primitive.
|
| - * - nested values of the object are themselves already canonicalized.
|
| - */
|
| - function constant(obj) {
|
| + function const$(obj) {
|
| let objectKey = [rtti.realRuntimeType(obj)];
|
| - // TODO(jmesserly): there's no guarantee in JS that names/symbols are
|
| - // returned in the same order.
|
| - //
|
| - // We could probably get the same order if we're judicious about
|
| - // initializing fields in a consistent order across all const constructors.
|
| - // Alternatively we need a way to sort them to make consistent.
|
| - //
|
| - // Right now we use the (name,value) pairs in sequence, which prevents
|
| - // an object with incorrect field values being returned, but won't
|
| - // canonicalize correctly if key order is different.
|
| for (let name of getOwnNamesAndSymbols(obj)) {
|
| objectKey.push(name);
|
| objectKey.push(obj[name]);
|
| }
|
| return multiKeyPutIfAbsent(constants, objectKey, () => obj);
|
| }
|
| - exports.const = constant;
|
| -
|
| -
|
| - // The following are helpers for Object methods when the receiver
|
| - // may be null or primitive. These should only be generated by
|
| - // the compiler.
|
| function hashCode(obj) {
|
| if (obj == null) {
|
| return 0;
|
| }
|
| - // TODO(vsm): What should we do for primitives and non-Dart objects?
|
| switch (typeof obj) {
|
| - case "number":
|
| - case "boolean":
|
| - return obj & 0x1FFFFFFF;
|
| - case "string":
|
| - // TODO(vsm): Call the JSString hashCode?
|
| - return obj.length;
|
| + case "number":
|
| + case "boolean":
|
| + {
|
| + return obj & 0x1FFFFFFF;
|
| + }
|
| + case "string":
|
| + {
|
| + return obj.length;
|
| + }
|
| }
|
| return obj.hashCode;
|
| }
|
| - exports.hashCode = hashCode;
|
| -
|
| function toString(obj) {
|
| if (obj == null) {
|
| return "null";
|
| }
|
| return obj.toString();
|
| }
|
| - exports.toString = toString;
|
| -
|
| function noSuchMethod(obj, invocation) {
|
| if (obj == null) {
|
| - errors.throwNoSuchMethod(obj, invocation.memberName,
|
| - invocation.positionalArguments, invocation.namedArguments);
|
| + throwNoSuchMethod(obj, invocation.memberName, invocation.positionalArguments, invocation.namedArguments);
|
| }
|
| switch (typeof obj) {
|
| case "number":
|
| case "boolean":
|
| case "string":
|
| - errors.throwNoSuchMethod(obj, invocation.memberName,
|
| - invocation.positionalArguments, invocation.namedArguments);
|
| + {
|
| + throwNoSuchMethod(obj, invocation.memberName, invocation.positionalArguments, invocation.namedArguments);
|
| + }
|
| }
|
| return obj.noSuchMethod(invocation);
|
| }
|
| - exports.noSuchMethod = noSuchMethod;
|
| -
|
| - class JsIterator {
|
| + const JsIterator = class JsIterator {
|
| constructor(dartIterator) {
|
| this.dartIterator = dartIterator;
|
| }
|
| next() {
|
| let i = this.dartIterator;
|
| let done = !i.moveNext();
|
| - return { done: done, value: done ? void 0 : i.current };
|
| + return {done: done, value: done ? void 0 : i.current};
|
| }
|
| - }
|
| + };
|
| + // Exports:
|
| + exports.getOwnNamesAndSymbols = getOwnNamesAndSymbols;
|
| + exports.getOwnPropertyNames = getOwnPropertyNames;
|
| + exports.hasOwnProperty = hasOwnProperty;
|
| + exports.dload = dload;
|
| + exports.dput = dput;
|
| + exports.checkApply = checkApply;
|
| + exports.throwNoSuchMethod = throwNoSuchMethod;
|
| + exports.checkAndCall = checkAndCall;
|
| + exports.dcall = dcall;
|
| + exports.callMethod = callMethod;
|
| + exports.dsend = dsend;
|
| + exports.dindex = dindex;
|
| + exports.dsetindex = dsetindex;
|
| + exports.strongInstanceOf = strongInstanceOf;
|
| + exports.instanceOfOrNull = instanceOfOrNull;
|
| + exports.instanceOf = instanceOf;
|
| + exports.cast = cast;
|
| + exports.asInt = asInt;
|
| + exports.arity = arity;
|
| + exports.equals = equals;
|
| + exports.notNull = notNull;
|
| + exports.map = map;
|
| + exports.assert = assert;
|
| + exports.throw = throw$;
|
| + exports.getError = getError;
|
| + exports.stackPrint = stackPrint;
|
| + exports.stackTrace = stackTrace;
|
| + exports.nullSafe = nullSafe;
|
| + exports.multiKeyPutIfAbsent = multiKeyPutIfAbsent;
|
| + exports.constants = constants;
|
| + exports.const = const$;
|
| + exports.hashCode = hashCode;
|
| + exports.toString = toString;
|
| + exports.noSuchMethod = noSuchMethod;
|
| exports.JsIterator = JsIterator;
|
| -
|
| -
|
| });
|
|
|