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 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 JS('', 'dartx[#] = #', name, sym); | 402 JS('', 'dartx[#] = #', name, sym); |
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, extProto) { | 412 void _installProperties(jsProto, dartType, installedParent) { |
413 // This relies on the Dart type literal evaluating to the JavaScript | 413 if (JS('bool', '# === #', dartType, Object)) { |
414 // constructor. | 414 _installPropertiesForObject(jsProto); |
415 var coreObjProto = JS('', '#.prototype', Object); | 415 return; |
| 416 } |
| 417 // If the extension methods of the parent have been installed on the parent |
| 418 // of [jsProto], the methods will be available via prototype inheritance. |
| 419 var dartSupertype = JS('', '#.__proto__', dartType); |
| 420 if (JS('bool', '# !== #', dartSupertype, installedParent)) { |
| 421 _installProperties(jsProto, dartSupertype, installedParent); |
| 422 } |
416 | 423 |
417 var parentsExtension = JS('', '(#.__proto__)[#]', jsProto, _extensionType); | 424 var dartProto = JS('', '#.prototype', dartType); |
418 var installedParent = | 425 copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto)); |
419 JS('', '# && #.prototype', parentsExtension, parentsExtension); | |
420 | |
421 _installProperties2(jsProto, extProto, coreObjProto, installedParent); | |
422 } | 426 } |
423 | 427 |
424 void _installProperties2(jsProto, extProto, coreObjProto, installedParent) { | 428 void _installPropertiesForObject(jsProto) { |
425 if (JS('bool', '# === #', extProto, coreObjProto)) { | |
426 _installPropertiesForObject(jsProto, coreObjProto); | |
427 return; | |
428 } | |
429 if (JS('bool', '# !== #', jsProto, extProto)) { | |
430 var extParent = JS('', '#.__proto__', extProto); | |
431 | |
432 // If the extension methods of the parent have been installed on the parent | |
433 // of [jsProto], the methods will be available via prototype inheritance. | |
434 | |
435 if (JS('bool', '# !== #', installedParent, extParent)) { | |
436 _installProperties2(jsProto, extParent, coreObjProto, installedParent); | |
437 } | |
438 } | |
439 copyTheseProperties(jsProto, extProto, getOwnPropertySymbols(extProto)); | |
440 } | |
441 | |
442 void _installPropertiesForObject(jsProto, coreObjProto) { | |
443 // core.Object members need to be copied from the non-symbol name to the | 429 // core.Object members need to be copied from the non-symbol name to the |
444 // symbol name. | 430 // symbol name. |
| 431 var coreObjProto = JS('', '#.prototype', Object); |
445 var names = getOwnPropertyNames(coreObjProto); | 432 var names = getOwnPropertyNames(coreObjProto); |
446 for (int i = 0; i < JS('int', '#.length', names); ++i) { | 433 for (int i = 0; i < JS('int', '#.length', names); ++i) { |
447 var name = JS('', '#[#]', names, i); | 434 var name = JS('', '#[#]', names, i); |
448 var desc = getOwnPropertyDescriptor(coreObjProto, name); | 435 var desc = getOwnPropertyDescriptor(coreObjProto, name); |
449 defineProperty(jsProto, getExtensionSymbol(name), desc); | 436 defineProperty(jsProto, getExtensionSymbol(name), desc); |
450 } | 437 } |
451 return; | |
452 } | 438 } |
453 | 439 |
454 /// Copy symbols from the prototype of the source to destination. | 440 /// Copy symbols from the prototype of the source to destination. |
455 /// These are the only properties safe to copy onto an existing public | 441 /// These are the only properties safe to copy onto an existing public |
456 /// JavaScript class. | 442 /// JavaScript class. |
457 registerExtension(jsType, dartExtType) => JS( | 443 registerExtension(jsType, dartExtType) => JS( |
458 '', | 444 '', |
459 '''(() => { | 445 '''(() => { |
460 // TODO(vsm): Not all registered js types are real. | 446 // TODO(vsm): Not all registered js types are real. |
461 if (!jsType) return; | 447 if (!jsType) return; |
462 | 448 |
463 let extProto = $dartExtType.prototype; | |
464 let jsProto = $jsType.prototype; | 449 let jsProto = $jsType.prototype; |
465 | 450 |
466 // TODO(vsm): This sometimes doesn't exist on FF. These types will be | 451 // TODO(vsm): This sometimes doesn't exist on FF. These types will be |
467 // broken. | 452 // broken. |
468 if (!jsProto) return; | 453 if (!jsProto) return; |
469 | 454 |
| 455 $_installProperties(jsProto, $dartExtType, jsProto[$_extensionType]); |
| 456 |
470 // Mark the JS type's instances so we can easily check for extensions. | 457 // Mark the JS type's instances so we can easily check for extensions. |
471 jsProto[$_extensionType] = $dartExtType; | 458 jsProto[$_extensionType] = $dartExtType; |
472 $_installProperties(jsProto, extProto); | 459 |
473 function updateSig(sigF) { | 460 function updateSig(sigF) { |
474 let originalDesc = $getOwnPropertyDescriptor($dartExtType, sigF); | 461 let originalDesc = $getOwnPropertyDescriptor($dartExtType, sigF); |
475 if (originalDesc === void 0) return; | 462 if (originalDesc === void 0) return; |
476 let originalSigFn = originalDesc.get; | 463 let originalSigFn = originalDesc.get; |
477 $assert_(originalSigFn); | 464 $assert_(originalSigFn); |
478 $defineMemoizedGetter($jsType, sigF, originalSigFn); | 465 $defineMemoizedGetter($jsType, sigF, originalSigFn); |
479 } | 466 } |
480 updateSig($_methodSig); | 467 updateSig($_methodSig); |
481 updateSig($_fieldSig); | 468 updateSig($_fieldSig); |
482 updateSig($_getterSig); | 469 updateSig($_getterSig); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 })()'''); | 526 })()'''); |
540 | 527 |
541 /// Sets the type of `obj` to be `type` | 528 /// Sets the type of `obj` to be `type` |
542 setType(obj, type) { | 529 setType(obj, type) { |
543 JS('', '#.__proto__ = #.prototype', obj, type); | 530 JS('', '#.__proto__ = #.prototype', obj, type); |
544 return obj; | 531 return obj; |
545 } | 532 } |
546 | 533 |
547 /// Sets the element type of a list literal. | 534 /// Sets the element type of a list literal. |
548 list(obj, elementType) => | 535 list(obj, elementType) => |
549 JS('', '$setType($obj, ${getGenericClass(JSArray)}($elementType))'); | 536 setType(obj, JS('', '#(#)', getGenericClass(JSArray), elementType)); |
550 | 537 |
551 /// Link the extension to the type it's extending as a base class. | 538 /// Link the extension to the type it's extending as a base class. |
552 setBaseClass(derived, base) { | 539 setBaseClass(derived, base) { |
553 JS('', '#.prototype.__proto__ = #.prototype', derived, base); | 540 JS('', '#.prototype.__proto__ = #.prototype', derived, base); |
554 // We use __proto__ to track the superclass hierarchy (see isSubtype). | 541 // We use __proto__ to track the superclass hierarchy (see isSubtype). |
555 JS('', '#.__proto__ = #', derived, base); | 542 JS('', '#.__proto__ = #', derived, base); |
556 } | 543 } |
557 | 544 |
558 /// Like [setBaseClass] but for generic extension types, e.g. `JSArray<E>` | 545 /// Like [setBaseClass], but for generic extension types such as `JSArray<E>`. |
559 setExtensionBaseClass(derived, base) { | 546 setExtensionBaseClass(dartType, jsType) { |
560 // Mark the generic type as an extension type and link the prototype objects | 547 // Mark the generic type as an extension type and link the prototype objects. |
561 return JS( | 548 var dartProto = JS('', '#.prototype', dartType); |
562 '', | 549 JS('', '#[#] = #', dartProto, _extensionType, dartType); |
563 '''(() => { | 550 JS('', '#.__proto__ = #.prototype', dartProto, jsType); |
564 if ($base) { | |
565 $derived.prototype[$_extensionType] = $derived; | |
566 $derived.prototype.__proto__ = $base.prototype | |
567 } | |
568 })()'''); | |
569 } | 551 } |
570 | 552 |
571 defineEnumValues(enumClass, names) { | 553 defineEnumValues(enumClass, names) { |
572 var values = []; | 554 var values = []; |
573 for (var i = 0; i < JS('int', '#.length', names); i++) { | 555 for (var i = 0; i < JS('int', '#.length', names); i++) { |
574 var value = const_(JS('', 'new #.new(#)', enumClass, i)); | 556 var value = const_(JS('', 'new #.new(#)', enumClass, i)); |
575 JS('', '#.push(#)', values, value); | 557 JS('', '#.push(#)', values, value); |
576 defineValue(enumClass, JS('', '#[#]', names, i), value); | 558 defineValue(enumClass, JS('', '#[#]', names, i), value); |
577 } | 559 } |
578 JS('', '#.values = #', enumClass, constList(values, enumClass)); | 560 JS('', '#.values = #', enumClass, constList(values, enumClass)); |
579 } | 561 } |
OLD | NEW |