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 /// 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(String 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( | 27 return new Map.fromIterable(getOwnPropertyNames(namedArgs), |
| 28 getOwnPropertyNames(namedArgs), | 28 key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)); |
| 29 key: _dartSymbol, | |
| 30 value: (k) => JS('', '#[#]', namedArgs, k)); | |
| 31 } | 29 } |
| 32 } | 30 } |
| 33 | 31 |
| 34 dload(obj, field) { | 32 dload(obj, field) { |
| 35 var f = _canonicalMember(obj, field); | 33 var f = _canonicalMember(obj, field); |
| 36 _trackCall(obj); | 34 _trackCall(obj); |
| 37 if (f != null) { | 35 if (f != null) { |
| 38 if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0')); | 36 if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0')); |
| 39 return JS('', '#[#]', obj, f); | 37 return JS('', '#[#]', obj, f); |
| 40 } | 38 } |
| 41 return noSuchMethod(obj, | 39 return noSuchMethod( |
| 42 new InvocationImpl(field, JS('', '[]'), isGetter: true)); | 40 obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); |
| 43 } | 41 } |
| 44 | 42 |
| 45 dput(obj, field, value) { | 43 dput(obj, field, value) { |
| 46 var f = _canonicalMember(obj, field); | 44 var f = _canonicalMember(obj, field); |
| 47 _trackCall(obj); | 45 _trackCall(obj); |
| 48 if (f != null) { | 46 if (f != null) { |
| 49 return JS('', '#[#] = #', obj, f, value); | 47 return JS('', '#[#] = #', obj, f, value); |
| 50 } | 48 } |
| 51 return noSuchMethod(obj, | 49 return noSuchMethod( |
| 52 new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); | 50 obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); |
| 53 } | 51 } |
| 54 | 52 |
| 55 /// Check that a function of a given type can be applied to | 53 /// Check that a function of a given type can be applied to |
| 56 /// actuals. | 54 /// actuals. |
| 57 _checkApply(type, actuals) => JS('', '''(() => { | 55 _checkApply(type, actuals) => JS( |
| 56 '', | |
| 57 '''(() => { | |
| 58 if ($actuals.length < $type.args.length) return false; | 58 if ($actuals.length < $type.args.length) return false; |
| 59 let index = 0; | 59 let index = 0; |
| 60 for(let i = 0; i < $type.args.length; ++i) { | 60 for(let i = 0; i < $type.args.length; ++i) { |
| 61 if (!$instanceOfOrNull($actuals[i], $type.args[i])) return false; | 61 if (!$instanceOfOrNull($actuals[i], $type.args[i])) return false; |
| 62 ++index; | 62 ++index; |
| 63 } | 63 } |
| 64 if ($actuals.length == $type.args.length) return true; | 64 if ($actuals.length == $type.args.length) return true; |
| 65 let extras = $actuals.length - $type.args.length; | 65 let extras = $actuals.length - $type.args.length; |
| 66 if ($type.optionals.length > 0) { | 66 if ($type.optionals.length > 0) { |
| 67 if (extras > $type.optionals.length) return false; | 67 if (extras > $type.optionals.length) return false; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 90 })()'''); | 90 })()'''); |
| 91 | 91 |
| 92 Symbol _dartSymbol(name) => | 92 Symbol _dartSymbol(name) => |
| 93 JS('', '#(#.new(#.toString()))', const_, Symbol, name); | 93 JS('', '#(#.new(#.toString()))', const_, Symbol, name); |
| 94 | 94 |
| 95 /// Extracts the named argument array from a list of arguments, and returns it. | 95 /// Extracts the named argument array from a list of arguments, and returns it. |
| 96 // TODO(jmesserly): we need to handle named arguments better. | 96 // TODO(jmesserly): we need to handle named arguments better. |
| 97 extractNamedArgs(args) { | 97 extractNamedArgs(args) { |
| 98 if (JS('bool', '#.length > 0', args)) { | 98 if (JS('bool', '#.length > 0', args)) { |
| 99 var last = JS('', '#[#.length - 1]', args, args); | 99 var last = JS('', '#[#.length - 1]', args, args); |
| 100 if (JS('bool', '# != null && #.__proto__ === Object.prototype', | 100 if (JS( |
| 101 last, last)) { | 101 'bool', '# != null && #.__proto__ === Object.prototype', last, last)) { |
| 102 return JS('', '#.pop()', args); | 102 return JS('', '#.pop()', args); |
| 103 } | 103 } |
| 104 } | 104 } |
| 105 return null; | 105 return null; |
| 106 } | 106 } |
| 107 | 107 |
| 108 _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => { | 108 _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS( |
| 109 '', | |
| 110 '''(() => { | |
| 109 $_trackCall($obj); | 111 $_trackCall($obj); |
| 110 | 112 |
| 111 let originalTarget = obj === void 0 ? f : obj; | 113 let originalTarget = obj === void 0 ? f : obj; |
| 112 | 114 |
| 113 function callNSM() { | 115 function callNSM() { |
| 114 return $noSuchMethod(originalTarget, new $InvocationImpl( | 116 return $noSuchMethod(originalTarget, new $InvocationImpl( |
| 115 $name, $args, | 117 $name, $args, |
| 116 {namedArguments: $extractNamedArgs($args), isMethod: true})); | 118 {namedArguments: $extractNamedArgs($args), isMethod: true})); |
| 117 } | 119 } |
| 118 if (!($f instanceof Function)) { | 120 if (!($f instanceof Function)) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 } | 171 } |
| 170 return $f.apply($obj, $args); | 172 return $f.apply($obj, $args); |
| 171 } | 173 } |
| 172 | 174 |
| 173 // TODO(leafp): throw a type error (rather than NSM) | 175 // TODO(leafp): throw a type error (rather than NSM) |
| 174 // if the arity matches but the types are wrong. | 176 // if the arity matches but the types are wrong. |
| 175 // TODO(jmesserly): nSM should include type args? | 177 // TODO(jmesserly): nSM should include type args? |
| 176 return callNSM(); | 178 return callNSM(); |
| 177 })()'''); | 179 })()'''); |
| 178 | 180 |
| 179 dcall(f, @rest args) => _checkAndCall( | 181 dcall(f, @rest args) => |
| 180 f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call'); | 182 _checkAndCall(f, _getRuntimeType(f), JS('', 'void 0'), null, args, 'call'); |
| 181 | 183 |
| 182 dgcall(f, typeArgs, @rest args) => _checkAndCall( | 184 dgcall(f, typeArgs, @rest args) => _checkAndCall( |
| 183 f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call'); | 185 f, _getRuntimeType(f), JS('', 'void 0'), typeArgs, args, 'call'); |
| 184 | 186 |
| 187 /// Helper for REPL dynamic invocation variants that make a best effort to | |
| 188 /// enable accessing private members across library boundaries. | |
| 189 _dhelperRepl(object, field, callback) => JS( | |
| 190 '', | |
| 191 '''(() => { | |
| 192 let rawField = $field; | |
| 193 if (typeof(field) == 'symbol') { | |
| 194 // test if the specified field exists in which case it is safe to use it. | |
| 195 if ($field in $object) return $callback($field); | |
| 196 | |
| 197 // Symbol is from a different library. Make a best effort to | |
| 198 $field = $field.toString(); | |
| 199 $field = $field.substring('Symbol('.length, field.length - 1); | |
| 200 | |
| 201 } else if ($field.charAt(0) != '_') { | |
| 202 // Not a private member so default call path is safe. | |
| 203 return $callback($field); | |
| 204 } | |
| 205 | |
| 206 // If the exact field name is present, invoke callback with it. | |
| 207 if ($field in $object) return $callback($field); | |
| 208 | |
| 209 // TODO(jacobr): warn if there are multiple private members with the same | |
| 210 // name which could happen if super classes in different libraries have | |
| 211 // the same private member name. | |
| 212 let proto = $object; | |
| 213 while (proto !== null) { | |
| 214 // Private field (indicated with "_"). | |
| 215 let symbols = Object.getOwnPropertySymbols(proto); | |
| 216 let target = 'Symbol(' + $field + ')'; | |
| 217 | |
| 218 for (let s = 0; s < symbols.length; s++) { | |
| 219 let sym = symbols[s]; | |
| 220 if (target == sym.toString()) return $callback(sym); | |
| 221 } | |
| 222 proto = proto.__proto__; | |
| 223 } | |
| 224 // We didnt find a plausible alternate private symbol so just fall back | |
|
Jennifer Messerly
2016/10/18 18:46:01
typo: "didn't"
| |
| 225 // to the regular field. | |
| 226 return $callback(rawField); | |
| 227 })()'''); | |
| 228 | |
| 229 dloadRepl(obj, field) => | |
| 230 _dhelperRepl(obj, field, (resolvedField) => dload(obj, resolvedField)); | |
| 231 | |
| 232 dputRepl(obj, field, value) => _dhelperRepl( | |
| 233 obj, field, (resolvedField) => dput(obj, resolvedField, value)); | |
| 234 | |
| 235 _callMethodRepl(obj, method, typeArgs, args) => _dhelperRepl(obj, method, | |
| 236 (resolvedField) => _callMethod(obj, resolvedField, typeArgs, args, method)); | |
| 237 | |
| 238 dsendRepl(obj, method, @rest args) => _callMethodRepl(obj, method, null, args); | |
| 239 | |
| 240 dgsendRepl(obj, typeArgs, method, @rest args) => | |
| 241 _callMethodRepl(obj, method, typeArgs, args); | |
| 242 | |
| 185 class _MethodStats { | 243 class _MethodStats { |
| 186 final String typeName; | 244 final String typeName; |
| 187 final String frame; | 245 final String frame; |
| 188 int count; | 246 int count; |
| 189 | 247 |
| 190 _MethodStats(this.typeName, this.frame) { | 248 _MethodStats(this.typeName, this.frame) { |
| 191 count = 0; | 249 count = 0; |
| 192 } | 250 } |
| 193 } | 251 } |
| 194 | 252 |
| 195 Map<String, _MethodStats> _callMethodStats = new Map(); | 253 Map<String, _MethodStats> _callMethodStats = new Map(); |
| 196 | 254 |
| 197 List<List<Object>> getDynamicStats() { | 255 List<List<Object>> getDynamicStats() { |
| 198 List<List<Object>> ret = []; | 256 List<List<Object>> ret = []; |
| 199 | 257 |
| 200 var keys = _callMethodStats.keys.toList(); | 258 var keys = _callMethodStats.keys.toList(); |
| 201 | 259 |
| 202 keys.sort((a, b) => _callMethodStats[b].count.compareTo( | 260 keys.sort( |
| 203 _callMethodStats[a].count)); | 261 (a, b) => _callMethodStats[b].count.compareTo(_callMethodStats[a].count)); |
| 204 for (var key in keys) { | 262 for (var key in keys) { |
| 205 var stats = _callMethodStats[key]; | 263 var stats = _callMethodStats[key]; |
| 206 ret.add([stats.typeName, stats.frame, stats.count]); | 264 ret.add([stats.typeName, stats.frame, stats.count]); |
| 207 } | 265 } |
| 208 | 266 |
| 209 return ret; | 267 return ret; |
| 210 } | 268 } |
| 211 | 269 |
| 212 clearDynamicStats() { | 270 clearDynamicStats() { |
| 213 _callMethodStats.clear(); | 271 _callMethodStats.clear(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 224 var src = ''; | 282 var src = ''; |
| 225 for (int i = 2; i < stack.length; ++i) { | 283 for (int i = 2; i < stack.length; ++i) { |
| 226 var frame = stack[i]; | 284 var frame = stack[i]; |
| 227 if (!frame.contains('dart_sdk.js')) { | 285 if (!frame.contains('dart_sdk.js')) { |
| 228 src = frame; | 286 src = frame; |
| 229 break; | 287 break; |
| 230 } | 288 } |
| 231 } | 289 } |
| 232 | 290 |
| 233 var actualTypeName = typeName(actual); | 291 var actualTypeName = typeName(actual); |
| 234 _callMethodStats.putIfAbsent("$actualTypeName <$src>", | 292 _callMethodStats |
| 235 () => new _MethodStats(actualTypeName, src)).count++; | 293 .putIfAbsent( |
| 294 "$actualTypeName <$src>", () => new _MethodStats(actualTypeName, src)) | |
| 295 .count++; | |
| 236 } | 296 } |
| 237 | 297 |
| 238 /// Shared code for dsend, dindex, and dsetindex. | 298 /// Shared code for dsend, dindex, and dsetindex. |
| 239 _callMethod(obj, name, typeArgs, args, displayName) { | 299 _callMethod(obj, name, typeArgs, args, displayName) { |
| 240 var symbol = _canonicalMember(obj, name); | 300 var symbol = _canonicalMember(obj, name); |
| 241 if (symbol == null) { | 301 if (symbol == null) { |
| 242 return noSuchMethod(obj, | 302 return noSuchMethod( |
| 243 new InvocationImpl(displayName, args, isMethod: true)); | 303 obj, new InvocationImpl(displayName, args, isMethod: true)); |
| 244 } | 304 } |
| 245 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; | 305 var f = obj != null ? JS('', '#[#]', obj, symbol) : null; |
| 246 var ftype = getMethodType(obj, symbol); | 306 var ftype = getMethodType(obj, symbol); |
| 247 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); | 307 return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); |
| 248 } | 308 } |
| 249 | 309 |
| 250 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); | 310 dsend(obj, method, @rest args) => _callMethod(obj, method, null, args, method); |
| 251 | 311 |
| 252 dgsend(obj, typeArgs, method, @rest args) => | 312 dgsend(obj, typeArgs, method, @rest args) => |
| 253 _callMethod(obj, method, typeArgs, args, method); | 313 _callMethod(obj, method, typeArgs, args, method); |
| 254 | 314 |
| 255 dindex(obj, index) => _callMethod(obj, 'get', null, JS('', '[#]', index), '[]'); | 315 dindex(obj, index) => _callMethod(obj, 'get', null, JS('', '[#]', index), '[]'); |
| 256 | 316 |
| 257 dsetindex(obj, index, value) => | 317 dsetindex(obj, index, value) => |
| 258 _callMethod(obj, 'set', null, JS('', '[#, #]', index, value), '[]='); | 318 _callMethod(obj, 'set', null, JS('', '[#, #]', index, value), '[]='); |
| 259 | 319 |
| 260 /// TODO(leafp): This duplicates code in types.dart. | 320 /// TODO(leafp): This duplicates code in types.dart. |
| 261 /// I haven't found a way to factor it out that makes the | 321 /// I haven't found a way to factor it out that makes the |
| 262 /// code generator happy though. | 322 /// code generator happy though. |
| 263 _ignoreMemo(f) => JS('', '''(() => { | 323 _ignoreMemo(f) => JS( |
| 324 '', | |
| 325 '''(() => { | |
| 264 let memo = new Map(); | 326 let memo = new Map(); |
| 265 return (t1, t2) => { | 327 return (t1, t2) => { |
| 266 let map = memo.get(t1); | 328 let map = memo.get(t1); |
| 267 let result; | 329 let result; |
| 268 if (map) { | 330 if (map) { |
| 269 result = map.get(t2); | 331 result = map.get(t2); |
| 270 if (result !== void 0) return result; | 332 if (result !== void 0) return result; |
| 271 } else { | 333 } else { |
| 272 memo.set(t1, map = new Map()); | 334 memo.set(t1, map = new Map()); |
| 273 } | 335 } |
| 274 result = $f(t1, t2); | 336 result = $f(t1, t2); |
| 275 map.set(t2, result); | 337 map.set(t2, result); |
| 276 return result; | 338 return result; |
| 277 }; | 339 }; |
| 278 })()'''); | 340 })()'''); |
| 279 | 341 |
| 280 final _ignoreTypeFailure = JS('', '''(() => { | 342 final _ignoreTypeFailure = JS( |
| 343 '', | |
| 344 '''(() => { | |
| 281 return $_ignoreMemo((actual, type) => { | 345 return $_ignoreMemo((actual, type) => { |
| 282 // TODO(vsm): Remove this hack ... | 346 // TODO(vsm): Remove this hack ... |
| 283 // This is primarily due to the lack of generic methods, | 347 // This is primarily due to the lack of generic methods, |
| 284 // but we need to triage all the types. | 348 // but we need to triage all the types. |
| 285 if (!!$isSubtype(type, $Iterable) && !!$isSubtype(actual, $Iterable) || | 349 if (!!$isSubtype(type, $Iterable) && !!$isSubtype(actual, $Iterable) || |
| 286 !!$isSubtype(type, $Future) && !!$isSubtype(actual, $Future) || | 350 !!$isSubtype(type, $Future) && !!$isSubtype(actual, $Future) || |
| 287 !!$isSubtype(type, $Map) && !!$isSubtype(actual, $Map) || | 351 !!$isSubtype(type, $Map) && !!$isSubtype(actual, $Map) || |
| 288 $isFunctionType(type) && $isFunctionType(actual) || | 352 $isFunctionType(type) && $isFunctionType(actual) || |
| 289 !!$isSubtype(type, $Stream) && !!$isSubtype(actual, $Stream) || | 353 !!$isSubtype(type, $Stream) && !!$isSubtype(actual, $Stream) || |
| 290 !!$isSubtype(type, $StreamSubscription) && | 354 !!$isSubtype(type, $StreamSubscription) && |
| 291 !!$isSubtype(actual, $StreamSubscription)) { | 355 !!$isSubtype(actual, $StreamSubscription)) { |
| 292 console.warn('Ignoring cast fail from ' + $typeName(actual) + | 356 console.warn('Ignoring cast fail from ' + $typeName(actual) + |
| 293 ' to ' + $typeName(type)); | 357 ' to ' + $typeName(type)); |
| 294 return true; | 358 return true; |
| 295 } | 359 } |
| 296 return false; | 360 return false; |
| 297 }); | 361 }); |
| 298 })()'''); | 362 })()'''); |
| 299 | 363 |
| 300 /// Returns true if [obj] is an instance of [type] | 364 /// Returns true if [obj] is an instance of [type] |
| 301 /// Returns false if [obj] is not an instance of [type] in both spec | 365 /// Returns false if [obj] is not an instance of [type] in both spec |
| 302 /// and strong mode | 366 /// and strong mode |
| 303 /// Returns null if [obj] is not an instance of [type] in strong mode | 367 /// Returns null if [obj] is not an instance of [type] in strong mode |
| 304 /// but might be in spec mode | 368 /// but might be in spec mode |
| 305 bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => { | 369 bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS( |
| 370 '', | |
| 371 '''(() => { | |
| 306 let actual = $getReifiedType($obj); | 372 let actual = $getReifiedType($obj); |
| 307 let result = $isSubtype(actual, $type); | 373 let result = $isSubtype(actual, $type); |
| 308 if (result || actual == $jsobject || | 374 if (result || actual == $jsobject || |
| 309 actual == $int && type == $double) return true; | 375 actual == $int && type == $double) return true; |
| 310 if (result === false) return false; | 376 if (result === false) return false; |
| 311 if ($ignoreFromWhiteList == void 0) return result; | 377 if ($ignoreFromWhiteList == void 0) return result; |
| 312 if ($_ignoreTypeFailure(actual, $type)) return true; | 378 if ($_ignoreTypeFailure(actual, $type)) return true; |
| 313 return result; | 379 return result; |
| 314 })()'''); | 380 })()'''); |
| 315 | 381 |
| 316 /// Returns true if [obj] is null or an instance of [type] | 382 /// Returns true if [obj] is null or an instance of [type] |
| 317 /// Returns false if [obj] is non-null and not an instance of [type] | 383 /// Returns false if [obj] is non-null and not an instance of [type] |
| 318 /// in strong mode | 384 /// in strong mode |
| 319 instanceOfOrNull(obj, type) => JS('', '''(() => { | 385 instanceOfOrNull(obj, type) => JS( |
| 386 '', | |
| 387 '''(() => { | |
| 320 // If strongInstanceOf returns null, convert to false here. | 388 // If strongInstanceOf returns null, convert to false here. |
| 321 if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true; | 389 if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true; |
| 322 return false; | 390 return false; |
| 323 })()'''); | 391 })()'''); |
| 324 | 392 |
| 325 @JSExportName('is') | 393 @JSExportName('is') |
| 326 instanceOf(obj, type) => JS('', '''(() => { | 394 instanceOf(obj, type) => JS( |
| 395 '', | |
| 396 '''(() => { | |
| 327 let result = $strongInstanceOf($obj, $type); | 397 let result = $strongInstanceOf($obj, $type); |
| 328 if (result !== null) return result; | 398 if (result !== null) return result; |
| 329 let actual = $getReifiedType($obj); | 399 let actual = $getReifiedType($obj); |
| 330 $throwStrongModeError('Strong mode is-check failure: ' + | 400 $throwStrongModeError('Strong mode is-check failure: ' + |
| 331 $typeName(actual) + ' does not soundly subtype ' + | 401 $typeName(actual) + ' does not soundly subtype ' + |
| 332 $typeName($type)); | 402 $typeName($type)); |
| 333 })()'''); | 403 })()'''); |
| 334 | 404 |
| 335 @JSExportName('as') | 405 @JSExportName('as') |
| 336 cast(obj, type) { | 406 cast(obj, type) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 | 452 |
| 383 if (JS('bool', 'Math.floor(#) != #', obj, obj)) { | 453 if (JS('bool', 'Math.floor(#) != #', obj, obj)) { |
| 384 throwCastError(obj, getReifiedType(obj), JS('', '#', int)); | 454 throwCastError(obj, getReifiedType(obj), JS('', '#', int)); |
| 385 } | 455 } |
| 386 return obj; | 456 return obj; |
| 387 } | 457 } |
| 388 | 458 |
| 389 /// Adds type type test predicates to a constructor for a non-parameterized | 459 /// Adds type type test predicates to a constructor for a non-parameterized |
| 390 /// type. Non-parameterized types can use `instanceof` for subclass checks and | 460 /// type. Non-parameterized types can use `instanceof` for subclass checks and |
| 391 /// fall through to a helper for subtype tests. | 461 /// fall through to a helper for subtype tests. |
| 392 addSimpleTypeTests(ctor) => JS('', '''(() => { | 462 addSimpleTypeTests(ctor) => JS( |
| 463 '', | |
| 464 '''(() => { | |
| 393 $ctor.is = function is_C(object) { | 465 $ctor.is = function is_C(object) { |
| 394 // This is incorrect for classes [Null] and [Object], so we do not use | 466 // This is incorrect for classes [Null] and [Object], so we do not use |
| 395 // [addSimpleTypeTests] for these classes. | 467 // [addSimpleTypeTests] for these classes. |
| 396 if (object instanceof this) return true; | 468 if (object instanceof this) return true; |
| 397 return dart.is(object, this); | 469 return dart.is(object, this); |
| 398 }; | 470 }; |
| 399 $ctor.as = function as_C(object) { | 471 $ctor.as = function as_C(object) { |
| 400 if (object instanceof this) return object; | 472 if (object instanceof this) return object; |
| 401 return dart.as(object, this); | 473 return dart.as(object, this); |
| 402 }; | 474 }; |
| 403 $ctor._check = function check_C(object) { | 475 $ctor._check = function check_C(object) { |
| 404 if (object instanceof this) return object; | 476 if (object instanceof this) return object; |
| 405 return dart.check(object, this); | 477 return dart.check(object, this); |
| 406 }; | 478 }; |
| 407 })()'''); | 479 })()'''); |
| 408 | 480 |
| 409 /// Adds type type test predicates to a constructor. Used for parmeterized | 481 /// Adds type type test predicates to a constructor. Used for parmeterized |
| 410 /// types. We avoid `instanceof` for, e.g. `x is ListQueue` since there is | 482 /// types. We avoid `instanceof` for, e.g. `x is ListQueue` since there is |
| 411 /// no common class for `ListQueue<int>` and `ListQueue<String>`. | 483 /// no common class for `ListQueue<int>` and `ListQueue<String>`. |
| 412 addTypeTests(ctor) => JS('', '''(() => { | 484 addTypeTests(ctor) => JS( |
| 485 '', | |
| 486 '''(() => { | |
| 413 $ctor.as = function as_G(object) { | 487 $ctor.as = function as_G(object) { |
| 414 return dart.as(object, this); | 488 return dart.as(object, this); |
| 415 }; | 489 }; |
| 416 $ctor.is = function is_G(object) { | 490 $ctor.is = function is_G(object) { |
| 417 return dart.is(object, this); | 491 return dart.is(object, this); |
| 418 }; | 492 }; |
| 419 $ctor._check = function check_G(object) { | 493 $ctor._check = function check_G(object) { |
| 420 return dart.check(object, this); | 494 return dart.check(object, this); |
| 421 }; | 495 }; |
| 422 })()'''); | 496 })()'''); |
| 423 | 497 |
| 424 equals(x, y) => JS('', '''(() => { | 498 equals(x, y) => JS( |
| 499 '', | |
| 500 '''(() => { | |
| 425 if ($x == null || $y == null) return $x == $y; | 501 if ($x == null || $y == null) return $x == $y; |
| 426 let eq = $x['==']; | 502 let eq = $x['==']; |
| 427 return eq ? eq.call($x, $y) : $x === $y; | 503 return eq ? eq.call($x, $y) : $x === $y; |
| 428 })()'''); | 504 })()'''); |
| 429 | 505 |
| 430 /// Checks that `x` is not null or undefined. */ | 506 /// Checks that `x` is not null or undefined. */ |
| 431 notNull(x) { | 507 notNull(x) { |
| 432 if (x == null) throwNullValueError(); | 508 if (x == null) throwNullValueError(); |
| 433 return x; | 509 return x; |
| 434 } | 510 } |
| 435 | 511 |
| 436 /// | 512 /// |
| 437 /// Creates a dart:collection LinkedHashMap. | 513 /// Creates a dart:collection LinkedHashMap. |
| 438 /// | 514 /// |
| 439 /// For a map with string keys an object literal can be used, for example | 515 /// For a map with string keys an object literal can be used, for example |
| 440 /// `map({'hi': 1, 'there': 2})`. | 516 /// `map({'hi': 1, 'there': 2})`. |
| 441 /// | 517 /// |
| 442 /// Otherwise an array should be used, for example `map([1, 2, 3, 4])` will | 518 /// Otherwise an array should be used, for example `map([1, 2, 3, 4])` will |
| 443 /// create a map with keys [1, 3] and values [2, 4]. Each key-value pair | 519 /// create a map with keys [1, 3] and values [2, 4]. Each key-value pair |
| 444 /// should be adjacent entries in the array. | 520 /// should be adjacent entries in the array. |
| 445 /// | 521 /// |
| 446 /// For a map with no keys the function can be called with no arguments, for | 522 /// For a map with no keys the function can be called with no arguments, for |
| 447 /// example `map()`. | 523 /// example `map()`. |
| 448 /// | 524 /// |
| 449 // TODO(jmesserly): this could be faster | 525 // TODO(jmesserly): this could be faster |
| 450 // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed. | 526 // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed. |
| 451 // TODO(jmesserly): move this to classes for consistentcy with list literals? | 527 // TODO(jmesserly): move this to classes for consistentcy with list literals? |
| 452 map(values, [K, V]) => JS('', '''(() => { | 528 map(values, [K, V]) => JS( |
| 529 '', | |
| 530 '''(() => { | |
| 453 if ($K == null) $K = $dynamic; | 531 if ($K == null) $K = $dynamic; |
| 454 if ($V == null) $V = $dynamic; | 532 if ($V == null) $V = $dynamic; |
| 455 let map = ${getGenericClass(LinkedHashMap)}($K, $V).new(); | 533 let map = ${getGenericClass(LinkedHashMap)}($K, $V).new(); |
| 456 if (Array.isArray($values)) { | 534 if (Array.isArray($values)) { |
| 457 for (let i = 0, end = $values.length - 1; i < end; i += 2) { | 535 for (let i = 0, end = $values.length - 1; i < end; i += 2) { |
| 458 let key = $values[i]; | 536 let key = $values[i]; |
| 459 let value = $values[i + 1]; | 537 let value = $values[i + 1]; |
| 460 map.set(key, value); | 538 map.set(key, value); |
| 461 } | 539 } |
| 462 } else if (typeof $values === 'object') { | 540 } else if (typeof $values === 'object') { |
| 463 for (let key of $getOwnPropertyNames($values)) { | 541 for (let key of $getOwnPropertyNames($values)) { |
| 464 map.set(key, $values[key]); | 542 map.set(key, $values[key]); |
| 465 } | 543 } |
| 466 } | 544 } |
| 467 return map; | 545 return map; |
| 468 })()'''); | 546 })()'''); |
| 469 | 547 |
| 470 @JSExportName('assert') | 548 @JSExportName('assert') |
| 471 assert_(condition) => JS('', '''(() => { | 549 assert_(condition) => JS( |
| 550 '', | |
| 551 '''(() => { | |
| 472 if (!$condition) $throwAssertionError(); | 552 if (!$condition) $throwAssertionError(); |
| 473 })()'''); | 553 })()'''); |
| 474 | 554 |
| 475 final _stack = JS('', 'new WeakMap()'); | 555 final _stack = JS('', 'new WeakMap()'); |
| 476 @JSExportName('throw') | 556 @JSExportName('throw') |
| 477 throw_(obj) => JS('', '''(() => { | 557 throw_(obj) => JS( |
| 558 '', | |
| 559 '''(() => { | |
| 478 if ($obj != null && (typeof $obj == 'object' || typeof $obj == 'function')) { | 560 if ($obj != null && (typeof $obj == 'object' || typeof $obj == 'function')) { |
| 479 // TODO(jmesserly): couldn't we store the most recent stack in a single | 561 // TODO(jmesserly): couldn't we store the most recent stack in a single |
| 480 // variable? There should only be one active stack trace. That would | 562 // variable? There should only be one active stack trace. That would |
| 481 // allow it to work for things like strings and numbers. | 563 // allow it to work for things like strings and numbers. |
| 482 $_stack.set($obj, new Error()); | 564 $_stack.set($obj, new Error()); |
| 483 } | 565 } |
| 484 throw $obj; | 566 throw $obj; |
| 485 })()'''); | 567 })()'''); |
| 486 | 568 |
| 487 getError(exception) => JS('', '''(() => { | 569 getError(exception) => JS( |
| 570 '', | |
| 571 '''(() => { | |
| 488 var stack = $_stack.get($exception); | 572 var stack = $_stack.get($exception); |
| 489 return stack !== void 0 ? stack : $exception; | 573 return stack !== void 0 ? stack : $exception; |
| 490 })()'''); | 574 })()'''); |
| 491 | 575 |
| 492 // This is a utility function: it is only intended to be called from dev | 576 // This is a utility function: it is only intended to be called from dev |
| 493 // tools. | 577 // tools. |
| 494 stackPrint(exception) => JS('', '''(() => { | 578 stackPrint(exception) => JS( |
| 579 '', | |
| 580 '''(() => { | |
| 495 var error = $getError($exception); | 581 var error = $getError($exception); |
| 496 console.log(error.stack ? error.stack : 'No stack trace for: ' + error); | 582 console.log(error.stack ? error.stack : 'No stack trace for: ' + error); |
| 497 })()'''); | 583 })()'''); |
| 498 | 584 |
| 499 stackTrace(exception) => JS('', '''(() => { | 585 stackTrace(exception) => JS( |
| 586 '', | |
| 587 '''(() => { | |
| 500 var error = $getError($exception); | 588 var error = $getError($exception); |
| 501 return $getTraceFromException(error); | 589 return $getTraceFromException(error); |
| 502 })()'''); | 590 })()'''); |
| 503 | 591 |
| 504 /// | 592 /// |
| 505 /// Implements a sequence of .? operations. | 593 /// Implements a sequence of .? operations. |
| 506 /// | 594 /// |
| 507 /// Will call each successive callback, unless one returns null, which stops | 595 /// Will call each successive callback, unless one returns null, which stops |
| 508 /// the sequence. | 596 /// the sequence. |
| 509 /// | 597 /// |
| 510 nullSafe(obj, @rest callbacks) => JS('', '''(() => { | 598 nullSafe(obj, @rest callbacks) => JS( |
| 599 '', | |
| 600 '''(() => { | |
| 511 if ($obj == null) return $obj; | 601 if ($obj == null) return $obj; |
| 512 for (let callback of $callbacks) { | 602 for (let callback of $callbacks) { |
| 513 $obj = callback($obj); | 603 $obj = callback($obj); |
| 514 if ($obj == null) break; | 604 if ($obj == null) break; |
| 515 } | 605 } |
| 516 return $obj; | 606 return $obj; |
| 517 })()'''); | 607 })()'''); |
| 518 | 608 |
| 519 final _value = JS('', 'Symbol("_value")'); | 609 final _value = JS('', 'Symbol("_value")'); |
| 610 | |
| 520 /// | 611 /// |
| 521 /// Looks up a sequence of [keys] in [map], recursively, and | 612 /// Looks up a sequence of [keys] in [map], recursively, and |
| 522 /// returns the result. If the value is not found, [valueFn] will be called to | 613 /// returns the result. If the value is not found, [valueFn] will be called to |
| 523 /// add it. For example: | 614 /// add it. For example: |
| 524 /// | 615 /// |
| 525 /// let map = new Map(); | 616 /// let map = new Map(); |
| 526 /// putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world'); | 617 /// putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world'); |
| 527 /// | 618 /// |
| 528 /// ... will create a Map with a structure like: | 619 /// ... will create a Map with a structure like: |
| 529 /// | 620 /// |
| 530 /// { 1: { 2: { 'hi ': { 'there ': 'world' } } } } | 621 /// { 1: { 2: { 'hi ': { 'there ': 'world' } } } } |
| 531 /// | 622 /// |
| 532 multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => { | 623 multiKeyPutIfAbsent(map, keys, valueFn) => JS( |
| 624 '', | |
| 625 '''(() => { | |
| 533 for (let k of $keys) { | 626 for (let k of $keys) { |
| 534 let value = $map.get(k); | 627 let value = $map.get(k); |
| 535 if (!value) { | 628 if (!value) { |
| 536 // TODO(jmesserly): most of these maps are very small (e.g. 1 item), | 629 // TODO(jmesserly): most of these maps are very small (e.g. 1 item), |
| 537 // so it may be worth optimizing for that. | 630 // so it may be worth optimizing for that. |
| 538 $map.set(k, value = new Map()); | 631 $map.set(k, value = new Map()); |
| 539 } | 632 } |
| 540 $map = value; | 633 $map = value; |
| 541 } | 634 } |
| 542 if ($map.has($_value)) return $map.get($_value); | 635 if ($map.has($_value)) return $map.get($_value); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 554 final constants = JS('', 'new Map()'); | 647 final constants = JS('', 'new Map()'); |
| 555 | 648 |
| 556 /// | 649 /// |
| 557 /// Canonicalize a constant object. | 650 /// Canonicalize a constant object. |
| 558 /// | 651 /// |
| 559 /// Preconditions: | 652 /// Preconditions: |
| 560 /// - `obj` is an objects or array, not a primitive. | 653 /// - `obj` is an objects or array, not a primitive. |
| 561 /// - nested values of the object are themselves already canonicalized. | 654 /// - nested values of the object are themselves already canonicalized. |
| 562 /// | 655 /// |
| 563 @JSExportName('const') | 656 @JSExportName('const') |
| 564 const_(obj) => JS('', '''(() => { | 657 const_(obj) => JS( |
| 658 '', | |
| 659 '''(() => { | |
| 565 // TODO(leafp): This table gets quite large in apps. | 660 // TODO(leafp): This table gets quite large in apps. |
| 566 // Keeping the paths is probably expensive. It would probably | 661 // Keeping the paths is probably expensive. It would probably |
| 567 // be more space efficient to just use a direct hash table with | 662 // be more space efficient to just use a direct hash table with |
| 568 // an appropriately defined structural equality function. | 663 // an appropriately defined structural equality function. |
| 569 function lookupNonTerminal(map, key) { | 664 function lookupNonTerminal(map, key) { |
| 570 let result = map.get(key); | 665 let result = map.get(key); |
| 571 if (result !== void 0) return result; | 666 if (result !== void 0) return result; |
| 572 map.set(key, result = new Map()); | 667 map.set(key, result = new Map()); |
| 573 return result; | 668 return result; |
| 574 }; | 669 }; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 605 /// This maps the number of elements in the list (n) | 700 /// This maps the number of elements in the list (n) |
| 606 /// to a path of length n of maps indexed by the value | 701 /// to a path of length n of maps indexed by the value |
| 607 /// of the field. The final map is indexed by the element | 702 /// of the field. The final map is indexed by the element |
| 608 /// type and contains the canonical version of the list. | 703 /// type and contains the canonical version of the list. |
| 609 final constantLists = JS('', 'new Map()'); | 704 final constantLists = JS('', 'new Map()'); |
| 610 | 705 |
| 611 /// | 706 /// |
| 612 /// Canonicalize a constant list | 707 /// Canonicalize a constant list |
| 613 /// | 708 /// |
| 614 @JSExportName('constList') | 709 @JSExportName('constList') |
| 615 constList_(elements, elementType) => JS('', '''(() => { | 710 constList_(elements, elementType) => JS( |
| 711 '', | |
| 712 '''(() => { | |
| 616 function lookupNonTerminal(map, key) { | 713 function lookupNonTerminal(map, key) { |
| 617 let result = map.get(key); | 714 let result = map.get(key); |
| 618 if (result !== void 0) return result; | 715 if (result !== void 0) return result; |
| 619 map.set(key, result = new Map()); | 716 map.set(key, result = new Map()); |
| 620 return result; | 717 return result; |
| 621 }; | 718 }; |
| 622 let count = $elements.length; | 719 let count = $elements.length; |
| 623 let map = lookupNonTerminal($constantLists, count); | 720 let map = lookupNonTerminal($constantLists, count); |
| 624 for (let i = 0; i < count; i++) { | 721 for (let i = 0; i < count; i++) { |
| 625 map = lookupNonTerminal(map, elements[i]); | 722 map = lookupNonTerminal(map, elements[i]); |
| 626 } | 723 } |
| 627 let value = map.get($elementType); | 724 let value = map.get($elementType); |
| 628 if (value) return value; | 725 if (value) return value; |
| 629 value = $list($elements, $elementType); | 726 value = $list($elements, $elementType); |
| 630 map.set($elementType, value); | 727 map.set($elementType, value); |
| 631 return value; | 728 return value; |
| 632 })()'''); | 729 })()'''); |
| 633 | 730 |
| 634 // The following are helpers for Object methods when the receiver | 731 // The following are helpers for Object methods when the receiver |
| 635 // may be null or primitive. These should only be generated by | 732 // may be null or primitive. These should only be generated by |
| 636 // the compiler. | 733 // the compiler. |
| 637 hashCode(obj) { | 734 hashCode(obj) { |
| 638 if (obj == null) return 0; | 735 if (obj == null) return 0; |
| 639 | 736 |
| 640 switch (JS('String', 'typeof #', obj)) { | 737 switch (JS('String', 'typeof #', obj)) { |
| 641 case "number": | 738 case "number": |
| 642 return JS('','# & 0x1FFFFFFF', obj); | 739 return JS('', '# & 0x1FFFFFFF', obj); |
| 643 case "boolean": | 740 case "boolean": |
| 644 // From JSBool.hashCode, see comment there. | 741 // From JSBool.hashCode, see comment there. |
| 645 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); | 742 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); |
| 646 case "function": | 743 case "function": |
| 647 // TODO(jmesserly): this doesn't work for method tear-offs. | 744 // TODO(jmesserly): this doesn't work for method tear-offs. |
| 648 return Primitives.objectHashCode(obj); | 745 return Primitives.objectHashCode(obj); |
| 649 } | 746 } |
| 650 | 747 |
| 651 var extension = getExtensionType(obj); | 748 var extension = getExtensionType(obj); |
| 652 if (extension != null) { | 749 if (extension != null) { |
| 653 return JS('', '#[dartx.hashCode]', obj); | 750 return JS('', '#[dartx.hashCode]', obj); |
| 654 } | 751 } |
| 655 return JS('', '#.hashCode', obj); | 752 return JS('', '#.hashCode', obj); |
| 656 } | 753 } |
| 657 | 754 |
| 658 @JSExportName('toString') | 755 @JSExportName('toString') |
| 659 String _toString(obj) { | 756 String _toString(obj) { |
| 660 if (obj == null) return "null"; | 757 if (obj == null) return "null"; |
| 661 | 758 |
| 662 var extension = getExtensionType(obj); | 759 var extension = getExtensionType(obj); |
| 663 if (extension != null) { | 760 if (extension != null) { |
| 664 return JS('String', '#[dartx.toString]()', obj); | 761 return JS('String', '#[dartx.toString]()', obj); |
| 665 } | 762 } |
| 666 if (JS('bool', 'typeof # == "function"', obj)) { | 763 if (JS('bool', 'typeof # == "function"', obj)) { |
| 667 return JS('String', r'"Closure: " + # + " from: " + #', | 764 return JS( |
| 668 getReifiedType(obj), obj); | 765 'String', r'"Closure: " + # + " from: " + #', getReifiedType(obj), obj); |
| 669 } | 766 } |
| 670 // TODO(jmesserly): restore this faster path once ES Symbol is treated as | 767 // TODO(jmesserly): restore this faster path once ES Symbol is treated as |
| 671 // an extension type (and thus hits the above code path). | 768 // an extension type (and thus hits the above code path). |
| 672 // See https://github.com/dart-lang/dev_compiler/issues/578. | 769 // See https://github.com/dart-lang/dev_compiler/issues/578. |
| 673 // return JS('', '"" + #', obj); | 770 // return JS('', '"" + #', obj); |
| 674 return JS('String', '#.toString()', obj); | 771 return JS('String', '#.toString()', obj); |
| 675 } | 772 } |
| 676 | 773 |
| 677 // TODO(jmesserly): is the argument type verified statically? | 774 // TODO(jmesserly): is the argument type verified statically? |
| 678 noSuchMethod(obj, Invocation invocation) { | 775 noSuchMethod(obj, Invocation invocation) { |
| 679 if (obj == null || JS('bool', 'typeof # == "function"', obj)) { | 776 if (obj == null || JS('bool', 'typeof # == "function"', obj)) { |
| 680 throw new NoSuchMethodError( | 777 throw new NoSuchMethodError(obj, invocation.memberName, |
| 681 obj, | 778 invocation.positionalArguments, invocation.namedArguments); |
| 682 invocation.memberName, | |
| 683 invocation.positionalArguments, | |
| 684 invocation.namedArguments); | |
| 685 } | 779 } |
| 686 // Delegate to the (possibly user-defined) method on the object. | 780 // Delegate to the (possibly user-defined) method on the object. |
| 687 var extension = getExtensionType(obj); | 781 var extension = getExtensionType(obj); |
| 688 if (extension != null) { | 782 if (extension != null) { |
| 689 return JS('', '#[dartx.noSuchMethod](#)', obj, invocation); | 783 return JS('', '#[dartx.noSuchMethod](#)', obj, invocation); |
| 690 } | 784 } |
| 691 return JS('', '#.noSuchMethod(#)', obj, invocation); | 785 return JS('', '#.noSuchMethod(#)', obj, invocation); |
| 692 } | 786 } |
| 693 | 787 |
| 694 constFn(x) => JS('', '() => x'); | 788 constFn(x) => JS('', '() => x'); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 705 } | 799 } |
| 706 if (JS('bool', 'typeof # == "function"', obj)) { | 800 if (JS('bool', 'typeof # == "function"', obj)) { |
| 707 return wrapType(getReifiedType(obj)); | 801 return wrapType(getReifiedType(obj)); |
| 708 } | 802 } |
| 709 return JS('', '#.runtimeType', obj); | 803 return JS('', '#.runtimeType', obj); |
| 710 } | 804 } |
| 711 | 805 |
| 712 /// Implements Dart's interpolated strings as ES2015 tagged template literals. | 806 /// Implements Dart's interpolated strings as ES2015 tagged template literals. |
| 713 /// | 807 /// |
| 714 /// For example: dart.str`hello ${name}` | 808 /// For example: dart.str`hello ${name}` |
| 715 String str(strings, @rest values) => JS('', '''(() => { | 809 String str(strings, @rest values) => JS( |
| 810 '', | |
| 811 '''(() => { | |
| 716 let s = $strings[0]; | 812 let s = $strings[0]; |
| 717 for (let i = 0, len = $values.length; i < len; ) { | 813 for (let i = 0, len = $values.length; i < len; ) { |
| 718 s += $notNull($_toString($values[i])) + $strings[++i]; | 814 s += $notNull($_toString($values[i])) + $strings[++i]; |
| 719 } | 815 } |
| 720 return s; | 816 return s; |
| 721 })()'''); | 817 })()'''); |
| 722 | 818 |
| 723 | 819 final JsIterator = JS( |
| 724 final JsIterator = JS('', ''' | 820 '', |
| 821 ''' | |
| 725 class JsIterator { | 822 class JsIterator { |
| 726 constructor(dartIterator) { | 823 constructor(dartIterator) { |
| 727 this.dartIterator = dartIterator; | 824 this.dartIterator = dartIterator; |
| 728 } | 825 } |
| 729 next() { | 826 next() { |
| 730 let i = this.dartIterator; | 827 let i = this.dartIterator; |
| 731 let done = !i.moveNext(); | 828 let done = !i.moveNext(); |
| 732 return { done: done, value: done ? void 0 : i.current }; | 829 return { done: done, value: done ? void 0 : i.current }; |
| 733 } | 830 } |
| 734 } | 831 } |
| 735 '''); | 832 '''); |
| 736 | 833 |
| 737 _canonicalMember(obj, name) { | 834 _canonicalMember(obj, name) { |
| 738 // Private names are symbols and are already canonical. | 835 // Private names are symbols and are already canonical. |
| 739 if (JS('bool', 'typeof # === "symbol"', name)) return name; | 836 if (JS('bool', 'typeof # === "symbol"', name)) return name; |
| 740 | 837 |
| 741 if (obj != null && getExtensionType(obj) != null) { | 838 if (obj != null && getExtensionType(obj) != null) { |
| 742 return JS('', 'dartx.#', name); | 839 return JS('', 'dartx.#', name); |
| 743 } | 840 } |
| 744 | 841 |
| 745 // Check for certain names that we can't use in JS | 842 // Check for certain names that we can't use in JS |
| 746 if (name == 'constructor' || name == 'prototype') { | 843 if (name == 'constructor' || name == 'prototype') { |
| 747 name = '+' + name; | 844 name = '+' + name; |
| 748 } | 845 } |
| 749 return name; | 846 return name; |
| 750 } | 847 } |
| OLD | NEW |