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 |