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 /// This library defines runtime operations on objects used by the code | 5 /// This library defines runtime operations on objects used by the code |
6 /// generator. | 6 /// generator. |
7 part of dart._runtime; | 7 part of dart._runtime; |
8 | 8 |
9 class InvocationImpl extends Invocation { | 9 class InvocationImpl extends Invocation { |
10 final Symbol memberName; | 10 final Symbol memberName; |
11 final List positionalArguments; | 11 final List positionalArguments; |
12 final Map<Symbol, dynamic> namedArguments; | 12 final Map<Symbol, dynamic> namedArguments; |
13 final bool isMethod; | 13 final bool isMethod; |
14 final bool isGetter; | 14 final bool isGetter; |
15 final bool isSetter; | 15 final bool isSetter; |
16 | 16 |
17 InvocationImpl(String memberName, this.positionalArguments, | 17 InvocationImpl(memberName, this.positionalArguments, |
18 {namedArguments, | 18 {namedArguments, |
19 this.isMethod: false, | 19 this.isMethod: false, |
20 this.isGetter: false, | 20 this.isGetter: false, |
21 this.isSetter: false}) | 21 this.isSetter: false}) |
22 : memberName = _dartSymbol(memberName), | 22 : memberName = _dartSymbol(memberName), |
23 namedArguments = _namedArgsToSymbols(namedArguments); | 23 namedArguments = _namedArgsToSymbols(namedArguments); |
24 | 24 |
25 static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) { | 25 static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) { |
26 if (namedArgs == null) return {}; | 26 if (namedArgs == null) return {}; |
27 return new Map.fromIterable(getOwnPropertyNames(namedArgs), | 27 return new Map.fromIterable(getOwnPropertyNames(namedArgs), |
28 key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)); | 28 key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)); |
29 } | 29 } |
30 } | 30 } |
31 | 31 |
32 // Warning: dload, dput, and dsend assume they are never called on methods | |
33 // implemented by the Object base class as those methods can always be | |
34 // statically resolved. | |
32 dload(obj, field) { | 35 dload(obj, field) { |
33 var f = _canonicalMember(obj, field); | 36 var f = _canonicalMember(obj, field); |
37 | |
34 _trackCall(obj); | 38 _trackCall(obj); |
35 if (f != null) { | 39 if (f != null) { |
36 if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0')); | 40 var type = getType(obj); |
37 return JS('', '#[#]', obj, f); | 41 |
42 if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f); | |
43 if (hasMethod(type, f)) return bind(obj, f, JS('', 'void 0')); | |
38 } | 44 } |
39 return noSuchMethod( | 45 return noSuchMethod( |
40 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); | 46 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); |
41 } | 47 } |
42 | 48 |
43 dput(obj, field, value) { | 49 dput(obj, field, value) { |
44 var f = _canonicalMember(obj, field); | 50 var f = _canonicalMember(obj, field); |
45 _trackCall(obj); | 51 _trackCall(obj); |
46 if (f != null) { | 52 if (f != null) { |
47 return JS('', '#[#] = #', obj, f, value); | 53 var type = getType(obj); |
54 var setter = getSetterType(type, f); | |
Jennifer Messerly
2017/01/24 03:51:03
Possibly calling this setterType would be a bit mo
Jacob
2017/01/24 19:12:32
agreed. cleaned up.
| |
55 if (JS('bool', '# != void 0', setter)) { | |
56 // TODO(jacobr): throw a type error instead of a NoSuchMethodError if | |
57 // the type of the setter doesn't match. | |
58 if (instanceOfOrNull(value, JS('', '#.args[0]', setter))) { | |
59 return JS('', '#[#] = #', obj, f, value); | |
60 } | |
61 } else { | |
62 var field = getFieldType(type, f); | |
63 // TODO(jacobr): propagate metadata tracking which fields are private. | |
Jennifer Messerly
2017/01/24 03:51:03
What does this mean? It shouldn't be possible to g
Jacob
2017/01/24 19:12:32
Done.
It means I got distracted writing the commen
| |
64 if (JS('bool', '# != void 0', field)) { | |
65 // TODO(jacobr): throw a type error instead of a NoSuchMethodError if | |
66 // the type of the field doesn't match. | |
67 if (instanceOfOrNull(value, field)) { | |
68 return JS('', '#[#] = #', obj, f, value); | |
69 } | |
70 } | |
71 } | |
48 } | 72 } |
49 return noSuchMethod( | 73 return noSuchMethod( |
50 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); | 74 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); |
51 } | 75 } |
52 | 76 |
53 /// Check that a function of a given type can be applied to | 77 /// Check that a function of a given type can be applied to |
54 /// actuals. | 78 /// actuals. |
55 _checkApply(type, actuals) => JS( | 79 _checkApply(type, actuals) => JS( |
56 '', | 80 '', |
57 '''(() => { | 81 '''(() => { |
(...skipping 24 matching lines...) Expand all Loading... | |
82 if (names.length == 0) return false; | 106 if (names.length == 0) return false; |
83 for (var name of names) { | 107 for (var name of names) { |
84 if (!($hasOwnProperty.call($type.named, name))) { | 108 if (!($hasOwnProperty.call($type.named, name))) { |
85 return false; | 109 return false; |
86 } | 110 } |
87 $check(opts[name], $type.named[name]); | 111 $check(opts[name], $type.named[name]); |
88 } | 112 } |
89 return true; | 113 return true; |
90 })()'''); | 114 })()'''); |
91 | 115 |
92 Symbol _dartSymbol(name) => | 116 _toSymbolName(symbol) => JS( |
93 JS('', '#(#.new(#.toString()))', const_, Symbol, name); | 117 '', |
118 '''(() => { | |
119 let str = $symbol.toString(); | |
120 // Strip leading 'Symbol(' and trailing ')' | |
121 return str.substring(7, str.length-1); | |
122 })()'''); | |
123 | |
124 _toDisplayName(name) => JS( | |
125 '', | |
126 '''(() => { | |
127 // Names starting with _ are escaped names used to disambiguate Dart and | |
128 // JS names. | |
129 if ($name[0] === '_') { | |
130 // Inverse of | |
131 switch($name) { | |
132 case '_get': | |
133 return '[]'; | |
134 case '_set': | |
135 return '[]='; | |
136 case '_negate': | |
137 return 'unary-'; | |
138 case '_constructor': | |
139 case '_prototype': | |
140 return $name.substring(1); | |
141 } | |
142 } | |
143 return $name; | |
144 })()'''); | |
145 | |
146 Symbol _dartSymbol(name) { | |
147 return (JS('bool', 'typeof # === "symbol"', name)) | |
148 ? JS('', '#(new #.es6(#, #))', const_, _internal.Symbol, | |
149 _toSymbolName(name), name) | |
150 : JS('', '#(#.new(#))', const_, Symbol, _toDisplayName(name)); | |
151 } | |
94 | 152 |
95 /// Extracts the named argument array from a list of arguments, and returns it. | 153 /// Extracts the named argument array from a list of arguments, and returns it. |
96 // TODO(jmesserly): we need to handle named arguments better. | 154 // TODO(jmesserly): we need to handle named arguments better. |
97 extractNamedArgs(args) { | 155 extractNamedArgs(args) { |
98 if (JS('bool', '#.length > 0', args)) { | 156 if (JS('bool', '#.length > 0', args)) { |
99 var last = JS('', '#[#.length - 1]', args, args); | 157 var last = JS('', '#[#.length - 1]', args, args); |
100 if (JS( | 158 if (JS( |
101 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) { | 159 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) { |
102 return JS('', '#.pop()', args); | 160 return JS('', '#.pop()', args); |
103 } | 161 } |
(...skipping 10 matching lines...) Expand all Loading... | |
114 | 172 |
115 function callNSM() { | 173 function callNSM() { |
116 return $noSuchMethod(originalTarget, new $InvocationImpl( | 174 return $noSuchMethod(originalTarget, new $InvocationImpl( |
117 $name, $args, | 175 $name, $args, |
118 {namedArguments: $extractNamedArgs($args), isMethod: true})); | 176 {namedArguments: $extractNamedArgs($args), isMethod: true})); |
119 } | 177 } |
120 if (!($f instanceof Function)) { | 178 if (!($f instanceof Function)) { |
121 // We're not a function (and hence not a method either) | 179 // We're not a function (and hence not a method either) |
122 // Grab the `call` method if it's not a function. | 180 // Grab the `call` method if it's not a function. |
123 if ($f != null) { | 181 if ($f != null) { |
124 $ftype = $getMethodType($f, 'call'); | 182 $ftype = $getMethodType($getType($f), 'call'); |
125 $f = $f.call; | 183 $f = $f.call; |
126 } | 184 } |
127 if (!($f instanceof Function)) { | 185 if (!($f instanceof Function)) { |
128 return callNSM(); | 186 return callNSM(); |
129 } | 187 } |
130 } | 188 } |
131 // If f is a function, but not a method (no method type) | 189 // If f is a function, but not a method (no method type) |
132 // then it should have been a function valued field, so | 190 // then it should have been a function valued field, so |
133 // get the type from the function. | 191 // get the type from the function. |
134 if ($ftype === void 0) { | 192 if ($ftype === void 0) { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 } | 354 } |
297 | 355 |
298 /// Shared code for dsend, dindex, and dsetindex. | 356 /// Shared code for dsend, dindex, and dsetindex. |
299 _callMethod(obj, name, typeArgs, args, displayName) { | 357 _callMethod(obj, name, typeArgs, args, displayName) { |
300 var symbol = _canonicalMember(obj, name); | 358 var symbol = _canonicalMember(obj, name); |
301 if (symbol == null) { | 359 if (symbol == null) { |
302 return noSuchMethod( | 360 return noSuchMethod( |
303 obj, new InvocationImpl(displayName, args, isMethod: true)); | 361 obj, new InvocationImpl(displayName, args, isMethod: true)); |
304 } | 362 } |
305 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; | 363 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; |
306 var ftype = getMethodType(obj, symbol); | 364 var type = getType(obj); |
365 var ftype = getMethodType(type, symbol); | |
366 // No such method if dart object and ftype is missing. | |
307 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); | 367 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); |
308 } | 368 } |
309 | 369 |
310 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); | 370 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); |
311 | 371 |
312 dgsend(obj, typeArgs, method, @rest args) => | 372 dgsend(obj, typeArgs, method, @rest args) => |
313 _callMethod(obj, method, typeArgs, args, method); | 373 _callMethod(obj, method, typeArgs, args, method); |
314 | 374 |
315 dindex(obj, index) => | 375 dindex(obj, index) => |
316 _callMethod(obj, '_get', null, JS('', '[#]', index), '[]'); | 376 _callMethod(obj, '_get', null, JS('', '[#]', index), '[]'); |
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
841 name = '+' + name; | 901 name = '+' + name; |
842 } | 902 } |
843 return name; | 903 return name; |
844 } | 904 } |
845 | 905 |
846 /// Emulates the implicit "loadLibrary" function provided by a deferred library. | 906 /// Emulates the implicit "loadLibrary" function provided by a deferred library. |
847 /// | 907 /// |
848 /// Libraries are not actually deferred in DDC, so this just returns a future | 908 /// Libraries are not actually deferred in DDC, so this just returns a future |
849 /// that completes immediately. | 909 /// that completes immediately. |
850 Future loadLibrary() => new Future.value(); | 910 Future loadLibrary() => new Future.value(); |
OLD | NEW |