Index: lib/runtime/_rtti.js |
diff --git a/lib/runtime/_rtti.js b/lib/runtime/_rtti.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3dbf4ae463b3d1c66a4b4114630691b9708f629c |
--- /dev/null |
+++ b/lib/runtime/_rtti.js |
@@ -0,0 +1,149 @@ |
+// 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 the association between runtime objects and |
+ * runtime types. |
+*/ |
+ |
+dart_library.library('dart_runtime/_rtti', null, /* Imports */[ |
+], /* Lazy Imports */[ |
+ 'dart/core', |
+ 'dart_runtime/_types' |
+], function(exports, core, types) { |
+ 'use strict'; |
+ |
+ const defineLazyProperty = dart_utils.defineLazyProperty; |
+ |
+ const defineProperty = Object.defineProperty; |
+ |
+ const slice = [].slice; |
+ |
+ /** |
+ *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 types.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 = types.functionType.apply(null, args); |
+ } |
+ tag(closure, t); |
+ return closure; |
+ } |
+ exports.fn = fn; |
+ |
+ // 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; |
+ } |
+ |
+ function runtimeType(obj) { |
+ let result = checkPrimitiveType(obj); |
+ if (result !== null) return result; |
+ return obj.runtimeType; |
+ } |
+ exports.runtimeType = runtimeType; |
+ |
+ 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 types.functionType(types.bottom, args); |
+ } |
+ |
+ /** |
+ * 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; |
+ } |
+ exports.realRuntimeType = realRuntimeType; |
+ |
+ function LazyTagged(infoFn) { |
+ class _Tagged { |
+ get [_runtimeType]() {return infoFn();} |
+ } |
+ return _Tagged; |
+ } |
+ exports.LazyTagged = LazyTagged; |
+ |
+ function read(value) { |
+ return value[_runtimeType]; |
+ } |
+ exports.read = read; |
+ |
+ function tag(value, info) { |
+ value[_runtimeType] = info; |
+ } |
+ exports.tag = tag; |
+ |
+ function tagComputed(value, compute) { |
+ defineProperty(value, _runtimeType, { get: compute }); |
+ } |
+ exports.tagComputed = tagComputed; |
+ |
+ function tagMemoized(value, compute) { |
+ let cache = null; |
+ function getter() { |
+ if (compute == null) return cache; |
+ cache = compute(); |
+ compute = null; |
+ return cache; |
+ } |
+ tagComputed(value, getter); |
+ } |
+ exports.tagMemoized = tagMemoized; |
+}); |