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 the operations that define and manipulate Dart | 5 /// This library defines the operations that define and manipulate Dart |
6 /// classes. Included in this are: | 6 /// classes. Included in this are: |
7 /// - Generics | 7 /// - Generics |
8 /// - Class metadata | 8 /// - Class metadata |
9 /// - Extension methods | 9 /// - Extension methods |
10 /// | 10 /// |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
403 } | 403 } |
404 return sym; | 404 return sym; |
405 } | 405 } |
406 | 406 |
407 defineExtensionNames(names) => | 407 defineExtensionNames(names) => |
408 JS('', '#.forEach(#)', names, getExtensionSymbol); | 408 JS('', '#.forEach(#)', names, getExtensionSymbol); |
409 | 409 |
410 /// Install properties in prototype-first order. Properties / descriptors from | 410 /// Install properties in prototype-first order. Properties / descriptors from |
411 /// more specific types should overwrite ones from less specific types. | 411 /// more specific types should overwrite ones from less specific types. |
412 void _installProperties(jsProto, dartType, installedParent) { | 412 void _installProperties(jsProto, dartType, installedParent) { |
413 if (JS('bool', '# === #', dartType, Object)) { | 413 // Extension types should bottom out at core.Object. The one exception |
414 // is JSArray, which we rewire to the native Array type. | |
Jennifer Messerly
2017/07/14 19:38:08
hmmm wait I don't understand the JSArray comment.
| |
415 if (JS('bool', '# === # || # === #.Object', dartType, Object, dartType, | |
416 global_)) { | |
414 _installPropertiesForObject(jsProto); | 417 _installPropertiesForObject(jsProto); |
415 return; | 418 return; |
416 } | 419 } |
417 // If the extension methods of the parent have been installed on the parent | 420 // If the extension methods of the parent have been installed on the parent |
418 // of [jsProto], the methods will be available via prototype inheritance. | 421 // of [jsProto], the methods will be available via prototype inheritance. |
419 var dartSupertype = JS('', '#.__proto__', dartType); | 422 var dartSupertype = JS('', '#.__proto__', dartType); |
420 if (JS('bool', '# !== #', dartSupertype, installedParent)) { | 423 if (JS('bool', '# !== #', dartSupertype, installedParent)) { |
421 _installProperties(jsProto, dartSupertype, installedParent); | 424 _installProperties(jsProto, dartSupertype, installedParent); |
422 } | 425 } |
423 | 426 |
424 var dartProto = JS('', '#.prototype', dartType); | 427 var dartProto = JS('', '#.prototype', dartType); |
425 copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto)); | 428 copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto)); |
426 } | 429 } |
427 | 430 |
428 void _installPropertiesForObject(jsProto) { | 431 void _installPropertiesForObject(jsProto) { |
429 // core.Object members need to be copied from the non-symbol name to the | 432 // core.Object members need to be copied from the non-symbol name to the |
430 // symbol name. | 433 // symbol name. |
431 var coreObjProto = JS('', '#.prototype', Object); | 434 var coreObjProto = JS('', '#.prototype', Object); |
432 var names = getOwnPropertyNames(coreObjProto); | 435 var names = getOwnPropertyNames(coreObjProto); |
433 for (int i = 0; i < JS('int', '#.length', names); ++i) { | 436 for (int i = 0; i < JS('int', '#.length', names); ++i) { |
434 var name = JS('', '#[#]', names, i); | 437 var name = JS('', '#[#]', names, i); |
435 var desc = getOwnPropertyDescriptor(coreObjProto, name); | 438 var desc = getOwnPropertyDescriptor(coreObjProto, name); |
436 defineProperty(jsProto, getExtensionSymbol(name), desc); | 439 defineProperty(jsProto, getExtensionSymbol(name), desc); |
437 } | 440 } |
438 } | 441 } |
439 | 442 |
440 /// Copy symbols from the prototype of the source to destination. | 443 var _extensionMap; |
Jennifer Messerly
2017/07/14 19:38:08
this can be eager initialized:
final _extensi
vsm
2017/07/19 15:59:02
Done.
| |
441 /// These are the only properties safe to copy onto an existing public | 444 |
442 /// JavaScript class. | 445 _cacheExtension(name, dartExtType) { |
443 registerExtension(jsType, dartExtType) => JS( | 446 if (_extensionMap == null) _extensionMap = JS('', 'new Map()'); |
447 JS('', '#.set(#, #)', _extensionMap, name, dartExtType); | |
448 } | |
449 | |
450 _applyExtension(jsType, dartExtType) => JS( | |
444 '', | 451 '', |
445 '''(() => { | 452 '''(() => { |
446 // TODO(vsm): Not all registered js types are real. | 453 // TODO(vsm): Not all registered js types are real. |
447 if (!jsType) return; | 454 if (!jsType) return; |
448 | 455 |
456 let extProto = $dartExtType.prototype; | |
Jennifer Messerly
2017/07/14 19:38:08
this line is unused. I'm guessing it was a merge c
vsm
2017/07/19 15:59:02
Done.
| |
449 let jsProto = $jsType.prototype; | 457 let jsProto = $jsType.prototype; |
450 | 458 |
451 // TODO(vsm): This sometimes doesn't exist on FF. These types will be | 459 // TODO(vsm): This sometimes doesn't exist on FF. These types will be |
452 // broken. | 460 // broken. |
453 if (!jsProto) return; | 461 if (!jsProto) return; |
454 | 462 |
455 $_installProperties(jsProto, $dartExtType, jsProto[$_extensionType]); | 463 $_installProperties(jsProto, $dartExtType, jsProto[$_extensionType]); |
456 | 464 |
457 // Mark the JS type's instances so we can easily check for extensions. | 465 // Mark the JS type's instances so we can easily check for extensions. |
458 jsProto[$_extensionType] = $dartExtType; | 466 jsProto[$_extensionType] = $dartExtType; |
459 | 467 |
460 function updateSig(sigF) { | 468 function updateSig(sigF) { |
461 let originalDesc = $getOwnPropertyDescriptor($dartExtType, sigF); | 469 let originalDesc = $getOwnPropertyDescriptor($dartExtType, sigF); |
462 if (originalDesc === void 0) return; | 470 if (originalDesc === void 0) return; |
463 let originalSigFn = originalDesc.get; | 471 let originalSigFn = originalDesc.get; |
464 $assert_(originalSigFn); | 472 $assert_(originalSigFn); |
465 $defineMemoizedGetter($jsType, sigF, originalSigFn); | 473 $defineMemoizedGetter(jsType, sigF, originalSigFn); |
466 } | 474 } |
467 updateSig($_methodSig); | 475 updateSig($_methodSig); |
468 updateSig($_fieldSig); | 476 updateSig($_fieldSig); |
469 updateSig($_getterSig); | 477 updateSig($_getterSig); |
470 updateSig($_setterSig); | 478 updateSig($_setterSig); |
471 })()'''); | 479 })()'''); |
472 | 480 |
481 /// Apply all registered extensions to a window. This is intended for | |
482 /// different frames, where registrations need to be reapplied. | |
483 applyAllExtensions(global) { | |
484 JS('', '#.forEach((dartExtType, name) => #(#[name], dartExtType))', | |
485 _extensionMap, _applyExtension, global); | |
486 } | |
487 | |
488 /// Copy symbols from the prototype of the source to destination. | |
489 /// These are the only properties safe to copy onto an existing public | |
490 /// JavaScript class. | |
491 registerExtension(name, dartExtType) { | |
492 _cacheExtension(name, dartExtType); | |
Jennifer Messerly
2017/07/14 19:38:08
based on suggestion above this is a 1-liner now an
vsm
2017/07/19 15:59:01
Done.
| |
493 var jsType = JS('', '#[#]', global_, name); | |
494 _applyExtension(jsType, dartExtType); | |
495 } | |
496 | |
473 /// | 497 /// |
474 /// Mark a concrete type as implementing extension methods. | 498 /// Mark a concrete type as implementing extension methods. |
475 /// For example: `class MyIter implements Iterable`. | 499 /// For example: `class MyIter implements Iterable`. |
476 /// | 500 /// |
477 /// This takes a list of names, which are the extension methods implemented. | 501 /// This takes a list of names, which are the extension methods implemented. |
478 /// It will add a forwarder, so the extension method name redirects to the | 502 /// It will add a forwarder, so the extension method name redirects to the |
479 /// normal Dart method name. For example: | 503 /// normal Dart method name. For example: |
480 /// | 504 /// |
481 /// defineExtensionMembers(MyType, ['add', 'remove']); | 505 /// defineExtensionMembers(MyType, ['add', 'remove']); |
482 /// | 506 /// |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
552 | 576 |
553 defineEnumValues(enumClass, names) { | 577 defineEnumValues(enumClass, names) { |
554 var values = []; | 578 var values = []; |
555 for (var i = 0; i < JS('int', '#.length', names); i++) { | 579 for (var i = 0; i < JS('int', '#.length', names); i++) { |
556 var value = const_(JS('', 'new #.new(#)', enumClass, i)); | 580 var value = const_(JS('', 'new #.new(#)', enumClass, i)); |
557 JS('', '#.push(#)', values, value); | 581 JS('', '#.push(#)', values, value); |
558 defineValue(enumClass, JS('', '#[#]', names, i), value); | 582 defineValue(enumClass, JS('', '#[#]', names, i), value); |
559 } | 583 } |
560 JS('', '#.values = #', enumClass, constList(values, enumClass)); | 584 JS('', '#.values = #', enumClass, constList(values, enumClass)); |
561 } | 585 } |
OLD | NEW |