Chromium Code Reviews| 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 library dev_compiler.src.codegen.js_codegen; | 5 library dev_compiler.src.codegen.js_codegen; |
| 6 | 6 |
| 7 import 'dart:collection' show HashSet, HashMap; | 7 import 'dart:collection' show HashSet, HashMap; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| (...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 var isObject = type.isObject; | 566 var isObject = type.isObject; |
| 567 var name = node.name.name; | 567 var name = node.name.name; |
| 568 | 568 |
| 569 // Iff no constructor is specified for a class C, it implicitly has a | 569 // Iff no constructor is specified for a class C, it implicitly has a |
| 570 // default constructor `C() : super() {}`, unless C is class Object. | 570 // default constructor `C() : super() {}`, unless C is class Object. |
| 571 var jsMethods = <JS.Method>[]; | 571 var jsMethods = <JS.Method>[]; |
| 572 if (ctors.isEmpty && !isObject) { | 572 if (ctors.isEmpty && !isObject) { |
| 573 jsMethods.add(_emitImplicitConstructor(node, name, fields)); | 573 jsMethods.add(_emitImplicitConstructor(node, name, fields)); |
| 574 } | 574 } |
| 575 | 575 |
| 576 for (var member in node.members) { | 576 bool hasJsPeer = getAnnotationValue(node, _isJsPeerInterface) != null; |
| 577 if (member is ConstructorDeclaration) { | 577 |
| 578 jsMethods.add(_emitConstructor(member, name, fields, isObject)); | 578 bool hasIterator = false; |
| 579 } else if (member is MethodDeclaration) { | 579 for (var m in node.members) { |
| 580 jsMethods.add(_emitMethodDeclaration(type, member)); | 580 if (m is ConstructorDeclaration) { |
| 581 jsMethods.add(_emitConstructor(m, name, fields, isObject)); | |
| 582 } else if (m is MethodDeclaration) { | |
| 583 jsMethods.add(_emitMethodDeclaration(type, m)); | |
| 584 | |
| 585 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | |
| 586 hasIterator = true; | |
| 587 jsMethods.add(_emitIterable(type)); | |
|
vsm
2015/05/05 14:19:28
Should we check the return type of iterator here?
Jennifer Messerly
2015/05/05 15:38:25
First off, just confirming: most of this is the jo
| |
| 588 } | |
| 581 } | 589 } |
| 582 } | 590 } |
| 583 | 591 |
| 584 // Support for adapting dart:core Iterator/Iterable to ES6 versions. | 592 // If the type doesn't have an `iterator`, but claims to implement Iterable, |
| 585 // This lets them use for-of loops transparently. | 593 // we inject the adaptor method here, as it's less code size to put the |
| 586 // https://github.com/lukehoban/es6features#iterators--forof | 594 // helper on a parent class. This pattern is common in the core libraries |
| 587 if (element.library.isDartCore && element.name == 'Iterable') { | 595 // (e.g. IterableMixin<E> and IterableBase<E>). |
| 588 JS.Fun body = js.call('''function() { | 596 // |
| 589 var iterator = this.iterator; | 597 // (We could do this same optimization for any interface with an `iterator` |
| 590 return { | 598 // method, but that's more expensive to check for, so it doesn't seem worth |
| 591 next() { | 599 // it. The above case for an explicit `iterator` method will catch those.) |
| 592 var done = iterator.moveNext(); | 600 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
| 593 return { done: done, current: done ? void 0 : iterator.current }; | 601 jsMethods.add(_emitIterable(type)); |
| 594 } | |
| 595 }; | |
| 596 }'''); | |
| 597 jsMethods.add(new JS.Method(js.call('$_SYMBOL.iterator'), body)); | |
| 598 } | 602 } |
| 603 | |
| 599 return jsMethods.where((m) => m != null).toList(growable: false); | 604 return jsMethods.where((m) => m != null).toList(growable: false); |
| 600 } | 605 } |
| 601 | 606 |
| 607 bool _implementsIterable(InterfaceType t) => | |
| 608 t.interfaces.any((i) => i.element.type == types.iterableType); | |
| 609 | |
| 610 /// Support for adapting dart:core Iterable to ES6 versions. | |
| 611 /// | |
| 612 /// This lets them use for-of loops transparently: | |
| 613 /// <https://github.com/lukehoban/es6features#iterators--forof> | |
| 614 /// | |
| 615 /// This will return `null` if the adapter was already added on a super type, | |
| 616 /// otherwise it returns the adapter code. | |
| 617 // TODO(jmesserly): should we adapt `Iterator` too? | |
| 618 JS.Method _emitIterable(InterfaceType t) { | |
| 619 // If a parent had an `iterator` (concrete or abstract) or implements | |
| 620 // Iterable, we know the adapter is already there, so we can skip it as a | |
| 621 // simple code size optimization. | |
| 622 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); | |
| 623 if (parent != null) return null; | |
| 624 parent = findSupertype(t, _implementsIterable); | |
| 625 if (parent != null) return null; | |
| 626 | |
| 627 // Otherwise, emit the adapter method, which wraps the Dart iterator in | |
| 628 // an ES6 iterator. | |
| 629 return new JS.Method(js.call('$_SYMBOL.iterator'), js.call( | |
| 630 'function() { return new dart.JsIterator(this.#); }', | |
| 631 [_emitMemberName('iterator', type: t)])); | |
| 632 } | |
| 633 | |
| 602 /// Emit class members that need to come after the class declaration, such | 634 /// Emit class members that need to come after the class declaration, such |
| 603 /// as static fields. See [_emitClassMethods] for things that are emitted | 635 /// as static fields. See [_emitClassMethods] for things that are emitted |
| 604 /// inside the ES6 `class { ... }` node. | 636 /// inside the ES6 `class { ... }` node. |
| 605 JS.Statement _finishClassMembers(ClassElement classElem, | 637 JS.Statement _finishClassMembers(ClassElement classElem, |
| 606 JS.ClassExpression cls, List<ConstructorDeclaration> ctors, | 638 JS.ClassExpression cls, List<ConstructorDeclaration> ctors, |
| 607 List<FieldDeclaration> fields, List<FieldDeclaration> staticFields, | 639 List<FieldDeclaration> fields, List<FieldDeclaration> staticFields, |
| 608 String jsPeerName) { | 640 String jsPeerName) { |
| 609 var name = classElem.name; | 641 var name = classElem.name; |
| 610 var body = <JS.Statement>[]; | 642 var body = <JS.Statement>[]; |
| 611 body.add(new JS.ClassDeclaration(cls)); | 643 body.add(new JS.ClassDeclaration(cls)); |
| (...skipping 1926 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2538 // TODO(jmesserly): validate the library. See issue #135. | 2570 // TODO(jmesserly): validate the library. See issue #135. |
| 2539 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; | 2571 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; |
| 2540 | 2572 |
| 2541 bool _isJsPeerInterface(DartObjectImpl value) => | 2573 bool _isJsPeerInterface(DartObjectImpl value) => |
| 2542 value.type.name == 'JsPeerInterface'; | 2574 value.type.name == 'JsPeerInterface'; |
| 2543 | 2575 |
| 2544 // TODO(jacobr): we would like to do something like the following | 2576 // TODO(jacobr): we would like to do something like the following |
| 2545 // but we don't have summary support yet. | 2577 // but we don't have summary support yet. |
| 2546 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 2578 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
| 2547 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 2579 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
| OLD | NEW |