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 _canonicalFieldName(obj, name, args, displayName) => JS('', '''(() => { | 9 _canonicalFieldName(obj, name, args, displayName) => JS('', '''(() => { |
10 $name = $canonicalMember($obj, $name); | 10 $name = $canonicalMember($obj, $name); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
114 $throwStrongModeError('call to JS object `' + $obj + | 114 $throwStrongModeError('call to JS object `' + $obj + |
115 '` with type arguments <' + $typeArgs + '> is not supported.'); | 115 '` with type arguments <' + $typeArgs + '> is not supported.'); |
116 } | 116 } |
117 return $f.apply($obj, $args); | 117 return $f.apply($obj, $args); |
118 } | 118 } |
119 | 119 |
120 // Apply type arguments | 120 // Apply type arguments |
121 let formalCount = $ftype[$_typeFormalCount]; | 121 let formalCount = $ftype[$_typeFormalCount]; |
122 if (formalCount != null) { | 122 if (formalCount != null) { |
123 if ($typeArgs == null) { | 123 if ($typeArgs == null) { |
124 $typeArgs = Array(formalCount).fill($dynamicR); | 124 $typeArgs = Array(formalCount).fill($dynamic); |
125 } else if ($typeArgs.length != formalCount) { | 125 } else if ($typeArgs.length != formalCount) { |
126 // TODO(jmesserly): is this the right error? | 126 // TODO(jmesserly): is this the right error? |
127 $throwStrongModeError( | 127 $throwStrongModeError( |
128 'incorrect number of arguments to generic function ' + | 128 'incorrect number of arguments to generic function ' + |
129 $typeName($ftype) + ', got <' + $typeArgs + '> expected ' + | 129 $typeName($ftype) + ', got <' + $typeArgs + '> expected ' + |
130 formalCount + '.'); | 130 formalCount + '.'); |
131 } | 131 } |
132 // Instantiate the function. | 132 // Instantiate the function. |
133 $ftype = $ftype(...$typeArgs); | 133 $ftype = $ftype(...$typeArgs); |
134 } else if ($typeArgs != null) { | 134 } else if ($typeArgs != null) { |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
261 return { min: $f.length, max: $f.length }; | 261 return { min: $f.length, max: $f.length }; |
262 })()'''); | 262 })()'''); |
263 | 263 |
264 equals(x, y) => JS('', '''(() => { | 264 equals(x, y) => JS('', '''(() => { |
265 if ($x == null || $y == null) return $x == $y; | 265 if ($x == null || $y == null) return $x == $y; |
266 let eq = $x['==']; | 266 let eq = $x['==']; |
267 return eq ? eq.call($x, $y) : $x === $y; | 267 return eq ? eq.call($x, $y) : $x === $y; |
268 })()'''); | 268 })()'''); |
269 | 269 |
270 /// Checks that `x` is not null or undefined. */ | 270 /// Checks that `x` is not null or undefined. */ |
271 notNull(x) => JS('', '''(() => { | 271 notNull(x) { |
272 if ($x == null) $throwNullValueError(); | 272 if (x == null) throwNullValueError(); |
273 return $x; | 273 return x; |
274 })()'''); | 274 } |
275 | 275 |
276 /// | 276 /// |
277 /// Creates a dart:collection LinkedHashMap. | 277 /// Creates a dart:collection LinkedHashMap. |
278 /// | 278 /// |
279 /// For a map with string keys an object literal can be used, for example | 279 /// For a map with string keys an object literal can be used, for example |
280 /// `map({'hi': 1, 'there': 2})`. | 280 /// `map({'hi': 1, 'there': 2})`. |
281 /// | 281 /// |
282 /// Otherwise an array should be used, for example `map([1, 2, 3, 4])` will | 282 /// Otherwise an array should be used, for example `map([1, 2, 3, 4])` will |
283 /// create a map with keys [1, 3] and values [2, 4]. Each key-value pair | 283 /// create a map with keys [1, 3] and values [2, 4]. Each key-value pair |
284 /// should be adjacent entries in the array. | 284 /// should be adjacent entries in the array. |
285 /// | 285 /// |
286 /// For a map with no keys the function can be called with no arguments, for | 286 /// For a map with no keys the function can be called with no arguments, for |
287 /// example `map()`. | 287 /// example `map()`. |
288 /// | 288 /// |
289 // TODO(jmesserly): this could be faster | 289 // TODO(jmesserly): this could be faster |
290 // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed. | 290 // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed. |
291 // TODO(jmesserly): move this to classes for consistentcy with list literals? | 291 // TODO(jmesserly): move this to classes for consistentcy with list literals? |
292 map(values, [K, V]) => JS('', '''(() => { | 292 map(values, [K, V]) => JS('', '''(() => { |
293 if ($K == null) $K = $dynamicR; | 293 if ($K == null) $K = $dynamic; |
294 if ($V == null) $V = $dynamicR; | 294 if ($V == null) $V = $dynamic; |
295 let map = ${getGenericClass(LinkedHashMap)}($K, $V).new(); | 295 let map = ${getGenericClass(LinkedHashMap)}($K, $V).new(); |
296 if (Array.isArray($values)) { | 296 if (Array.isArray($values)) { |
297 for (let i = 0, end = $values.length - 1; i < end; i += 2) { | 297 for (let i = 0, end = $values.length - 1; i < end; i += 2) { |
298 let key = $values[i]; | 298 let key = $values[i]; |
299 let value = $values[i + 1]; | 299 let value = $values[i + 1]; |
300 map.set(key, value); | 300 map.set(key, value); |
301 } | 301 } |
302 } else if (typeof $values === 'object') { | 302 } else if (typeof $values === 'object') { |
303 for (let key of $getOwnPropertyNames($values)) { | 303 for (let key of $getOwnPropertyNames($values)) { |
304 map.set(key, $values[key]); | 304 map.set(key, $values[key]); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
412 objectKey.push(name); | 412 objectKey.push(name); |
413 objectKey.push($obj[name]); | 413 objectKey.push($obj[name]); |
414 } | 414 } |
415 return $multiKeyPutIfAbsent($constants, objectKey, () => $obj); | 415 return $multiKeyPutIfAbsent($constants, objectKey, () => $obj); |
416 })()'''); | 416 })()'''); |
417 | 417 |
418 | 418 |
419 // The following are helpers for Object methods when the receiver | 419 // The following are helpers for Object methods when the receiver |
420 // may be null or primitive. These should only be generated by | 420 // may be null or primitive. These should only be generated by |
421 // the compiler. | 421 // the compiler. |
422 hashCode(obj) => JS('', '''(() => { | 422 hashCode(obj) { |
423 if ($obj == null) { | 423 if (obj == null) return 0; |
424 return 0; | 424 |
425 switch (JS('String', 'typeof #', obj)) { | |
426 case "number": | |
427 return JS('','# & 0x1FFFFFFF', obj); | |
428 case "boolean": | |
429 // From JSBool.hashCode, see comment there. | |
430 return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); | |
425 } | 431 } |
426 // TODO(vsm): What should we do for primitives and non-Dart objects? | 432 |
427 switch (typeof $obj) { | 433 var extension = getExtensionType(obj); |
428 case "number": | 434 if (extension != null) { |
429 case "boolean": | 435 return JS('', '#[dartx.hashCode]', obj); |
430 return $obj & 0x1FFFFFFF; | |
431 case "string": | |
432 // TODO(vsm): Call the JSString hashCode? | |
433 return $obj.length; | |
434 } | 436 } |
435 return $obj.hashCode; | 437 return JS('', '#.hashCode', obj); |
436 })()'''); | 438 } |
437 | 439 |
438 toString(obj) => JS('', '''(() => { | 440 @JSExportName('toString') |
439 if ($obj == null) { | 441 _toString(obj) { |
440 return "null"; | 442 if (obj == null) return "null"; |
443 | |
444 var extension = getExtensionType(obj); | |
445 if (extension != null) { | |
446 return JS('', '#[dartx.toString]()', obj); | |
441 } | 447 } |
442 return $obj.toString(); | 448 return JS('', '#.toString()', obj); |
443 })()'''); | 449 } |
444 | 450 |
445 noSuchMethod(obj, invocation) => JS('', '''(() => { | 451 // TODO(jmesserly): is the argument type verified statically? |
446 if ($obj == null) { | 452 noSuchMethod(obj, Invocation invocation) { |
447 $throwNoSuchMethod($obj, $invocation.memberName, | 453 if (obj == null) { |
448 $invocation.positionalArguments, $invocation.namedArguments); | 454 throw new NoSuchMethodError( |
455 null, | |
456 invocation.memberName, | |
457 invocation.positionalArguments, | |
458 invocation.namedArguments); | |
449 } | 459 } |
450 switch (typeof $obj) { | 460 // TODO(jmesserly): I don't think any extension types define nSM. If they |
451 case "number": | 461 // do we need to add a cast here. |
vsm
2016/05/09 20:55:56
Can we sanity check?
var extension = getExtension
Jennifer Messerly
2016/05/10 00:33:57
Not sure I follow that code example, but yes I wen
| |
452 case "boolean": | 462 return JS('', '#.noSuchMethod(#)', obj, invocation); |
453 case "string": | 463 } |
454 $throwNoSuchMethod($obj, $invocation.memberName, | 464 |
455 $invocation.positionalArguments, $invocation.namedArguments); | 465 runtimeType(obj) { |
466 // Handle primitives where the method isn't on the object. | |
467 var result = _checkPrimitiveType(obj); | |
468 if (result != null) return wrapType(result); | |
469 | |
470 // Delegate to the (possibly user-defined) method on the object. | |
471 var extension = getExtensionType(obj); | |
472 if (extension != null) { | |
473 return JS('', '#[dartx.runtimeType]', obj); | |
456 } | 474 } |
457 return $obj.noSuchMethod($invocation); | 475 return JS('', '#.runtimeType', obj); |
458 })()'''); | 476 } |
459 | 477 |
460 final JsIterator = JS('', ''' | 478 final JsIterator = JS('', ''' |
461 class JsIterator { | 479 class JsIterator { |
462 constructor(dartIterator) { | 480 constructor(dartIterator) { |
463 this.dartIterator = dartIterator; | 481 this.dartIterator = dartIterator; |
464 } | 482 } |
465 next() { | 483 next() { |
466 let i = this.dartIterator; | 484 let i = this.dartIterator; |
467 let done = !i.moveNext(); | 485 let done = !i.moveNext(); |
468 return { done: done, value: done ? void 0 : i.current }; | 486 return { done: done, value: done ? void 0 : i.current }; |
469 } | 487 } |
470 } | 488 } |
471 '''); | 489 '''); |
OLD | NEW |