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 |