Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 var dart, _js_helper, _js_primitives; | 5 var dart, _js_helper, _js_primitives, dartx; |
| 6 (function (dart) { | 6 (function (dart) { |
| 7 'use strict'; | 7 'use strict'; |
| 8 | 8 |
| 9 // TODO(vsm): This is referenced (as init.globalState) from | 9 // TODO(vsm): This is referenced (as init.globalState) from |
| 10 // isolate_helper.dart. Where should it go? | 10 // isolate_helper.dart. Where should it go? |
| 11 // See: https://github.com/dart-lang/dev_compiler/issues/164 | 11 // See: https://github.com/dart-lang/dev_compiler/issues/164 |
| 12 dart.globalState = null; | 12 dart.globalState = null; |
| 13 | 13 |
| 14 let defineProperty = Object.defineProperty; | 14 const defineProperty = Object.defineProperty; |
| 15 let getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; | 15 const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; |
| 16 let getOwnPropertyNames = Object.getOwnPropertyNames; | 16 const getOwnPropertyNames = Object.getOwnPropertyNames; |
| 17 let getOwnPropertySymbols = Object.getOwnPropertySymbols; | 17 const getOwnPropertySymbols = Object.getOwnPropertySymbols; |
| 18 const hasOwnProperty = Object.prototype.hasOwnProperty; | |
| 19 const slice = [].slice; | |
| 18 | 20 |
| 19 function getOwnNamesAndSymbols(obj) { | 21 function getOwnNamesAndSymbols(obj) { |
| 20 return getOwnPropertyNames(obj).concat(getOwnPropertySymbols(obj)); | 22 return getOwnPropertyNames(obj).concat(getOwnPropertySymbols(obj)); |
| 21 } | 23 } |
| 22 | 24 |
| 23 function dload(obj, field) { | 25 function dload(obj, field) { |
| 24 field = _canonicalFieldName(obj, field); | 26 field = _canonicalFieldName(obj, field, [], field); |
| 25 if (_getMethodType(obj, field) !== void 0) { | 27 if (_getMethodType(obj, field) !== void 0) { |
| 26 return dart.bind(obj, field); | 28 return dart.bind(obj, field); |
| 27 } | 29 } |
| 28 // TODO(vsm): Implement NSM robustly. An 'in' check breaks on certain | 30 // TODO(vsm): Implement NSM robustly. An 'in' check breaks on certain |
| 29 // types. hasOwnProperty doesn't chase the proto chain. | 31 // types. hasOwnProperty doesn't chase the proto chain. |
| 30 // Also, do we want an NSM on regular JS objects? | 32 // Also, do we want an NSM on regular JS objects? |
| 31 // See: https://github.com/dart-lang/dev_compiler/issues/169 | 33 // See: https://github.com/dart-lang/dev_compiler/issues/169 |
| 32 var result = obj[field]; | 34 var result = obj[field]; |
| 33 | 35 |
| 34 // TODO(leafp): Decide whether to keep this for javascript | 36 // TODO(vsm): Check this more robustly. |
| 35 // objects, or just use the javascript semantics. | 37 if (typeof result == "function" && !hasOwnProperty.call(obj, field)) { |
| 36 if (typeof result == "function" && | |
| 37 !Object.prototype.hasOwnProperty.call(obj, field)) { | |
| 38 // This appears to be a method tearoff. Bind this. | 38 // This appears to be a method tearoff. Bind this. |
| 39 return result.bind(obj); | 39 return result.bind(obj); |
| 40 } | 40 } |
| 41 return result; | 41 return result; |
| 42 } | 42 } |
| 43 dart.dload = dload; | 43 dart.dload = dload; |
| 44 | 44 |
| 45 function dput(obj, field, value) { | 45 function dput(obj, field, value) { |
| 46 field = _canonicalFieldName(obj, field); | 46 field = _canonicalFieldName(obj, field, [value], field); |
| 47 // TODO(vsm): Implement NSM and type checks. | 47 // TODO(vsm): Implement NSM and type checks. |
| 48 // See: https://github.com/dart-lang/dev_compiler/issues/170 | 48 // See: https://github.com/dart-lang/dev_compiler/issues/170 |
| 49 obj[field] = value; | 49 obj[field] = value; |
| 50 } | 50 } |
| 51 dart.dput = dput; | 51 dart.dput = dput; |
| 52 | 52 |
| 53 // TODO(jmesserly): this should call noSuchMethod, not throw. | 53 // TODO(jmesserly): this should call noSuchMethod, not throw. |
| 54 function throwNoSuchMethod(obj, name, args, opt_func) { | 54 function throwNoSuchMethod(obj, name, args, opt_func) { |
| 55 if (obj === void 0) obj = opt_func; | 55 if (obj === void 0) obj = opt_func; |
| 56 throw new core.NoSuchMethodError(obj, name, args); | 56 throw new core.NoSuchMethodError(obj, name, args); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 84 if (ftype.checkApply(args)) { | 84 if (ftype.checkApply(args)) { |
| 85 return f.apply(obj, args); | 85 return f.apply(obj, args); |
| 86 } | 86 } |
| 87 | 87 |
| 88 // TODO(leafp): throw a type error (rather than NSM) | 88 // TODO(leafp): throw a type error (rather than NSM) |
| 89 // if the arity matches but the types are wrong. | 89 // if the arity matches but the types are wrong. |
| 90 throwNoSuchMethod(obj, name, args, f); | 90 throwNoSuchMethod(obj, name, args, f); |
| 91 } | 91 } |
| 92 | 92 |
| 93 function dcall(f/*, ...args*/) { | 93 function dcall(f/*, ...args*/) { |
| 94 let args = Array.prototype.slice.call(arguments, 1); | 94 let args = slice.call(arguments, 1); |
| 95 let ftype = _getFunctionType(f); | 95 let ftype = _getFunctionType(f); |
| 96 return checkAndCall(f, ftype, void 0, args, 'call'); | 96 return checkAndCall(f, ftype, void 0, args, 'call'); |
| 97 } | 97 } |
| 98 dart.dcall = dcall; | 98 dart.dcall = dcall; |
| 99 | 99 |
| 100 // TODO(vsm): Automatically build this. | 100 let _extensionType = Symbol('extensionType'); |
| 101 // All dynamic methods should check for these. | 101 function _canonicalFieldName(obj, name, args, displayName) { |
| 102 // See: https://github.com/dart-lang/dev_compiler/issues/142 | 102 if (obj[_extensionType]) { |
| 103 var _extensionMethods = { | 103 var extension = dartx[name]; |
| 104 // Lazy - as these symbols may not be loaded yet. | 104 if (extension) return extension; |
| 105 // TODO(vsm): This should record / check the receiver type | 105 // TODO(jmesserly): in the future we might have types that "overlay" Dart |
| 106 // as well. E.g., only look for core.$map if the receiver | 106 // methods while also exposing the full native API, e.g. dart:html vs |
| 107 // is an Iterable. | 107 // dart:dom. To support that we'd need to fall back to the normal name |
| 108 'map': () => core.$map | 108 // if an extension method wasn't found. |
| 109 }; | 109 throwNoSuchMethod(obj, displayName, args); |
| 110 | 110 } |
| 111 // TODO(leafp): Integrate this with the eventual proper extension | |
| 112 // method system. | |
| 113 function _canonicalFieldName(obj, name) { | |
| 114 if (obj[name] === void 0) return _extensionMethods[name](); | |
| 115 return name; | 111 return name; |
| 116 } | 112 } |
| 117 | 113 |
| 114 /** Shared code for dsend, dindex, and dsetindex. */ | |
| 115 function callMethod(obj, name, args, displayName) { | |
| 116 let symbol = _canonicalFieldName(obj, name, args, displayName); | |
| 117 let f = obj[symbol]; | |
| 118 let ftype = _getMethodType(obj, name); | |
| 119 return checkAndCall(f, ftype, obj, args, displayName); | |
| 120 } | |
| 121 | |
| 118 function dsend(obj, method/*, ...args*/) { | 122 function dsend(obj, method/*, ...args*/) { |
| 119 let args = Array.prototype.slice.call(arguments, 2); | 123 return callMethod(obj, method, slice.call(arguments, 2)); |
| 120 let symbol = _canonicalFieldName(obj, method); | |
| 121 let f = obj[symbol]; | |
| 122 let ftype = _getMethodType(obj, symbol); | |
| 123 return checkAndCall(f, ftype, obj, args, method); | |
| 124 } | 124 } |
| 125 dart.dsend = dsend; | 125 dart.dsend = dsend; |
| 126 | 126 |
| 127 function dindex(obj, index) { | 127 function dindex(obj, index) { |
| 128 // TODO(jmesserly): remove this special case once Array extensions are | 128 return callMethod(obj, 'get', [index], '[]'); |
| 129 // hooked up. | |
| 130 if (obj instanceof Array && realRuntimeType(index) == core.int) { | |
| 131 return obj[index]; | |
| 132 } | |
| 133 return checkAndCall(obj.get, void 0, obj, [index], '[]'); | |
| 134 } | 129 } |
| 135 dart.dindex = dindex; | 130 dart.dindex = dindex; |
| 136 | 131 |
| 137 function dsetindex(obj, index, value) { | 132 function dsetindex(obj, index, value) { |
| 138 return checkAndCall(obj.set, void 0, obj, [index, value], '[]='); | 133 return callMethod(obj, 'set', [index, value], '[]='); |
| 139 } | 134 } |
| 140 dart.dsetindex = dsetindex; | 135 dart.dsetindex = dsetindex; |
| 141 | 136 |
| 142 function typeToString(type) { | 137 function typeToString(type) { |
| 143 if (typeof(type) == "function") { | 138 if (typeof(type) == "function") { |
| 144 var name = type.name; | 139 var name = type.name; |
| 145 var args = type[dart.typeArguments]; | 140 var args = type[dart.typeArguments]; |
| 146 if (args) { | 141 if (args) { |
| 147 name += '<'; | 142 name += '<'; |
| 148 for (var i = 0; i < args.length; ++i) { | 143 for (var i = 0; i < args.length; ++i) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 171 console.log('Warning: ignoring cast fail from ' + typeToString(actual) + ' to ' + typeToString(type)); | 166 console.log('Warning: ignoring cast fail from ' + typeToString(actual) + ' to ' + typeToString(type)); |
| 172 return obj; | 167 return obj; |
| 173 } | 168 } |
| 174 // console.log('Error: cast fail from ' + typeToString(actual) + ' to ' + ty peToString(type)); | 169 // console.log('Error: cast fail from ' + typeToString(actual) + ' to ' + ty peToString(type)); |
| 175 throw new _js_helper.CastErrorImplementation(actual, type); | 170 throw new _js_helper.CastErrorImplementation(actual, type); |
| 176 } | 171 } |
| 177 dart.as = cast; | 172 dart.as = cast; |
| 178 | 173 |
| 179 | 174 |
| 180 // TODO(vsm): How should we encode the runtime type? | 175 // TODO(vsm): How should we encode the runtime type? |
| 181 let _runtimeType = Symbol('_runtimeType'); | 176 const _runtimeType = Symbol('_runtimeType'); |
| 182 | 177 |
| 183 function checkPrimitiveType(obj) { | 178 function checkPrimitiveType(obj) { |
| 184 switch (typeof obj) { | 179 switch (typeof obj) { |
| 185 case "undefined": | 180 case "undefined": |
| 186 return core.Null; | 181 return core.Null; |
| 187 case "number": | 182 case "number": |
| 188 return Math.floor(obj) == obj ? core.int : core.double; | 183 return Math.floor(obj) == obj ? core.int : core.double; |
| 189 case "boolean": | 184 case "boolean": |
| 190 return core.bool; | 185 return core.bool; |
| 191 case "string": | 186 case "string": |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 if (t === Array) return core.List; | 235 if (t === Array) return core.List; |
| 241 | 236 |
| 242 // We shouldn't normally get here with these types, unless something strange | 237 // We shouldn't normally get here with these types, unless something strange |
| 243 // happens like subclassing Number in JS and passing it to Dart. | 238 // happens like subclassing Number in JS and passing it to Dart. |
| 244 if (t === String) return core.String; | 239 if (t === String) return core.String; |
| 245 if (t === Number) return core.double; | 240 if (t === Number) return core.double; |
| 246 if (t === Boolean) return core.bool; | 241 if (t === Boolean) return core.bool; |
| 247 return t; | 242 return t; |
| 248 } | 243 } |
| 249 | 244 |
| 250 let subtypeMap = new Map(); | 245 const subtypeMap = new Map(); |
| 251 function isSubtype(t1, t2) { | 246 function isSubtype(t1, t2) { |
| 252 // See if we already know the answer | 247 // See if we already know the answer |
| 253 // TODO(jmesserly): general purpose memoize function? | 248 // TODO(jmesserly): general purpose memoize function? |
| 254 let map = subtypeMap.get(t1); | 249 let map = subtypeMap.get(t1); |
| 255 let result; | 250 let result; |
| 256 if (map) { | 251 if (map) { |
| 257 result = map.get(t2); | 252 result = map.get(t2); |
| 258 if (result !== void 0) return result; | 253 if (result !== void 0) return result; |
| 259 } else { | 254 } else { |
| 260 subtypeMap.set(t1, map = new Map()); | 255 subtypeMap.set(t1, map = new Map()); |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 554 let build = () => { | 549 let build = () => { |
| 555 let args = Array.apply(null, new Array(len)).map(() => core.Object); | 550 let args = Array.apply(null, new Array(len)).map(() => core.Object); |
| 556 return functionType(core.Object, args); | 551 return functionType(core.Object, args); |
| 557 }; | 552 }; |
| 558 // We could be called before Object is defined. | 553 // We could be called before Object is defined. |
| 559 if (core.Object === void 0) return fn(closure, build); | 554 if (core.Object === void 0) return fn(closure, build); |
| 560 t = build(); | 555 t = build(); |
| 561 } else { | 556 } else { |
| 562 // We're passed the piecewise components of the function type, | 557 // We're passed the piecewise components of the function type, |
| 563 // construct it. | 558 // construct it. |
| 564 let args = Array.prototype.slice.call(arguments, 1); | 559 let args = slice.call(arguments, 1); |
| 565 t = functionType.apply(null, args); | 560 t = functionType.apply(null, args); |
| 566 } | 561 } |
| 567 setRuntimeType(closure, t); | 562 setRuntimeType(closure, t); |
| 568 return closure; | 563 return closure; |
| 569 } | 564 } |
| 570 dart.fn = fn; | 565 dart.fn = fn; |
| 571 | 566 |
| 572 function functionType(returnType, args, extra) { | 567 function functionType(returnType, args, extra) { |
| 573 // TODO(vsm): Cache / memomize? | 568 // TODO(vsm): Cache / memomize? |
| 574 var optionals; | 569 var optionals; |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 771 | 766 |
| 772 /** | 767 /** |
| 773 * Copy properties from source to destination object. | 768 * Copy properties from source to destination object. |
| 774 * This operation is commonly called `mixin` in JS. | 769 * This operation is commonly called `mixin` in JS. |
| 775 */ | 770 */ |
| 776 function copyProperties(to, from) { | 771 function copyProperties(to, from) { |
| 777 return copyPropertiesHelper(to, from, getOwnNamesAndSymbols(from)); | 772 return copyPropertiesHelper(to, from, getOwnNamesAndSymbols(from)); |
| 778 } | 773 } |
| 779 dart.copyProperties = copyProperties; | 774 dart.copyProperties = copyProperties; |
| 780 | 775 |
| 776 function getExtensionSymbol(name) { | |
| 777 let sym = dartx[name]; | |
| 778 if (!sym) dartx[name] = sym = Symbol('dartx.' + name); | |
| 779 return sym; | |
| 780 } | |
| 781 | |
| 781 /** | 782 /** |
| 782 * Copy symbols from the prototype of the source to destination. | 783 * Copy symbols from the prototype of the source to destination. |
| 783 * These are the only properties safe to copy onto an existing public | 784 * These are the only properties safe to copy onto an existing public |
| 784 * JavaScript class. | 785 * JavaScript class. |
| 785 */ | 786 */ |
| 786 function registerExtension(to, from) { | 787 function registerExtension(jsType, dartExtType) { |
| 787 return copyPropertiesHelper(to.prototype, from.prototype, | 788 let extProto = dartExtType.prototype; |
| 788 getOwnPropertySymbols(from.prototype)); | 789 let jsProto = jsType.prototype; |
| 790 | |
| 791 // Mark the JS type's instances so we can easily check for extensions. | |
| 792 assert(jsProto[_extensionType] === void 0); | |
| 793 jsProto[_extensionType] = extProto; | |
| 794 for (let name of getOwnPropertyNames(extProto)) { | |
| 795 let symbol = getExtensionSymbol(name); | |
| 796 defineProperty(jsProto, symbol, getOwnPropertyDescriptor(extProto, name)); | |
| 797 } | |
| 789 } | 798 } |
| 790 dart.registerExtension = registerExtension; | 799 dart.registerExtension = registerExtension; |
| 791 | 800 |
| 801 /** | |
| 802 * Mark a concrete type as implementing extension methods. | |
| 803 * For example: `class MyIter implements Iterable`. | |
| 804 * | |
| 805 * This takes a list of names, which are the extension methods implemented. | |
| 806 * It will add a forwarder, so the extension method name redirects to the | |
| 807 * normal Dart method name. For example: | |
| 808 * | |
| 809 * defineExtensionMembers(MyType, ['add', 'remove']); | |
| 810 * | |
| 811 * Results in: | |
| 812 * | |
| 813 * MyType.prototype[dartx.add] = MyType.prototype.add; | |
| 814 * MyType.prototype[dartx.remove] = MyType.prototype.remove; | |
| 815 */ | |
| 816 // TODO(jmesserly): essentially this gives two names to the same method. | |
| 817 // This benefit is roughly equivalent call performance either way, but the | |
| 818 // cost is we need to call implementExtension any time a subclass overrides | |
| 819 // one of these methods. | |
|
vsm
2015/06/04 21:50:02
I see. So, the virtual dispatch is happening on f
Jennifer Messerly
2015/06/04 21:57:46
exactly. If we wanted to do it the other way, we'd
| |
| 820 function defineExtensionMembers(type, methodNames) { | |
| 821 let proto = type.prototype; | |
| 822 for (let name of methodNames) { | |
| 823 let method = getOwnPropertyDescriptor(proto, name); | |
| 824 defineProperty(proto, getExtensionSymbol(name), method); | |
| 825 } | |
| 826 } | |
| 827 dart.defineExtensionMembers = defineExtensionMembers; | |
| 828 | |
| 792 function setBaseClass(derived, base) { | 829 function setBaseClass(derived, base) { |
| 793 // Link the extension to the type it's extending as a base class. | 830 // Link the extension to the type it's extending as a base class. |
| 794 derived.prototype.__proto__ = base.prototype; | 831 derived.prototype.__proto__ = base.prototype; |
| 795 } | 832 } |
| 796 dart.setBaseClass = setBaseClass; | 833 dart.setBaseClass = setBaseClass; |
| 797 | 834 |
| 798 /** | 835 /** |
| 799 * This is called whenever a derived class needs to introduce a new field, | 836 * This is called whenever a derived class needs to introduce a new field, |
| 800 * shadowing a field or getter/setter pair on its parent. | 837 * shadowing a field or getter/setter pair on its parent. |
| 801 * | 838 * |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 826 * | 863 * |
| 827 * Each mixin applies in sequence, with further to the right ones overriding | 864 * Each mixin applies in sequence, with further to the right ones overriding |
| 828 * previous entries. | 865 * previous entries. |
| 829 * | 866 * |
| 830 * For each mixin, we only take its own properties, not anything from its | 867 * For each mixin, we only take its own properties, not anything from its |
| 831 * superclass (prototype). | 868 * superclass (prototype). |
| 832 */ | 869 */ |
| 833 function mixin(base/*, ...mixins*/) { | 870 function mixin(base/*, ...mixins*/) { |
| 834 // Create an initializer for the mixin, so when derived constructor calls | 871 // Create an initializer for the mixin, so when derived constructor calls |
| 835 // super, we can correctly initialize base and mixins. | 872 // super, we can correctly initialize base and mixins. |
| 836 let mixins = Array.prototype.slice.call(arguments, 1); | 873 let mixins = slice.call(arguments, 1); |
| 837 | 874 |
| 838 // Create a class that will hold all of the mixin methods. | 875 // Create a class that will hold all of the mixin methods. |
| 839 class Mixin extends base { | 876 class Mixin extends base { |
| 840 // Initializer method: run mixin initializers, then the base. | 877 // Initializer method: run mixin initializers, then the base. |
| 841 [base.name](/*...args*/) { | 878 [base.name](/*...args*/) { |
| 842 // Run mixin initializers. They cannot have arguments. | 879 // Run mixin initializers. They cannot have arguments. |
| 843 // Run them backwards so most-derived mixin is initialized first. | 880 // Run them backwards so most-derived mixin is initialized first. |
| 844 for (let i = mixins.length - 1; i >= 0; i--) { | 881 for (let i = mixins.length - 1; i >= 0; i--) { |
| 845 let mixin = mixins[i]; | 882 let mixin = mixins[i]; |
| 846 let init = mixin.prototype[mixin.name]; | 883 let init = mixin.prototype[mixin.name]; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 914 function throw_(obj) { throw obj; } | 951 function throw_(obj) { throw obj; } |
| 915 dart.throw_ = throw_; | 952 dart.throw_ = throw_; |
| 916 | 953 |
| 917 /** | 954 /** |
| 918 * Given a class and an initializer method name, creates a constructor | 955 * Given a class and an initializer method name, creates a constructor |
| 919 * function with the same name. For example `new SomeClass.name(args)`. | 956 * function with the same name. For example `new SomeClass.name(args)`. |
| 920 */ | 957 */ |
| 921 function defineNamedConstructor(clazz, name) { | 958 function defineNamedConstructor(clazz, name) { |
| 922 let proto = clazz.prototype; | 959 let proto = clazz.prototype; |
| 923 let initMethod = proto[name]; | 960 let initMethod = proto[name]; |
| 924 let ctor = function() { return initMethod.apply(this, arguments); } | 961 let ctor = function() { return initMethod.apply(this, arguments); }; |
| 925 ctor.prototype = proto; | 962 ctor.prototype = proto; |
| 926 // Use defineProperty so we don't hit a property defined on Function, | 963 // Use defineProperty so we don't hit a property defined on Function, |
| 927 // like `caller` and `arguments`. | 964 // like `caller` and `arguments`. |
| 928 defineProperty(clazz, name, { value: ctor, configurable: true }); | 965 defineProperty(clazz, name, { value: ctor, configurable: true }); |
| 929 } | 966 } |
| 930 dart.defineNamedConstructor = defineNamedConstructor; | 967 dart.defineNamedConstructor = defineNamedConstructor; |
| 931 | 968 |
| 932 function stackTrace(exception) { | 969 function stackTrace(exception) { |
| 933 return _js_helper.getTraceFromException(exception); | 970 return _js_helper.getTraceFromException(exception); |
| 934 } | 971 } |
| 935 dart.stackTrace = stackTrace; | 972 dart.stackTrace = stackTrace; |
| 936 | 973 |
| 937 /** The Symbol for storing type arguments on a specialized generic type. */ | 974 /** The Symbol for storing type arguments on a specialized generic type. */ |
| 938 dart.typeArguments = Symbol('typeArguments'); | 975 dart.typeArguments = Symbol('typeArguments'); |
| 939 dart.originalDeclaration = Symbol('originalDeclaration'); | 976 dart.originalDeclaration = Symbol('originalDeclaration'); |
| 940 | 977 |
| 941 /** Memoize a generic type constructor function. */ | 978 /** Memoize a generic type constructor function. */ |
| 942 function generic(typeConstructor) { | 979 function generic(typeConstructor) { |
| 943 let length = typeConstructor.length; | 980 let length = typeConstructor.length; |
| 944 if (length < 1) throw Error('must have at least one generic type argument'); | 981 if (length < 1) throw Error('must have at least one generic type argument'); |
| 945 | 982 |
| 946 let resultMap = new Map(); | 983 let resultMap = new Map(); |
| 947 function makeGenericType(/*...arguments*/) { | 984 function makeGenericType(/*...arguments*/) { |
| 948 if (arguments.length != length && arguments.length != 0) { | 985 if (arguments.length != length && arguments.length != 0) { |
| 949 throw Error('requires ' + length + ' or 0 type arguments'); | 986 throw Error('requires ' + length + ' or 0 type arguments'); |
| 950 } | 987 } |
| 951 let args = Array.prototype.slice.call(arguments); | 988 let args = slice.call(arguments); |
| 952 // TODO(leafp): This should really be core.Object for | 989 // TODO(leafp): This should really be core.Object for |
| 953 // consistency, but Object is not attached to core | 990 // consistency, but Object is not attached to core |
| 954 // until the entire core library has been processed, | 991 // until the entire core library has been processed, |
| 955 // which is too late. | 992 // which is too late. |
| 956 while (args.length < length) args.push(dart.dynamic); | 993 while (args.length < length) args.push(dart.dynamic); |
| 957 | 994 |
| 958 let value = resultMap; | 995 let value = resultMap; |
| 959 for (let i = 0; i < length; i++) { | 996 for (let i = 0; i < length; i++) { |
| 960 let arg = args[i]; | 997 let arg = args[i]; |
| 961 if (arg == null) { | 998 if (arg == null) { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1109 } | 1146 } |
| 1110 map = value; | 1147 map = value; |
| 1111 } | 1148 } |
| 1112 if (map.has(_value)) return map.get(_value); | 1149 if (map.has(_value)) return map.get(_value); |
| 1113 let value = valueFn(); | 1150 let value = valueFn(); |
| 1114 map.set(_value, value); | 1151 map.set(_value, value); |
| 1115 return value; | 1152 return value; |
| 1116 } | 1153 } |
| 1117 | 1154 |
| 1118 /** The global constant table. */ | 1155 /** The global constant table. */ |
| 1119 let constants = new Map(); | 1156 const constants = new Map(); |
| 1120 | 1157 |
| 1121 /** | 1158 /** |
| 1122 * Canonicalize a constant object. | 1159 * Canonicalize a constant object. |
| 1123 * | 1160 * |
| 1124 * Preconditions: | 1161 * Preconditions: |
| 1125 * - `obj` is an objects or array, not a primitive. | 1162 * - `obj` is an objects or array, not a primitive. |
| 1126 * - nested values of the object are themselves already canonicalized. | 1163 * - nested values of the object are themselves already canonicalized. |
| 1127 */ | 1164 */ |
| 1128 function constant(obj) { | 1165 function constant(obj) { |
| 1129 let objectKey = [realRuntimeType(obj)]; | 1166 let objectKey = [realRuntimeType(obj)]; |
| 1130 // There's no guarantee in JS that names/symbols are returned in the same | 1167 // TODO(jmesserly): there's no guarantee in JS that names/symbols are |
| 1131 // order. We could probably get the same order if we're judicious about | 1168 // returned in the same order. |
| 1132 // initializing them, but easier to not depend on that. | 1169 // |
| 1170 // We could probably get the same order if we're judicious about | |
| 1171 // initializing fields in a consistent order across all const constructors. | |
| 1172 // Alternatively we need a way to sort them to make consistent. | |
| 1173 // | |
| 1174 // Right now we use the (name,value) pairs in sequence, which prevents | |
| 1175 // an object with incorrect field values being returned, but won't | |
| 1176 // canonicalize correctly if key order is different. | |
| 1133 for (let name of getOwnNamesAndSymbols(obj)) { | 1177 for (let name of getOwnNamesAndSymbols(obj)) { |
| 1134 // TODO(jmesserly): we can make this faster if needed. | |
| 1135 objectKey.push(name); | 1178 objectKey.push(name); |
| 1136 objectKey.push(obj[name]); | 1179 objectKey.push(obj[name]); |
| 1137 } | 1180 } |
| 1138 return multiKeyPutIfAbsent(constants, objectKey, () => obj); | 1181 return multiKeyPutIfAbsent(constants, objectKey, () => obj); |
| 1139 } | 1182 } |
| 1140 dart.const = constant; | 1183 dart.const = constant; |
| 1141 | 1184 |
| 1142 // TODO(vsm): Rationalize these type methods. We're currently using the | 1185 // TODO(vsm): Rationalize these type methods. We're currently using the |
| 1143 // setType / proto scheme for nominal types (e.g., classes) and the | 1186 // setType / proto scheme for nominal types (e.g., classes) and the |
| 1144 // setRuntimeType / field scheme for structural types (e.g., functions | 1187 // setRuntimeType / field scheme for structural types (e.g., functions |
| 1145 // - and only in tests for now). | 1188 // - and only in tests for now). |
| 1146 // See: https://github.com/dart-lang/dev_compiler/issues/172 | 1189 // See: https://github.com/dart-lang/dev_compiler/issues/172 |
| 1147 | 1190 |
| 1148 /** Sets the type of `obj` to be `type` */ | 1191 /** Sets the type of `obj` to be `type` */ |
| 1149 function setType(obj, type) { | 1192 function setType(obj, type) { |
| 1150 obj.__proto__ = type.prototype; | 1193 obj.__proto__ = type.prototype; |
| 1151 return obj; | 1194 return obj; |
| 1152 } | 1195 } |
| 1153 dart.setType = setType; | 1196 dart.setType = setType; |
| 1154 | 1197 |
| 1198 /** Sets the element type of a list literal. */ | |
| 1199 function list(obj, elementType) { | |
| 1200 return setType(obj, _interceptors.JSArray$(elementType)); | |
| 1201 } | |
| 1202 dart.list = list; | |
| 1203 | |
| 1155 /** Sets the internal runtime type of `obj` to be `type` */ | 1204 /** Sets the internal runtime type of `obj` to be `type` */ |
| 1156 function setRuntimeType(obj, type) { | 1205 function setRuntimeType(obj, type) { |
| 1157 obj[_runtimeType] = type; | 1206 obj[_runtimeType] = type; |
| 1158 } | 1207 } |
| 1159 dart.setRuntimeType = setRuntimeType; | 1208 dart.setRuntimeType = setRuntimeType; |
| 1160 | 1209 |
| 1161 // The following are helpers for Object methods when the receiver | 1210 // The following are helpers for Object methods when the receiver |
| 1162 // may be null or primitive. These should only be generated by | 1211 // may be null or primitive. These should only be generated by |
| 1163 // the compiler. | 1212 // the compiler. |
| 1164 function hashCode(obj) { | 1213 function hashCode(obj) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1251 } | 1300 } |
| 1252 dart.defineLibrary = defineLibrary; | 1301 dart.defineLibrary = defineLibrary; |
| 1253 | 1302 |
| 1254 // TODO(jmesserly): hack to bootstrap the SDK | 1303 // TODO(jmesserly): hack to bootstrap the SDK |
| 1255 _js_helper = _js_helper || {}; | 1304 _js_helper = _js_helper || {}; |
| 1256 _js_helper.checkNum = notNull; | 1305 _js_helper.checkNum = notNull; |
| 1257 | 1306 |
| 1258 _js_primitives = _js_primitives || {}; | 1307 _js_primitives = _js_primitives || {}; |
| 1259 _js_primitives.printString = (s) => console.log(s); | 1308 _js_primitives.printString = (s) => console.log(s); |
| 1260 | 1309 |
| 1261 // TODO(vsm): Plumb this correctly. | |
| 1262 // See: https://github.com/dart-lang/dev_compiler/issues/40 | |
| 1263 String.prototype.contains = function(sub) { return this.indexOf(sub) >= 0; } | |
| 1264 let _split = String.prototype.split; | |
| 1265 String.prototype.split = function() { | |
| 1266 let result = _split.apply(this, arguments); | |
| 1267 dart.setType(result, core.List$(core.String)); | |
| 1268 return result; | |
| 1269 }; | |
| 1270 String.prototype.get = function(i) { | |
| 1271 return this[i]; | |
| 1272 }; | |
| 1273 String.prototype.codeUnitAt = function(i) { | |
| 1274 return this.charCodeAt(i); | |
| 1275 }; | |
| 1276 String.prototype.replaceAllMapped = function(from, cb) { | |
| 1277 return this.replace(from.multiple, function() { | |
| 1278 // Remove offset & string from the result array | |
| 1279 var matches = arguments; | |
| 1280 matches.splice(-2, 2); | |
| 1281 // The callback receives match, p1, ..., pn | |
| 1282 return cb(matches); | |
| 1283 }); | |
| 1284 }; | |
| 1285 String.prototype['+'] = function(arg) { return this.valueOf() + arg; }; | |
| 1286 | |
| 1287 Boolean.prototype['!'] = function() { return !this.valueOf(); }; | |
| 1288 Boolean.prototype['&&'] = function(arg) { return this.valueOf() && arg; }; | |
| 1289 Boolean.prototype['||'] = function(arg) { return this.valueOf() || arg; }; | |
| 1290 Number.prototype['<'] = function(arg) { return this.valueOf() < arg; }; | |
| 1291 Number.prototype['<='] = function(arg) { return this.valueOf() <= arg; }; | |
| 1292 Number.prototype['>'] = function(arg) { return this.valueOf() > arg; }; | |
| 1293 Number.prototype['+'] = function(arg) { return this.valueOf() + arg; }; | |
| 1294 | |
| 1295 // TODO(vsm): DOM facades? | 1310 // TODO(vsm): DOM facades? |
| 1296 // See: https://github.com/dart-lang/dev_compiler/issues/173 | 1311 // See: https://github.com/dart-lang/dev_compiler/issues/173 |
| 1297 NodeList.prototype.get = function(i) { return this[i]; }; | 1312 NodeList.prototype.get = function(i) { return this[i]; }; |
| 1298 NamedNodeMap.prototype.get = function(i) { return this[i]; }; | 1313 NamedNodeMap.prototype.get = function(i) { return this[i]; }; |
| 1299 DOMTokenList.prototype.get = function(i) { return this[i]; }; | 1314 DOMTokenList.prototype.get = function(i) { return this[i]; }; |
| 1300 | 1315 |
| 1316 /** Dart extension members. */ | |
| 1317 dartx = dartx || {}; | |
| 1318 | |
| 1301 })(dart || (dart = {})); | 1319 })(dart || (dart = {})); |
| OLD | NEW |