Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Unified Diff: lib/runtime/dart_runtime.js

Issue 1182653002: Refactor runtime into libraries, better type reps (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Address comments 2 Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/runtime/dart_library.js ('k') | lib/runtime/dart_utils.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/runtime/dart_runtime.js
diff --git a/lib/runtime/dart_runtime.js b/lib/runtime/dart_runtime.js
index 0c1df96582a0ec8ae04602a9d2ffbe98f39fe3d7..914636ae8cd900771054820bbc86879cfea34510 100644
--- a/lib/runtime/dart_runtime.js
+++ b/lib/runtime/dart_runtime.js
@@ -2,1461 +2,106 @@
// 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.
-var dart, dartx;
-(function (dart) {
+dart_library.library('dart_runtime/dart', null, /* Imports */[
+ 'dart_runtime/_classes',
+ 'dart_runtime/_errors',
+ 'dart_runtime/_operations',
+ 'dart_runtime/_rtti',
+ 'dart_runtime/_types',
+], /* Lazy Imports */[
+ 'dart/_js_helper'
+], function(exports, classes, errors, operations, rtti, types, _js_helper) {
'use strict';
- const defineProperty = Object.defineProperty;
- const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
- const getOwnPropertyNames = Object.getOwnPropertyNames;
- const getOwnPropertySymbols = Object.getOwnPropertySymbols;
- const hasOwnProperty = Object.prototype.hasOwnProperty;
- const slice = [].slice;
-
- let _constructorSig = Symbol('sigCtor');
- let _methodSig = Symbol("sig");
- let _staticSig = Symbol("sigStatic");
-
- function getOwnNamesAndSymbols(obj) {
- return getOwnPropertyNames(obj).concat(getOwnPropertySymbols(obj));
- }
-
- function dload(obj, field) {
- field = _canonicalFieldName(obj, field, [], field);
- if (_getMethodType(obj, field) !== void 0) {
- return dart.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];
-
- // TODO(vsm): Check this more robustly.
- if (typeof result == "function" && !hasOwnProperty.call(obj, field)) {
- // This appears to be a method tearoff. Bind this.
- return result.bind(obj);
- }
- return result;
- }
- dart.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;
- }
- dart.dput = dput;
-
- function throwRuntimeError(message) {
- throw Error(message);
- }
-
- // TODO(jmesserly): this should call noSuchMethod, not throw.
- function throwNoSuchMethod(obj, name, args, opt_func) {
- if (obj === void 0) obj = opt_func;
- throw new core.NoSuchMethodError(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 = _getMethodType(f, 'call');
- f = f.call;
- }
- if (!(f instanceof Function)) {
- 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 = _getFunctionType(f);
- }
-
- if (!ftype) {
- // TODO(leafp): Allow JS objects to go through?
- // This includes the DOM.
- return f.apply(obj, args);
- }
-
- if (ftype.checkApply(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 args = slice.call(arguments, 1);
- let ftype = _getFunctionType(f);
- return checkAndCall(f, ftype, void 0, args, 'call');
- }
- dart.dcall = dcall;
-
- let _extensionType = Symbol('extensionType');
- function _canonicalFieldName(obj, name, args, displayName) {
- if (obj[_extensionType]) {
- let extension = dartx[name];
- if (extension) return extension;
- // 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.
- throwNoSuchMethod(obj, displayName, args);
- }
- return name;
- }
-
- /** Shared code for dsend, dindex, and dsetindex. */
- function callMethod(obj, name, args, displayName) {
- let symbol = _canonicalFieldName(obj, name, args, displayName);
- let f = obj[symbol];
- let ftype = _getMethodType(obj, name);
- return checkAndCall(f, ftype, obj, args, displayName);
- }
-
- function dsend(obj, method/*, ...args*/) {
- return callMethod(obj, method, slice.call(arguments, 2));
- }
- dart.dsend = dsend;
-
- function dindex(obj, index) {
- return callMethod(obj, 'get', [index], '[]');
- }
- dart.dindex = dindex;
-
- function dsetindex(obj, index, value) {
- return callMethod(obj, 'set', [index, value], '[]=');
+ function _export(value) {
+ if (value) return value;
+ console.log("Re-exporting null field: " + name);
+ throw "Bad export";
}
- dart.dsetindex = dsetindex;
-
- function _typeName(type) {
- if (typeof(type) == "function") {
- let name = type.name;
- let args = type[dart.typeArguments];
- if (args) {
- name += '<';
- for (let i = 0; i < args.length; ++i) {
- if (i > 0) name += ', ';
- name += _typeName(args[i]);
- }
- name += '>';
- }
- return name;
- } else {
- return type.toString();
- }
- }
- dart.typeName = _typeName;
-
- 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.
- 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)) {
- console.error('Ignoring cast fail from ' + _typeName(actual) +
- ' to ' + _typeName(type));
- return true;
- }
- return false;
- }
-
- function cast(obj, type) {
- // TODO(vsm): handle non-nullable types
- if (obj == null) return obj;
- let actual = realRuntimeType(obj);
- if (isSubtype(actual, type)) return obj;
- if (_ignoreTypeFailure(actual, type)) return obj;
- throw new _js_helper.CastErrorImplementation(actual, type);
- }
- dart.as = cast;
-
-
- // TODO(vsm): How should we encode the runtime type?
- const _runtimeType = Symbol('_runtimeType');
-
- function checkPrimitiveType(obj) {
- switch (typeof obj) {
- case "undefined":
- return core.Null;
- case "number":
- return Math.floor(obj) == obj ? core.int : core.double;
- case "boolean":
- return core.bool;
- case "string":
- return core.String;
- case "symbol":
- return Symbol;
- }
- // Undefined is handled above. For historical reasons,
- // typeof null == "object" in JS.
- if (obj === null) return core.Null;
- return null;
- }
-
- /**
- * Returns the runtime type of obj. This is the same as `obj.realRuntimeType`
- * but will not call an overridden getter.
- *
- * Currently this will return null for non-Dart objects.
- */
- function realRuntimeType(obj) {
- let result = checkPrimitiveType(obj);
- if (result !== null) return result;
- // TODO(vsm): Should we treat Dart and JS objects differently here?
- // E.g., we can check if obj instanceof core.Object to differentiate.
- result = obj[_runtimeType];
- if (result) return result;
- result = obj.constructor;
- if (result == Function) {
- return getFunctionType(obj);
- }
- return result;
- }
- dart.realRuntimeType = realRuntimeType;
-
- function instanceOf(obj, type) {
- return isSubtype(realRuntimeType(obj), type);
- }
- dart.is = instanceOf;
-
- function instanceOfOrNull(obj, type) {
- // FIXME(vsm): This is used only in checkApply.
- // Just log failures due to generics for now.
- if ((obj == null) || instanceOf(obj, type)) return true;
- let actual = realRuntimeType(obj);
- if (_ignoreTypeFailure(actual, type)) return true;
- return false;
- }
-
- /**
- * Computes the canonical type.
- * This maps JS types onto their corresponding Dart Type.
- */
- // TODO(jmesserly): lots more needs to be done here.
- function canonicalType(t) {
- if (t === Object) return core.Object;
- if (t === Function) return core.Function;
- if (t === Array) return core.List;
-
- // We shouldn't normally get here with these types, unless something strange
- // happens like subclassing Number in JS and passing it to Dart.
- if (t === String) return core.String;
- if (t === Number) return core.double;
- if (t === Boolean) return core.bool;
- return t;
- }
-
- const subtypeMap = new Map();
- function isSubtype(t1, t2) {
- // See if we already know the answer
- // TODO(jmesserly): general purpose memoize function?
- let map = subtypeMap.get(t1);
- let result;
- if (map) {
- result = map.get(t2);
- if (result !== void 0) return result;
- } else {
- subtypeMap.set(t1, map = new Map());
- }
- if (t2 == core.Type) {
- // Special case Types.
- result = t1.prototype instanceof core.Type ||
- t1 instanceof AbstractFunctionType ||
- isSubtype_(t1, t2);
- } else {
- result = isSubtype_(t1, t2)
- }
- map.set(t2, result);
- return result;
- }
- dart.isSubtype = isSubtype;
-
- function _isBottom(type, dynamicIsBottom) {
- return (type == dart.dynamic && dynamicIsBottom) || type == dart.bottom;
- }
-
- function _isTop(type, dynamicIsBottom) {
- return type == core.Object || (type == dart.dynamic && !dynamicIsBottom);
- }
-
- function isSubtype_(t1, t2, opt_dynamicIsBottom) {
- let dynamicIsBottom =
- opt_dynamicIsBottom === void 0 ? false : opt_dynamicIsBottom;
-
- t1 = canonicalType(t1);
- t2 = canonicalType(t2);
- if (t1 == t2) return true;
-
- // In Dart, dynamic is effectively both top and bottom.
- // Here, we treat dynamic as one or the other depending on context,
- // but not both.
-
- // Trivially true.
- if (_isTop(t2, dynamicIsBottom) || _isBottom(t1, dynamicIsBottom)) {
- return true;
- }
-
- // Trivially false.
- if (_isTop(t1, dynamicIsBottom) || _isBottom(t2, dynamicIsBottom)) {
- return false;
- }
-
- // "Traditional" name-based subtype check.
- if (isClassSubType(t1, t2)) {
- return true;
- }
-
- // Function subtyping.
- // TODO(vsm): Handle Objects with call methods. Those are functions
- // even if they do not *nominally* subtype core.Function.
- if (isFunctionType(t1) &&
- isFunctionType(t2)) {
- return isFunctionSubType(t1, t2);
- }
- return false;
- }
-
- function safeGetOwnProperty(obj, name) {
- let desc = getOwnPropertyDescriptor(obj, name);
- if (desc) return desc.value;
- }
-
- function isClassSubType(t1, t2) {
- // We support Dart's covariant generics with the caveat that we do not
- // substitute bottom for dynamic in subtyping rules.
- // I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow:
- // - S !<: S<T1, ..., Tn>
- // - S<dynamic, ..., dynamic> !<: S<T1, ..., Tn>
- t1 = canonicalType(t1);
- assert(t2 == canonicalType(t2));
- if (t1 == t2) return true;
-
- if (t1 == core.Object) return false;
-
- // If t1 is a JS Object, we may not hit core.Object.
- if (t1 == null) return t2 == core.Object || t2 == dart.dynamic;
-
- // Check if t1 and t2 have the same raw type. If so, check covariance on
- // type parameters.
- let raw1 = safeGetOwnProperty(t1, dart.originalDeclaration);
- let raw2 = safeGetOwnProperty(t2, dart.originalDeclaration);
- if (raw1 != null && raw1 == raw2) {
- let typeArguments1 = safeGetOwnProperty(t1, dart.typeArguments);
- let typeArguments2 = safeGetOwnProperty(t2, dart.typeArguments);
- let length = typeArguments1.length;
- if (typeArguments2.length == 0) {
- // t2 is the raw form of t1
- return true;
- } else if (length == 0) {
- // t1 is raw, but t2 is not
- return false;
- }
- assert(length == typeArguments2.length);
- for (let i = 0; i < length; ++i) {
- if (!isSubtype(typeArguments1[i], typeArguments2[i])) {
- return false;
- }
- }
- return true;
- }
-
- // Check superclass.
- if (isClassSubType(t1.__proto__, t2)) return true;
-
- // Check mixins.
- let mixins = safeGetOwnProperty(t1, dart.mixins);
- if (mixins) {
- for (let m1 of mixins) {
- // TODO(jmesserly): remove the != null check once we can load core libs.
- if (m1 != null && isClassSubType(m1, t2)) return true;
- }
- }
-
- // Check interfaces.
- let getInterfaces = safeGetOwnProperty(t1, dart.implements);
- if (getInterfaces) {
- for (let i1 of getInterfaces()) {
- // TODO(jmesserly): remove the != null check once we can load core libs.
- if (i1 != null && isClassSubType(i1, t2)) return true;
- }
- }
-
- return false;
- }
-
- // TODO(jmesserly): this isn't currently used, but it could be if we want
- // `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile
- // time.
- function isGroundType(type) {
- // TODO(vsm): Cache this if we start using it at runtime.
-
- if (type instanceof AbstractFunctionType) {
- if (!_isTop(type.returnType, false)) return false;
- for (let i = 0; i < type.args.length; ++i) {
- if (!_isBottom(type.args[i], true)) return false;
- }
- for (let i = 0; i < type.optionals.length; ++i) {
- if (!_isBottom(type.optionals[i], true)) return false;
- }
- let names = getOwnPropertyNames(type.named);
- for (let i = 0; i < names.length; ++i) {
- if (!_isBottom(type.named[names[i]], true)) return false;
- }
- return true;
- }
-
- let typeArgs = safeGetOwnProperty(type, dart.typeArguments);
- if (!typeArgs) return true;
- for (let t of typeArgs) {
- if (t != core.Object && t != dart.dynamic) return false;
- }
- return true;
- }
- dart.isGroundType = isGroundType;
-
- 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 };
- }
- dart.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;
- }
- dart.equals = equals;
-
- /** Checks that `x` is not null or undefined. */
- function notNull(x) {
- if (x == null) throwRuntimeError('expected not-null value');
- return x;
- }
- dart.notNull = notNull;
-
- class AbstractFunctionType {
- constructor() {
- this._stringValue = null;
- }
-
- /// Check that a function of this type can be applied to
- /// actuals.
- checkApply(actuals) {
- if (actuals.length < this.args.length) return false;
- let index = 0;
- for(let i = 0; i < this.args.length; ++i) {
- if (!instanceOfOrNull(actuals[i], this.args[i])) return false;
- ++index;
- }
- if (actuals.length == this.args.length) return true;
- let extras = actuals.length - this.args.length;
- if (this.optionals.length > 0) {
- if (extras > this.optionals.length) return false;
- for(let i = 0, j=index; i < extras; ++i, ++j) {
- if (!instanceOfOrNull(actuals[j], this.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(this.named).length == 0) return false;
- let opts = actuals[index];
- let names = getOwnPropertyNames(opts);
- // This is something other than a map
- if (names.length == 0) return false;
- for (name of names) {
- if (!(Object.prototype.hasOwnProperty.call(this.named, name))) {
- return false;
- }
- if (!instanceOfOrNull(opts[name], this.named[name])) return false;
- }
- return true;
- }
-
- toString() { return this.name; }
-
- get name() {
- if (this._stringValue) return this._stringValue;
-
- let buffer = '(';
- for (let i = 0; i < this.args.length; ++i) {
- if (i > 0) {
- buffer += ', ';
- }
- buffer += _typeName(this.args[i]);
- }
- if (this.optionals.length > 0) {
- if (this.args.length > 0) buffer += ', ';
- buffer += '[';
- for (let i = 0; i < this.optionals.length; ++i) {
- if (i > 0) {
- buffer += ', ';
- }
- buffer += _typeName(this.optionals[i]);
- }
- buffer += ']';
- } else if (Object.keys(this.named).length > 0) {
- if (this.args.length > 0) buffer += ', ';
- buffer += '{';
- let names = getOwnPropertyNames(this.named).sort();
- for (let i = 0; i < names.length; ++i) {
- if (i > 0) {
- buffer += ', ';
- }
- buffer += names[i] + ': ' + _typeName(this.named[names[i]]);
- }
- buffer += '}';
- }
-
- buffer += ') -> ' + _typeName(this.returnType);
- this._stringValue = buffer;
- return buffer;
- }
- }
-
- class FunctionType extends AbstractFunctionType {
- constructor(returnType, args, optionals, named) {
- super();
- this.returnType = returnType;
- this.args = args;
- this.optionals = optionals;
- this.named = named;
- }
- }
-
- /// Tag a closure with a type, using one of three forms:
- /// dart.fn(cls) marks cls has having no optional or named
- /// parameters, with all argument and return types as dynamic
- /// dart.fn(cls, func) marks cls with the lazily computed
- /// runtime type as computed by func()
- /// dart.fn(cls, rType, argsT, extras) marks cls as having the
- /// runtime type dart.functionType(rType, argsT, extras)
- function fn(closure/* ...args*/) {
- // Closure and a lazy type constructor
- if (arguments.length == 2) {
- defineLazyProperty(closure, _runtimeType, {get : arguments[1]});
- return closure;
- }
- let t;
- if (arguments.length == 1) {
- // No type arguments, it's all dynamic
- let len = closure.length;
- let build = () => {
- let args = Array.apply(null, new Array(len)).map(() => core.Object);
- return functionType(core.Object, args);
- };
- // We could be called before Object is defined.
- if (core.Object === void 0) return fn(closure, build);
- t = build();
- } else {
- // We're passed the piecewise components of the function type,
- // construct it.
- let args = slice.call(arguments, 1);
- t = functionType.apply(null, args);
- }
- setRuntimeType(closure, t);
- return closure;
- }
- dart.fn = fn;
-
- function functionType(returnType, args, extra) {
- // TODO(vsm): Cache / memomize?
- let optionals;
- let named;
- if (extra === void 0) {
- optionals = [];
- named = {};
- } else if (extra instanceof Array) {
- optionals = extra;
- named = {};
- } else {
- optionals = [];
- named = extra;
- }
- return new FunctionType(returnType, args, optionals, named);
- }
- dart.functionType = functionType;
-
- class Typedef extends AbstractFunctionType {
- constructor(name, closure) {
- super();
- this._name = name;
- this._closure = closure;
- this._functionType = null;
- }
-
- get name() {
- return this._name;
- }
-
- get functionType() {
- if (!this._functionType) {
- this._functionType = this._closure();
- }
- return this._functionType;
- }
-
- get returnType() {
- return this.functionType.returnType;
- }
-
- get args() {
- return this.functionType.args;
- }
-
- get optionals() {
- return this.functionType.optionals;
- }
-
- get named() {
- return this.functionType.named;
- }
- }
-
- function typedef(name, closure) {
- return new Typedef(name, closure);
- }
- dart.typedef = typedef;
-
- function isFunctionType(type) {
- return isClassSubType(type, core.Function) ||
- type instanceof AbstractFunctionType;
- }
-
- function getFunctionType(obj) {
- // TODO(vsm): Encode this properly on the function for Dart-generated code.
- let args = Array.apply(null, new Array(obj.length)).map(() => core.Object);
- return functionType(dart.bottom, args);
- }
-
- function isFunctionSubType(ft1, ft2) {
- if (ft2 == core.Function) {
- return true;
- }
-
- let ret1 = ft1.returnType;
- let ret2 = ft2.returnType;
-
- if (!isSubtype_(ret1, ret2)) {
- // Covariant return types
- // Note, void (which can only appear as a return type) is effectively
- // treated as dynamic. If the base return type is void, we allow any
- // subtype return type.
- // E.g., we allow:
- // () -> int <: () -> void
- if (ret2 != dart.void) {
- return false;
- }
- }
-
- let args1 = ft1.args;
- let args2 = ft2.args;
-
- if (args1.length > args2.length) {
- return false;
- }
-
- for (let i = 0; i < args1.length; ++i) {
- if (!isSubtype_(args2[i], args1[i], true)) {
- return false;
- }
- }
-
- let optionals1 = ft1.optionals;
- let optionals2 = ft2.optionals;
- if (args1.length + optionals1.length < args2.length + optionals2.length) {
- return false;
- }
-
- let j = 0;
- for (let i = args1.length; i < args2.length; ++i, ++j) {
- if (!isSubtype_(args2[i], optionals1[j], true)) {
- return false;
- }
- }
-
- for (let i = 0; i < optionals2.length; ++i, ++j) {
- if (!isSubtype_(optionals2[i], optionals1[j], true)) {
- return false;
- }
- }
-
- let named1 = ft1.named;
- let named2 = ft2.named;
-
- let names = getOwnPropertyNames(named2);
- for (let i = 0; i < names.length; ++i) {
- let name = names[i];
- let n1 = named1[name];
- let n2 = named2[name];
- if (n1 === void 0) {
- return false;
- }
- if (!isSubtype_(n2, n1, true)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Defines a lazy property.
- * After initial get or set, it will replace itself with a value property.
- */
- // TODO(jmesserly): is this the best implementation for JS engines?
- // TODO(jmesserly): reusing descriptor objects has been shown to improve
- // performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
- function defineLazyProperty(to, name, desc) {
- let init = desc.get;
- let writable = !!desc.set;
- function lazySetter(value) {
- defineProperty(to, name, { value: value, writable: writable });
- }
- function lazyGetter() {
- // Clear the init function to detect circular initialization.
- let f = init;
- if (f === null) throwRuntimeError('circular initialization for field ' + name);
- init = null;
-
- // Compute and store the value.
- let value = f();
- lazySetter(value);
- return value;
- }
- desc.get = lazyGetter;
- desc.configurable = true;
- if (writable) desc.set = lazySetter;
- defineProperty(to, name, desc);
- }
-
- function defineLazy(to, from) {
- for (let name of getOwnNamesAndSymbols(from)) {
- defineLazyProperty(to, name, getOwnPropertyDescriptor(from, name));
- }
- }
- // TODO(jmesserly): these are identical, but this makes it easier to grep for.
- dart.defineLazyClass = defineLazy;
- dart.defineLazyProperties = defineLazy;
- dart.defineLazyClassGeneric = defineLazyProperty;
-
- function defineMemoizedGetter(obj, name, get) {
- let cache = null;
- function getter() {
- if (cache != null) return cache;
- cache = get();
- get = null;
- return cache;
- }
- defineProperty(obj, name, {get: getter, configurable: true});
- }
-
- function copyPropertiesHelper(to, from, names) {
- for (let name of names) {
- defineProperty(to, name, getOwnPropertyDescriptor(from, name));
- }
- return to;
- }
-
- /**
- * Copy properties from source to destination object.
- * This operation is commonly called `mixin` in JS.
- */
- function copyProperties(to, from) {
- return copyPropertiesHelper(to, from, getOwnNamesAndSymbols(from));
- }
- dart.copyProperties = copyProperties;
-
- function getExtensionSymbol(name) {
- let sym = dartx[name];
- if (!sym) dartx[name] = sym = Symbol('dartx.' + name);
- return sym;
- }
-
- function defineExtensionNames(names) {
- names.forEach(getExtensionSymbol);
- }
- dart.defineExtensionNames = defineExtensionNames;
-
- /**
- * Copy symbols from the prototype of the source to destination.
- * These are the only properties safe to copy onto an existing public
- * JavaScript class.
- */
- function registerExtension(jsType, dartExtType) {
- let extProto = dartExtType.prototype;
- let jsProto = jsType.prototype;
-
- // Mark the JS type's instances so we can easily check for extensions.
- assert(jsProto[_extensionType] === void 0);
- jsProto[_extensionType] = extProto;
-
- let dartObjProto = core.Object.prototype;
- while (extProto !== dartObjProto && extProto !== jsProto) {
- copyPropertiesHelper(jsProto, extProto, getOwnPropertySymbols(extProto));
- extProto = extProto.__proto__;
- }
- }
- dart.registerExtension = registerExtension;
-
- /**
- * Mark a concrete type as implementing extension methods.
- * For example: `class MyIter implements Iterable`.
- *
- * This takes a list of names, which are the extension methods implemented.
- * It will add a forwarder, so the extension method name redirects to the
- * normal Dart method name. For example:
- *
- * defineExtensionMembers(MyType, ['add', 'remove']);
- *
- * Results in:
- *
- * MyType.prototype[dartx.add] = MyType.prototype.add;
- * MyType.prototype[dartx.remove] = MyType.prototype.remove;
- */
- // TODO(jmesserly): essentially this gives two names to the same method.
- // This benefit is roughly equivalent call performance either way, but the
- // cost is we need to call defineExtensionMEmbers any time a subclass overrides
- // one of these methods.
- function defineExtensionMembers(type, methodNames) {
- let proto = type.prototype;
- for (let name of methodNames) {
- let method = getOwnPropertyDescriptor(proto, name);
- defineProperty(proto, getExtensionSymbol(name), method);
- }
- // Ensure the signature is available too.
- // TODO(jmesserly): not sure if we can do this in a cleaner way. Essentially
- // we need to copy the signature (and in the future, other data like
- // annotations) any time we copy a method as part of our metaprogramming.
- // It might be more friendly to JS metaprogramming if we include this info
- // on the function.
- let originalSigFn = getOwnPropertyDescriptor(type, _methodSig).get;
- defineMemoizedGetter(type, _methodSig, function() {
- let sig = originalSigFn();
- for (let name of methodNames) {
- sig[getExtensionSymbol(name)] = sig[name];
- }
- return sig;
- });
- }
- dart.defineExtensionMembers = defineExtensionMembers;
-
- function setBaseClass(derived, base) {
- // Link the extension to the type it's extending as a base class.
- derived.prototype.__proto__ = base.prototype;
- }
- dart.setBaseClass = setBaseClass;
-
- /**
- * This is called whenever a derived class needs to introduce a new field,
- * shadowing a field or getter/setter pair on its parent.
- *
- * This is important because otherwise, trying to read or write the field
- * would end up calling the getter or setter, and one of those might not even
- * exist, resulting in a runtime error. Even if they did exist, that's the
- * wrong behavior if a new field was declared.
- */
- function virtualField(subclass, fieldName) {
- // If the field is already overridden, do nothing.
- let prop = getOwnPropertyDescriptor(subclass.prototype, fieldName);
- if (prop) return;
-
- let symbol = Symbol(subclass.name + '.' + fieldName);
- defineProperty(subclass.prototype, fieldName, {
- get: function() { return this[symbol]; },
- set: function(x) { this[symbol] = x; }
- });
- }
- dart.virtualField = virtualField;
-
- /** The Symbol for storing type arguments on a specialized generic type. */
- dart.mixins = Symbol('mixins');
- dart.implements = Symbol('implements');
- dart.metadata = Symbol('metadata');
-
- /**
- * Returns a new type that mixes members from base and all mixins.
- *
- * Each mixin applies in sequence, with further to the right ones overriding
- * previous entries.
- *
- * For each mixin, we only take its own properties, not anything from its
- * superclass (prototype).
- */
- function mixin(base/*, ...mixins*/) {
- // Create an initializer for the mixin, so when derived constructor calls
- // super, we can correctly initialize base and mixins.
- let mixins = slice.call(arguments, 1);
-
- // Create a class that will hold all of the mixin methods.
- class Mixin extends base {
- // Initializer method: run mixin initializers, then the base.
- [base.name](/*...args*/) {
- // Run mixin initializers. They cannot have arguments.
- // Run them backwards so most-derived mixin is initialized first.
- for (let i = mixins.length - 1; i >= 0; i--) {
- let mixin = mixins[i];
- let init = mixin.prototype[mixin.name];
- if (init) init.call(this);
- }
- // Run base initializer.
- let init = base.prototype[base.name];
- if (init) init.apply(this, arguments);
- }
- }
- // Copy each mixin's methods, with later ones overwriting earlier entries.
- for (let m of mixins) {
- copyProperties(Mixin.prototype, m.prototype);
- }
-
- // Set the signature of the Mixin class to be the composition
- // of the signatures of the mixins.
- dart.setSignature(Mixin, {
- methods: () => {
- let s = {};
- for (let m of mixins) {
- copyProperties(s, m[_methodSig]);
- }
- return s;
- }
- });
-
- // Save mixins for reflection
- Mixin[dart.mixins] = mixins;
- return Mixin;
- }
- dart.mixin = mixin;
-
- /**
- * 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)) {
- for (let i = 0, end = values.length - 1; i < end; i += 2) {
- let key = values[i];
- let value = values[i + 1];
- map.set(key, value);
- }
- } else if (typeof values === 'object') {
- for (let key of getOwnPropertyNames(values)) {
- map.set(key, values[key]);
- }
- }
- return map;
- }
- dart.map = map;
-
- function assert(condition) {
- if (!condition) throw new core.AssertionError();
- }
- dart.assert = assert;
-
- function throw_(obj) { throw obj; }
- dart.throw_ = throw_;
-
- /**
- * Given a class and an initializer method name, creates a constructor
- * function with the same name. For example `new SomeClass.name(args)`.
- */
- function defineNamedConstructor(clazz, name) {
- let proto = clazz.prototype;
- let initMethod = proto[name];
- let ctor = function() { return initMethod.apply(this, arguments); };
- ctor.prototype = proto;
- // Use defineProperty so we don't hit a property defined on Function,
- // like `caller` and `arguments`.
- defineProperty(clazz, name, { value: ctor, configurable: true });
- }
- dart.defineNamedConstructor = defineNamedConstructor;
-
- function stackTrace(exception) {
- return _js_helper.getTraceFromException(exception);
- }
- dart.stackTrace = stackTrace;
-
- /** The Symbol for storing type arguments on a specialized generic type. */
- dart.typeArguments = Symbol('typeArguments');
- dart.originalDeclaration = Symbol('originalDeclaration');
-
- /** Memoize a generic type constructor function. */
- function generic(typeConstructor) {
- let length = typeConstructor.length;
- if (length < 1) throwRuntimeError('must have at least one generic type argument');
-
- let resultMap = new Map();
- function makeGenericType(/*...arguments*/) {
- if (arguments.length != length && arguments.length != 0) {
- throwRuntimeError('requires ' + length + ' or 0 type arguments');
- }
- let args = slice.call(arguments);
- // TODO(leafp): This should really be core.Object for
- // consistency, but Object is not attached to core
- // until the entire core library has been processed,
- // which is too late.
- while (args.length < length) args.push(dart.dynamic);
-
- let value = resultMap;
- for (let i = 0; i < length; i++) {
- let arg = args[i];
- if (arg == null) {
- throwRuntimeError('type arguments should not be null: ' + typeConstructor);
- }
- let map = value;
- value = map.get(arg);
- if (value === void 0) {
- if (i + 1 == length) {
- value = typeConstructor.apply(null, args);
- // Save the type constructor and arguments for reflection.
- if (value) {
- value[dart.typeArguments] = args;
- value[dart.originalDeclaration] = makeGenericType;
- }
- } else {
- value = new Map();
- }
- map.set(arg, value);
- }
- }
- return value;
- }
- return makeGenericType;
- }
- dart.generic = generic;
-
- /// Get the type of a function using the store runtime type
- function _getFunctionType(f) {
- return f[_runtimeType];
- }
-
- /// Get the type of a method using the stored signature
- function _getMethodType(obj, name) {
- if (obj === void 0) return void 0;
- if (obj == null) return void 0;
- let sigObj = obj.__proto__.constructor[_methodSig];
- if (sigObj === void 0) return void 0;
- let parts = sigObj[name];
- if (parts === void 0) return void 0;
- return functionType.apply(null, parts);
- }
-
- /// Get the type of a constructor from a class using the stored signature
- /// If name is undefined, returns the type of the default constructor
- /// Returns undefined if the constructor is not found.
- function _getConstructorType(cls, name) {
- if(!name) name = cls.name;
- if (cls === void 0) return void 0;
- if (cls == null) return void 0;
- let sigCtor = cls[_constructorSig];
- if (sigCtor === void 0) return void 0;
- let parts = sigCtor[name];
- if (parts === void 0) return void 0;
- return functionType.apply(null, parts);
- }
- dart.classGetConstructorType = _getConstructorType;
-
- /// Given an object and a method name, tear off the method.
- /// Sets the runtime type of the torn off method appropriately,
- /// and also binds the object.
- /// TODO(leafp): Consider caching the tearoff on the object?
- function bind(obj, name) {
- let f = obj[name].bind(obj);
- let sig = _getMethodType(obj, name);
- assert(sig);
- setRuntimeType(f, sig);
- return f;
- }
- dart.bind = bind;
-
- // Set up the method signature field on the constructor
- function _setMethodSignature(f, sigF) {
- defineMemoizedGetter(f, _methodSig, () => {
- let sigObj = sigF();
- sigObj.__proto__ = f.__proto__[_methodSig];
- return sigObj;
- });
- }
-
- // Set up the constructor signature field on the constructor
- function _setConstructorSignature(f, sigF) {
- defineMemoizedGetter(f, _constructorSig, sigF);
- }
-
- // Set up the static signature field on the constructor
- function _setStaticSignature(f, sigF) {
- defineMemoizedGetter(f, _staticSig, sigF);
- }
-
- // Set the lazily computed runtime type field on static methods
- function _setStaticTypes(f, names) {
+ function exportFrom(value, names) {
for (let name of names) {
- defineProperty(f[name], _runtimeType, { get: function() {
- let parts = f[_staticSig][name];
- return functionType.apply(null, parts);
- }});
- }
- }
-
- /// Set up the type signature of a class (constructor object)
- /// f is a constructor object
- /// signature is an object containing optional properties as follows:
- /// methods: A function returning an object mapping method names
- /// to method types. The function is evaluated lazily and cached.
- /// statics: A function returning an object mapping static method
- /// names to types. The function is evalutated lazily and cached.
- /// names: An array of the names of the static methods. Used to
- /// permit eagerly setting the runtimeType field on the methods
- /// while still lazily computing the type descriptor object.
- function setSignature(f, signature) {
- let constructors =
- ('constructors' in signature) ? signature.constructors : () => ({});
- let methods =
- ('methods' in signature) ? signature.methods : () => ({});
- let statics =
- ('statics' in signature) ? signature.statics : () => ({});
- let names =
- ('names' in signature) ? signature.names : [];
- _setConstructorSignature(f, constructors);
- _setMethodSignature(f, methods);
- _setStaticSignature(f, statics);
- _setStaticTypes(f, names);
- }
- dart.setSignature = setSignature;
-
- 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' } } } }
- */
- 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;
- }
- if (map.has(_value)) return map.get(_value);
- let value = valueFn();
- 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) {
- let objectKey = [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);
- }
- dart.const = constant;
-
- // TODO(vsm): Rationalize these type methods. We're currently using the
- // setType / proto scheme for nominal types (e.g., classes) and the
- // setRuntimeType / field scheme for structural types (e.g., functions
- // - and only in tests for now).
- // See: https://github.com/dart-lang/dev_compiler/issues/172
-
- /** Sets the type of `obj` to be `type` */
- function setType(obj, type) {
- obj.__proto__ = type.prototype;
- return obj;
- }
- dart.setType = setType;
-
- /** Sets the element type of a list literal. */
- function list(obj, elementType) {
- return setType(obj, _interceptors.JSArray$(elementType));
- }
- dart.list = list;
-
- /** Sets the internal runtime type of `obj` to be `type` */
- function setRuntimeType(obj, type) {
- obj[_runtimeType] = type;
- }
- dart.setRuntimeType = setRuntimeType;
-
- // 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;
- }
- return obj.hashCode;
- }
- dart.hashCode = hashCode;
-
- function runtimeType(obj) {
- let result = checkPrimitiveType(obj);
- if (result !== null) return result;
- return obj.runtimeType;
- }
- dart.runtimeType = runtimeType;
-
- function toString(obj) {
- if (obj == null) {
- return "null";
- }
- return obj.toString();
- }
- dart.toString = toString;
-
- function noSuchMethod(obj, invocation) {
- if (obj == null) {
- throw new core.NoSuchMethodError(obj, invocation.memberName,
- invocation.positionalArguments, invocation.namedArguments);
- }
- switch (typeof obj) {
- case "number":
- case "boolean":
- case "string":
- throw new core.NoSuchMethodError(obj, invocation.memberName,
- invocation.positionalArguments, invocation.namedArguments);
- }
- return obj.noSuchMethod(invocation);
- }
- dart.noSuchMethod = noSuchMethod;
-
- 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 };
- }
- }
- dart.JsIterator = JsIterator;
-
- // TODO(jmesserly/vsm): Right now these are sentinels. They should be type
- // objects of some sort, assuming we keep them at runtime.
- function _sentinel(_name) {
- return {
- toString() { return _name; },
- get name() { return this.toString(); }
- };
- }
- dart.dynamic = _sentinel('dynamic');
- dart.void = _sentinel('void');
- dart.bottom = _sentinel('bottom');
-
- dart.global = window || global;
- dart.JsSymbol = Symbol;
-
- // Module support. This is a simplified module system for Dart.
- // Longer term, we can easily migrate to an existing JS module system:
- // ES6, AMD, RequireJS, ....
-
- class LibraryLoader {
- constructor(name, defaultValue, imports, lazyImports, loader) {
- this._name = name;
- this._library = defaultValue ? defaultValue : {};
- this._imports = imports;
- this._lazyImports = lazyImports;
- this._loader = loader;
-
- // Cyclic import detection
- this._state = LibraryLoader.NOT_LOADED;
- }
-
- loadImports(pendingSet) {
- return this.handleImports(this._imports, (lib) => lib.load(pendingSet));
- }
-
- deferLazyImports(pendingSet) {
- return this.handleImports(this._lazyImports,
- (lib) => {
- pendingSet.add(lib._name);
- return lib.stub();
- });
- }
-
- loadLazyImports(pendingSet) {
- return this.handleImports(pendingSet, (lib) => lib.load());
- }
-
- handleImports(list, handler) {
- let results = [];
- for (let name of list) {
- let lib = libraries[name];
- if (!lib) {
- throwRuntimeError('Library not available: ' + name);
- }
- results.push(handler(lib));
- }
- return results;
- }
-
- load(inheritedPendingSet) {
- // Check for cycles
- if (this._state == LibraryLoader.LOADING) {
- throwRuntimeError('Circular dependence on library: ' + this._name);
- } else if (this._state >= LibraryLoader.LOADED) {
- return this._library;
- }
- this._state = LibraryLoader.LOADING;
-
- // Handle imports and record lazy imports
- let pendingSet = inheritedPendingSet ? inheritedPendingSet : new Set();
- let args = this.loadImports(pendingSet);
- args = args.concat(this.deferLazyImports(pendingSet));
-
- // Load the library
- args.unshift(this._library);
- this._loader.apply(null, args);
- this._state = LibraryLoader.LOADED;
-
- // Handle lazy imports
- if (inheritedPendingSet === void 0) {
- // Drain the queue
- this.loadLazyImports(pendingSet);
- }
- this._state = LibraryLoader.READY;
- return this._library;
- }
-
- stub() {
- return this._library;
- }
- }
- LibraryLoader.NOT_LOADED = 0;
- LibraryLoader.LOADING = 1;
- LibraryLoader.LOADED = 2;
- LibraryLoader.READY = 3;
-
- // Map from name to LibraryLoader
- let libraries = new Map();
-
- function library(name, defaultValue, imports, lazyImports, loader) {
- return libraries[name] =
- new LibraryLoader(name, defaultValue, imports, lazyImports, loader);
- }
- dart.library = library;
-
- function import_(libraryName) {
- bootstrap();
- let loader = libraries[libraryName];
- return loader.load();
- }
- dart.import = import_;
-
- function start(libraryName) {
- let library = import_(libraryName);
- _isolate_helper.startRootIsolate(library.main, []);
- }
- dart.start = start;
-
- // Libraries used in this file.
- let core;
- let collection;
- let async;
- let _interceptors;
- let _isolate_helper;
- let _js_helper;
- let _js_primitives;
-
- let _bootstrapped = false;
- function bootstrap() {
- if (_bootstrapped) return;
- _bootstrapped = true;
-
- // Setup stubs for top-level symbols.
- let lazyImport = (name) => libraries[name].stub();
- core = lazyImport('dart/core');
- collection = lazyImport('dart/collection');
- async = lazyImport('dart/async');
- _interceptors = lazyImport('dart/_interceptors');
- _isolate_helper = lazyImport('dart/_isolate_helper');
- _js_helper = lazyImport('dart/_js_helper');
- _js_helper.checkNum = notNull;
- _js_primitives = lazyImport('dart/_js_primitives');
- _js_primitives.printString = (s) => console.log(s);
-
- // Create namespace for dart extension members.
- dartx = dartx || {};
-
- // Force import of core.
- import_('dart/core');
-
- // TODO(vsm): DOM facades?
- // See: https://github.com/dart-lang/dev_compiler/issues/173
- NodeList.prototype.get = function(i) { return this[i]; };
- NamedNodeMap.prototype.get = function(i) { return this[i]; };
- DOMTokenList.prototype.get = function(i) { return this[i]; };
- HTMLCollection.prototype.get = function(i) { return this[i]; };
-
- // TODO(vsm): This is referenced (as init.globalState) from
- // isolate_helper.dart. Where should it go?
- // See: https://github.com/dart-lang/dev_compiler/issues/164
- dart.globalState = null;
- }
-})(dart || (dart = {}));
+ exports[name] = _export(value[name]);
+ }
+ }
+
+ exports.global = window || global;
+ exports.JsSymbol = _export(Symbol);
+
+ // TODO(vsm): This is referenced (as init.globalState) from
+ // isolate_helper.dart. Where should it go?
+ // See: https://github.com/dart-lang/dev_compiler/issues/164
+ exports.globalState = null;
+ _js_helper.checkNum = operations.notNull;
+
+ // Re-exports
+
+ // From classes
+ exportFrom(classes, [
+ 'bind',
+ 'classGetConstructorType',
+ 'dartx',
+ 'defineNamedConstructor',
+ 'defineExtensionNames',
+ 'defineExtensionMembers',
+ 'generic',
+ 'implements',
+ 'list',
+ 'metadata',
+ 'mixin',
+ 'registerExtension',
+ 'setBaseClass',
+ 'setSignature',
+ 'virtualField',
+ ])
+
+ // From dart_utils
+ exportFrom(dart_utils, ['copyProperties']);
+ // Renames
+ exports.defineLazyClass = _export(dart_utils.defineLazy);
+ exports.defineLazyProperties = _export(dart_utils.defineLazy);
+ exports.defineLazyClassGeneric = _export(dart_utils.defineLazyProperty);
+
+ // From operations
+ exportFrom(operations, [
+ 'JsIterator',
+ 'arity',
+ 'assert',
+ 'const',
+ 'dcall',
+ 'dindex',
+ 'dload',
+ 'dput',
+ 'dsend',
+ 'dsetindex',
+ 'equals',
+ 'hashCode',
+ 'map',
+ 'noSuchMethod',
+ 'notNull',
+ 'stackTrace',
+ 'throw_',
+ 'toString',
+ ])
+ // Renames
+ exports.as = _export(operations.cast);
+ exports.is = _export(operations.instanceOf);
+
+ // From types
+ exportFrom(types, [
+ 'bottom',
+ 'dynamic',
+ 'functionType',
+ 'typedef',
+ 'typeName',
+ 'void',
+ ]);
+
+ // From rtti
+ exportFrom(rtti, [
+ 'fn',
+ 'realRuntimeType',
+ 'runtimeType',
+ ]);
+
+});
« no previous file with comments | « lib/runtime/dart_library.js ('k') | lib/runtime/dart_utils.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698