| 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 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 bool hasSetter(type, name) => _hasSigEntry(type, _setterSig, name); | 384 bool hasSetter(type, name) => _hasSigEntry(type, _setterSig, name); |
| 385 bool hasField(type, name) => _hasSigEntry(type, _fieldSig, name); | 385 bool hasField(type, name) => _hasSigEntry(type, _fieldSig, name); |
| 386 | 386 |
| 387 final _extensionType = JS('', 'Symbol("extensionType")'); | 387 final _extensionType = JS('', 'Symbol("extensionType")'); |
| 388 | 388 |
| 389 /// This assumes that obj is not null | 389 /// This assumes that obj is not null |
| 390 getExtensionType(obj) => JS('', '#[#]', obj, _extensionType); | 390 getExtensionType(obj) => JS('', '#[#]', obj, _extensionType); |
| 391 | 391 |
| 392 final dartx = JS('', 'dartx'); | 392 final dartx = JS('', 'dartx'); |
| 393 | 393 |
| 394 getExtensionSymbol(name) { | |
| 395 var sym = JS('', 'dartx[#]', name); | |
| 396 if (sym == null) { | |
| 397 sym = JS('', 'Symbol("dartx." + #.toString())', name); | |
| 398 JS('', 'dartx[#] = #', name, sym); | |
| 399 } | |
| 400 return sym; | |
| 401 } | |
| 402 | |
| 403 defineExtensionNames(names) => | |
| 404 JS('', '#.forEach(#)', names, getExtensionSymbol); | |
| 405 | |
| 406 /// Install properties in prototype-first order. Properties / descriptors from | 394 /// Install properties in prototype-first order. Properties / descriptors from |
| 407 /// more specific types should overwrite ones from less specific types. | 395 /// more specific types should overwrite ones from less specific types. |
| 408 void _installProperties(jsProto, dartType, installedParent) { | 396 void _installProperties(jsProto, dartType, installedParent) { |
| 409 if (JS('bool', '# === #', dartType, Object)) { | 397 if (JS('bool', '# === #', dartType, Object)) { |
| 410 _installPropertiesForObject(jsProto); | 398 _installPropertiesForObject(jsProto); |
| 411 return; | 399 return; |
| 412 } | 400 } |
| 413 // If the extension methods of the parent have been installed on the parent | 401 // If the extension methods of the parent have been installed on the parent |
| 414 // of [jsProto], the methods will be available via prototype inheritance. | 402 // of [jsProto], the methods will be available via prototype inheritance. |
| 415 var dartSupertype = JS('', '#.__proto__', dartType); | 403 var dartSupertype = JS('', '#.__proto__', dartType); |
| 416 if (JS('bool', '# !== #', dartSupertype, installedParent)) { | 404 if (JS('bool', '# !== #', dartSupertype, installedParent)) { |
| 417 _installProperties(jsProto, dartSupertype, installedParent); | 405 _installProperties(jsProto, dartSupertype, installedParent); |
| 418 } | 406 } |
| 419 | 407 |
| 420 var dartProto = JS('', '#.prototype', dartType); | 408 var dartProto = JS('', '#.prototype', dartType); |
| 421 copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto)); | 409 copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto)); |
| 422 } | 410 } |
| 423 | 411 |
| 424 void _installPropertiesForObject(jsProto) { | 412 void _installPropertiesForObject(jsProto) { |
| 425 // core.Object members need to be copied from the non-symbol name to the | 413 // core.Object members need to be copied from the non-symbol name to the |
| 426 // symbol name. | 414 // symbol name. |
| 427 var coreObjProto = JS('', '#.prototype', Object); | 415 var coreObjProto = JS('', '#.prototype', Object); |
| 428 var names = getOwnPropertyNames(coreObjProto); | 416 var names = getOwnPropertyNames(coreObjProto); |
| 429 for (int i = 0; i < JS('int', '#.length', names); ++i) { | 417 for (int i = 0; i < JS('int', '#.length', names); ++i) { |
| 430 var name = JS('', '#[#]', names, i); | 418 var name = JS('', '#[#]', names, i); |
| 431 var desc = getOwnPropertyDescriptor(coreObjProto, name); | 419 var desc = getOwnPropertyDescriptor(coreObjProto, name); |
| 432 defineProperty(jsProto, getExtensionSymbol(name), desc); | 420 defineProperty(jsProto, JS('', '#.#', dartx, name), desc); |
| 433 } | 421 } |
| 434 } | 422 } |
| 435 | 423 |
| 436 final _extensionMap = JS('', 'new Map()'); | 424 final _extensionMap = JS('', 'new Map()'); |
| 437 | 425 |
| 438 _applyExtension(jsType, dartExtType) => JS('', '''(() => { | 426 _applyExtension(jsType, dartExtType) => JS('', '''(() => { |
| 439 // TODO(vsm): Not all registered js types are real. | 427 // TODO(vsm): Not all registered js types are real. |
| 440 if (!$jsType) return; | 428 if (!$jsType) return; |
| 441 | 429 |
| 442 let jsProto = $jsType.prototype; | 430 let jsProto = $jsType.prototype; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 494 /// MyType.prototype[dartx.remove] = MyType.prototype.remove; | 482 /// MyType.prototype[dartx.remove] = MyType.prototype.remove; |
| 495 /// | 483 /// |
| 496 // TODO(jmesserly): essentially this gives two names to the same method. | 484 // TODO(jmesserly): essentially this gives two names to the same method. |
| 497 // This benefit is roughly equivalent call performance either way, but the | 485 // This benefit is roughly equivalent call performance either way, but the |
| 498 // cost is we need to call defineExtensionMembers any time a subclass | 486 // cost is we need to call defineExtensionMembers any time a subclass |
| 499 // overrides one of these methods. | 487 // overrides one of these methods. |
| 500 defineExtensionMembers(type, methodNames) => JS('', '''(() => { | 488 defineExtensionMembers(type, methodNames) => JS('', '''(() => { |
| 501 let proto = $type.prototype; | 489 let proto = $type.prototype; |
| 502 for (let name of $methodNames) { | 490 for (let name of $methodNames) { |
| 503 let method = $getOwnPropertyDescriptor(proto, name); | 491 let method = $getOwnPropertyDescriptor(proto, name); |
| 504 $defineProperty(proto, $getExtensionSymbol(name), method); | 492 $defineProperty(proto, $dartx[name], method); |
| 505 } | 493 } |
| 506 // Ensure the signature is available too. | 494 // Ensure the signature is available too. |
| 507 // TODO(jmesserly): not sure if we can do this in a cleaner way. Essentially | 495 // TODO(jmesserly): not sure if we can do this in a cleaner way. Essentially |
| 508 // we need to copy the signature (and in the future, other data like | 496 // we need to copy the signature (and in the future, other data like |
| 509 // annotations) any time we copy a method as part of our metaprogramming. | 497 // annotations) any time we copy a method as part of our metaprogramming. |
| 510 // It might be more friendly to JS metaprogramming if we include this info | 498 // It might be more friendly to JS metaprogramming if we include this info |
| 511 // on the function. | 499 // on the function. |
| 512 | 500 |
| 513 function upgradeSig(sigF) { | 501 function upgradeSig(sigF) { |
| 514 let originalSigDesc = $getOwnPropertyDescriptor($type, sigF); | 502 let originalSigDesc = $getOwnPropertyDescriptor($type, sigF); |
| 515 if (originalSigDesc === void 0) return; | 503 if (originalSigDesc === void 0) return; |
| 516 let originalSigFn = originalSigDesc.get; | 504 let originalSigFn = originalSigDesc.get; |
| 517 $defineMemoizedGetter(type, sigF, function() { | 505 $defineMemoizedGetter(type, sigF, function() { |
| 518 let sig = originalSigFn(); | 506 let sig = originalSigFn(); |
| 519 let propertyNames = Object.getOwnPropertyNames(sig); | 507 let propertyNames = Object.getOwnPropertyNames(sig); |
| 520 for (let name of methodNames) { | 508 for (let name of methodNames) { |
| 521 if (name in sig) { | 509 if (name in sig) { |
| 522 sig[$getExtensionSymbol(name)] = sig[name]; | 510 sig[$dartx[name]] = sig[name]; |
| 523 } | 511 } |
| 524 } | 512 } |
| 525 return sig; | 513 return sig; |
| 526 }); | 514 }); |
| 527 }; | 515 }; |
| 528 upgradeSig($_methodSig); | 516 upgradeSig($_methodSig); |
| 529 upgradeSig($_fieldSig); | 517 upgradeSig($_fieldSig); |
| 530 upgradeSig($_getterSig); | 518 upgradeSig($_getterSig); |
| 531 upgradeSig($_setterSig); | 519 upgradeSig($_setterSig); |
| 532 })()'''); | 520 })()'''); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 final isList = JS('', 'Symbol("_is_List")'); | 606 final isList = JS('', 'Symbol("_is_List")'); |
| 619 | 607 |
| 620 /// The well known symbol for testing `is Map` | 608 /// The well known symbol for testing `is Map` |
| 621 final isMap = JS('', 'Symbol("_is_Map")'); | 609 final isMap = JS('', 'Symbol("_is_Map")'); |
| 622 | 610 |
| 623 /// The well known symbol for testing `is Stream` | 611 /// The well known symbol for testing `is Stream` |
| 624 final isStream = JS('', 'Symbol("_is_Stream")'); | 612 final isStream = JS('', 'Symbol("_is_Stream")'); |
| 625 | 613 |
| 626 /// The well known symbol for testing `is StreamSubscription` | 614 /// The well known symbol for testing `is StreamSubscription` |
| 627 final isStreamSubscription = JS('', 'Symbol("_is_StreamSubscription")'); | 615 final isStreamSubscription = JS('', 'Symbol("_is_StreamSubscription")'); |
| OLD | NEW |