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 return $name in sigObj; | 384 return $name in sigObj; |
385 })()'''); | 385 })()'''); |
386 | 386 |
387 bool hasMethod(type, name) => _hasSigEntry(type, _methodSig, name); | 387 bool hasMethod(type, name) => _hasSigEntry(type, _methodSig, name); |
388 bool hasGetter(type, name) => _hasSigEntry(type, _getterSig, name); | 388 bool hasGetter(type, name) => _hasSigEntry(type, _getterSig, name); |
389 bool hasSetter(type, name) => _hasSigEntry(type, _setterSig, name); | 389 bool hasSetter(type, name) => _hasSigEntry(type, _setterSig, name); |
390 bool hasField(type, name) => _hasSigEntry(type, _fieldSig, name); | 390 bool hasField(type, name) => _hasSigEntry(type, _fieldSig, name); |
391 | 391 |
392 final _extensionType = JS('', 'Symbol("extensionType")'); | 392 final _extensionType = JS('', 'Symbol("extensionType")'); |
393 | 393 |
394 getExtensionType(obj) => JS('', '#[#]', obj, _extensionType); | 394 getExtensionType(obj) { |
| 395 var result = JS('', '#[#]', obj, _extensionType); |
| 396 if (result != null) return result; |
| 397 |
| 398 if (JS('bool', 'typeof # != "object" || # instanceof #.Object', obj, obj, |
| 399 global_)) { |
| 400 return null; |
| 401 } |
| 402 |
| 403 // This is an object from another frame. Check to see if we have registered |
| 404 // an extension in case this is a DOM/native type. |
| 405 var jsType = JS('', '#.constructor', obj); |
| 406 var tag = JS('', '#.name', jsType); |
| 407 if (JS('bool', '#.has(#)', _extMap, tag)) { |
| 408 var jsProto = JS('', '#.__proto__', obj); |
| 409 var dartType = JS('', '#.get(#)', _extMap, tag); |
| 410 _installExtension(jsType, jsProto, dartType); |
| 411 return dartType; |
| 412 } |
| 413 |
| 414 return null; |
| 415 } |
395 | 416 |
396 final dartx = JS('', 'dartx'); | 417 final dartx = JS('', 'dartx'); |
397 | 418 |
398 getExtensionSymbol(name) { | 419 getExtensionSymbol(name) { |
399 var sym = JS('', 'dartx[#]', name); | 420 var sym = JS('', 'dartx[#]', name); |
400 if (sym == null) { | 421 if (sym == null) { |
401 sym = JS('', 'Symbol("dartx." + #.toString())', name); | 422 sym = JS('', 'Symbol("dartx." + #.toString())', name); |
402 JS('', 'dartx[#] = #', name, sym); | 423 JS('', 'dartx[#] = #', name, sym); |
403 } | 424 } |
404 return sym; | 425 return sym; |
(...skipping 25 matching lines...) Expand all Loading... |
430 // symbol name. | 451 // symbol name. |
431 var coreObjProto = JS('', '#.prototype', Object); | 452 var coreObjProto = JS('', '#.prototype', Object); |
432 var names = getOwnPropertyNames(coreObjProto); | 453 var names = getOwnPropertyNames(coreObjProto); |
433 for (int i = 0; i < JS('int', '#.length', names); ++i) { | 454 for (int i = 0; i < JS('int', '#.length', names); ++i) { |
434 var name = JS('', '#[#]', names, i); | 455 var name = JS('', '#[#]', names, i); |
435 var desc = getOwnPropertyDescriptor(coreObjProto, name); | 456 var desc = getOwnPropertyDescriptor(coreObjProto, name); |
436 defineProperty(jsProto, getExtensionSymbol(name), desc); | 457 defineProperty(jsProto, getExtensionSymbol(name), desc); |
437 } | 458 } |
438 } | 459 } |
439 | 460 |
| 461 var _extMap; |
| 462 |
| 463 _cacheExtension(jsProto, dartType) { |
| 464 if (_extMap == null) _extMap = JS('', 'new Map()'); |
| 465 // TODO(vsm): Make this work on non-Chrome browsers. |
| 466 var tag = JS('', '#.constructor.name', jsProto); |
| 467 JS('', '#.set(#, #)', _extMap, tag, dartType); |
| 468 } |
| 469 |
440 /// Copy symbols from the prototype of the source to destination. | 470 /// Copy symbols from the prototype of the source to destination. |
441 /// These are the only properties safe to copy onto an existing public | 471 /// These are the only properties safe to copy onto an existing public |
442 /// JavaScript class. | 472 /// JavaScript class. |
443 registerExtension(jsType, dartExtType) => JS( | 473 registerExtension(jsType, dartExtType) => JS( |
444 '', | 474 '', |
445 '''(() => { | 475 '''(() => { |
446 // TODO(vsm): Not all registered js types are real. | 476 // TODO(vsm): Not all registered js types are real. |
447 if (!jsType) return; | 477 if (!jsType) return; |
448 | 478 |
449 let jsProto = $jsType.prototype; | 479 let jsProto = $jsType.prototype; |
450 | 480 |
451 // TODO(vsm): This sometimes doesn't exist on FF. These types will be | 481 // TODO(vsm): This sometimes doesn't exist on FF. These types will be |
452 // broken. | 482 // broken. |
453 if (!jsProto) return; | 483 if (!jsProto) return; |
454 | 484 |
455 $_installProperties(jsProto, $dartExtType, jsProto[$_extensionType]); | 485 $_cacheExtension(jsProto, $dartExtType); |
456 | 486 |
457 // Mark the JS type's instances so we can easily check for extensions. | 487 // Mark the JS type's instances so we can easily check for extensions. |
458 jsProto[$_extensionType] = $dartExtType; | 488 $_installExtension(jsType, jsProto, dartExtType); |
| 489 })()'''); |
459 | 490 |
| 491 _installExtension(jsType, jsProto, dartType) => JS( |
| 492 '', |
| 493 '''(() => { |
| 494 $_installProperties(jsProto, $dartType, jsProto[$_extensionType]); |
| 495 |
| 496 // Mark the JS type's instances so we can easily check for extensions. |
| 497 jsProto[$_extensionType] = $dartType; |
460 function updateSig(sigF) { | 498 function updateSig(sigF) { |
461 let originalDesc = $getOwnPropertyDescriptor($dartExtType, sigF); | 499 let originalDesc = $getOwnPropertyDescriptor($dartType, sigF); |
462 if (originalDesc === void 0) return; | 500 if (originalDesc === void 0) return; |
463 let originalSigFn = originalDesc.get; | 501 let originalSigFn = originalDesc.get; |
464 $assert_(originalSigFn); | 502 $assert_(originalSigFn); |
465 $defineMemoizedGetter($jsType, sigF, originalSigFn); | 503 $defineMemoizedGetter($jsType, sigF, originalSigFn); |
466 } | 504 } |
467 updateSig($_methodSig); | 505 updateSig($_methodSig); |
468 updateSig($_fieldSig); | 506 updateSig($_fieldSig); |
469 updateSig($_getterSig); | 507 updateSig($_getterSig); |
470 updateSig($_setterSig); | 508 updateSig($_setterSig); |
471 })()'''); | 509 })()'''); |
472 | 510 |
473 /// | 511 /// |
474 /// Mark a concrete type as implementing extension methods. | 512 /// Mark a concrete type as implementing extension methods. |
475 /// For example: `class MyIter implements Iterable`. | 513 /// For example: `class MyIter implements Iterable`. |
476 /// | 514 /// |
477 /// This takes a list of names, which are the extension methods implemented. | 515 /// 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 | 516 /// It will add a forwarder, so the extension method name redirects to the |
479 /// normal Dart method name. For example: | 517 /// normal Dart method name. For example: |
480 /// | 518 /// |
481 /// defineExtensionMembers(MyType, ['add', 'remove']); | 519 /// defineExtensionMembers(MyType, ['add', 'remove']); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 | 590 |
553 defineEnumValues(enumClass, names) { | 591 defineEnumValues(enumClass, names) { |
554 var values = []; | 592 var values = []; |
555 for (var i = 0; i < JS('int', '#.length', names); i++) { | 593 for (var i = 0; i < JS('int', '#.length', names); i++) { |
556 var value = const_(JS('', 'new #.new(#)', enumClass, i)); | 594 var value = const_(JS('', 'new #.new(#)', enumClass, i)); |
557 JS('', '#.push(#)', values, value); | 595 JS('', '#.push(#)', values, value); |
558 defineValue(enumClass, JS('', '#[#]', names, i), value); | 596 defineValue(enumClass, JS('', '#[#]', names, i), value); |
559 } | 597 } |
560 JS('', '#.values = #', enumClass, constList(values, enumClass)); | 598 JS('', '#.values = #', enumClass, constList(values, enumClass)); |
561 } | 599 } |
OLD | NEW |