| 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, SplayTreeSet; | 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
| 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 540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 ])); | 551 ])); |
| 552 } | 552 } |
| 553 | 553 |
| 554 // Interfaces | 554 // Interfaces |
| 555 if (classElem.interfaces.isNotEmpty) { | 555 if (classElem.interfaces.isNotEmpty) { |
| 556 body.add(js.statement('#[dart.implements] = () => #;', [ | 556 body.add(js.statement('#[dart.implements] = () => #;', [ |
| 557 name, | 557 name, |
| 558 new JS.ArrayInitializer( | 558 new JS.ArrayInitializer( |
| 559 classElem.interfaces.map(_emitTypeName).toList()) | 559 classElem.interfaces.map(_emitTypeName).toList()) |
| 560 ])); | 560 ])); |
| 561 | |
| 562 // If a concrete class implements one of our extensions, we might need to | |
| 563 // add forwarders. | |
| 564 var extensions = _extensionsToImplement(classElem); | |
| 565 if (extensions.isNotEmpty) { | |
| 566 var methodNames = []; | |
| 567 for (var e in extensions) { | |
| 568 methodNames.add(_emitMemberDeclarationName(e)); | |
| 569 } | |
| 570 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ | |
| 571 name, | |
| 572 new JS.ArrayInitializer(methodNames, | |
| 573 multiline: methodNames.length > 4) | |
| 574 ])); | |
| 575 } | |
| 576 } | 561 } |
| 577 | 562 |
| 578 // Named constructors | 563 // Named constructors |
| 579 for (ConstructorDeclaration member in ctors) { | 564 for (ConstructorDeclaration member in ctors) { |
| 580 if (member.name != null && member.factoryKeyword == null) { | 565 if (member.name != null && member.factoryKeyword == null) { |
| 581 body.add(js.statement('dart.defineNamedConstructor(#, #);', [ | 566 body.add(js.statement('dart.defineNamedConstructor(#, #);', [ |
| 582 name, | 567 name, |
| 583 _emitMemberName(member.name.name, isStatic: true) | 568 _emitMemberName(member.name.name, isStatic: true) |
| 584 ])); | 569 ])); |
| 585 } | 570 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 601 var tMethods = []; | 586 var tMethods = []; |
| 602 var sNames = []; | 587 var sNames = []; |
| 603 for (MethodDeclaration node in methods) { | 588 for (MethodDeclaration node in methods) { |
| 604 if (!(node.isSetter || node.isGetter || node.isAbstract)) { | 589 if (!(node.isSetter || node.isGetter || node.isAbstract)) { |
| 605 var name = node.name.name; | 590 var name = node.name.name; |
| 606 var element = node.element; | 591 var element = node.element; |
| 607 var inheritedElement = | 592 var inheritedElement = |
| 608 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); | 593 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); |
| 609 if (inheritedElement != null && | 594 if (inheritedElement != null && |
| 610 inheritedElement.type == element.type) continue; | 595 inheritedElement.type == element.type) continue; |
| 611 var memberName = _emitMemberDeclarationName(element); | 596 var memberName = _elementMemberName(element); |
| 612 var parts = | 597 var parts = |
| 613 _emitFunctionTypeParts(element.type, dynamicIsBottom: false); | 598 _emitFunctionTypeParts(element.type, dynamicIsBottom: false); |
| 614 var property = | 599 var property = |
| 615 new JS.Property(memberName, new JS.ArrayInitializer(parts)); | 600 new JS.Property(memberName, new JS.ArrayInitializer(parts)); |
| 616 if (node.isStatic) { | 601 if (node.isStatic) { |
| 617 tStatics.add(property); | 602 tStatics.add(property); |
| 618 sNames.add(memberName); | 603 sNames.add(memberName); |
| 619 } else { | 604 } else { |
| 620 tMethods.add(property); | 605 tMethods.add(property); |
| 621 } | 606 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 648 sigFields.add(build('statics', tStatics)); | 633 sigFields.add(build('statics', tStatics)); |
| 649 sigFields.add(aNames); | 634 sigFields.add(aNames); |
| 650 } | 635 } |
| 651 if (!sigFields.isEmpty) { | 636 if (!sigFields.isEmpty) { |
| 652 var sig = new JS.ObjectInitializer(sigFields); | 637 var sig = new JS.ObjectInitializer(sigFields); |
| 653 var classExpr = new JS.Identifier(name); | 638 var classExpr = new JS.Identifier(name); |
| 654 body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig])); | 639 body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig])); |
| 655 } | 640 } |
| 656 } | 641 } |
| 657 | 642 |
| 643 // If a concrete class implements one of our extensions, we might need to |
| 644 // add forwarders. |
| 645 var extensions = _extensionsToImplement(classElem); |
| 646 if (extensions.isNotEmpty) { |
| 647 var methodNames = []; |
| 648 for (var e in extensions) { |
| 649 methodNames.add(_elementMemberName(e, declaration: true)); |
| 650 } |
| 651 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ |
| 652 name, |
| 653 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) |
| 654 ])); |
| 655 } |
| 656 |
| 658 return _statement(body); | 657 return _statement(body); |
| 659 } | 658 } |
| 660 | 659 |
| 661 List<ExecutableElement> _extensionsToImplement(ClassElement element) { | 660 List<ExecutableElement> _extensionsToImplement(ClassElement element) { |
| 662 var members = <ExecutableElement>[]; | 661 var members = <ExecutableElement>[]; |
| 663 if (_extensionTypes.contains(element)) return members; | 662 if (_extensionTypes.contains(element)) return members; |
| 664 | 663 |
| 665 // Collect all extension types we implement. | 664 // Collect all extension types we implement. |
| 666 var type = element.type; | 665 var type = element.type; |
| 667 var types = new Set<ClassElement>(); | 666 var types = new Set<ClassElement>(); |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1041 } | 1040 } |
| 1042 | 1041 |
| 1043 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { | 1042 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { |
| 1044 if (node.isAbstract || _externalOrNative(node)) { | 1043 if (node.isAbstract || _externalOrNative(node)) { |
| 1045 return null; | 1044 return null; |
| 1046 } | 1045 } |
| 1047 | 1046 |
| 1048 var params = _visit(node.parameters); | 1047 var params = _visit(node.parameters); |
| 1049 if (params == null) params = []; | 1048 if (params == null) params = []; |
| 1050 | 1049 |
| 1051 return new JS.Method(_emitMemberDeclarationName(node.element), | 1050 return new JS.Method(_elementMemberName(node.element, declaration: true), |
| 1052 new JS.Fun(params, _visit(node.body)), | 1051 new JS.Fun(params, _visit(node.body)), |
| 1053 isGetter: node.isGetter, | 1052 isGetter: node.isGetter, |
| 1054 isSetter: node.isSetter, | 1053 isSetter: node.isSetter, |
| 1055 isStatic: node.isStatic); | 1054 isStatic: node.isStatic); |
| 1056 } | 1055 } |
| 1057 | 1056 |
| 1058 @override | 1057 @override |
| 1059 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { | 1058 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { |
| 1060 assert(node.parent is CompilationUnit); | 1059 assert(node.parent is CompilationUnit); |
| 1061 | 1060 |
| (...skipping 1455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2517 /// Visits a list of expressions, creating a comma expression if needed in JS. | 2516 /// Visits a list of expressions, creating a comma expression if needed in JS. |
| 2518 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { | 2517 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { |
| 2519 if (nodes == null || nodes.isEmpty) return null; | 2518 if (nodes == null || nodes.isEmpty) return null; |
| 2520 return new JS.Expression.binary(_visitList(nodes), operator); | 2519 return new JS.Expression.binary(_visitList(nodes), operator); |
| 2521 } | 2520 } |
| 2522 | 2521 |
| 2523 /// Like [_emitMemberName], but for declaration sites. | 2522 /// Like [_emitMemberName], but for declaration sites. |
| 2524 /// | 2523 /// |
| 2525 /// Unlike call sites, we always have an element available, so we can use it | 2524 /// Unlike call sites, we always have an element available, so we can use it |
| 2526 /// directly rather than computing the relevant options for [_emitMemberName]. | 2525 /// directly rather than computing the relevant options for [_emitMemberName]. |
| 2527 JS.Expression _emitMemberDeclarationName(ExecutableElement e) { | 2526 JS.Expression _elementMemberName(ExecutableElement e, |
| 2527 {bool declaration: false}) { |
| 2528 String name; | 2528 String name; |
| 2529 if (e is PropertyAccessorElement) { | 2529 if (e is PropertyAccessorElement) { |
| 2530 name = e.variable.name; | 2530 name = e.variable.name; |
| 2531 } else { | 2531 } else { |
| 2532 name = e.name; | 2532 name = e.name; |
| 2533 } | 2533 } |
| 2534 return _emitMemberName(name, | 2534 return _emitMemberName(name, |
| 2535 type: (e.enclosingElement as ClassElement).type, | 2535 type: (e.enclosingElement as ClassElement).type, |
| 2536 unary: e.parameters.isEmpty, | 2536 unary: e.parameters.isEmpty, |
| 2537 isStatic: e.isStatic, | 2537 isStatic: e.isStatic, |
| 2538 declaration: true); | 2538 declaration: declaration); |
| 2539 } | 2539 } |
| 2540 | 2540 |
| 2541 /// This handles member renaming for private names and operators. | 2541 /// This handles member renaming for private names and operators. |
| 2542 /// | 2542 /// |
| 2543 /// Private names are generated using ES6 symbols: | 2543 /// Private names are generated using ES6 symbols: |
| 2544 /// | 2544 /// |
| 2545 /// // At the top of the module: | 2545 /// // At the top of the module: |
| 2546 /// let _x = Symbol('_x'); | 2546 /// let _x = Symbol('_x'); |
| 2547 /// let _y = Symbol('_y'); | 2547 /// let _y = Symbol('_y'); |
| 2548 /// ... | 2548 /// ... |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2592 | 2592 |
| 2593 if (name == '[]') { | 2593 if (name == '[]') { |
| 2594 name = 'get'; | 2594 name = 'get'; |
| 2595 } else if (name == '[]=') { | 2595 } else if (name == '[]=') { |
| 2596 name = 'set'; | 2596 name = 'set'; |
| 2597 } else if (name == '-' && unary) { | 2597 } else if (name == '-' && unary) { |
| 2598 name = 'unary-'; | 2598 name = 'unary-'; |
| 2599 } | 2599 } |
| 2600 | 2600 |
| 2601 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 2601 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
| 2602 if (!declaration && _extensionTypes.contains(type.element)) { | 2602 // Special case `length`. We can call it directly. |
| 2603 // Special case `length`. We can call it directly. | 2603 if (_extensionTypes.contains(type.element) && name != 'length') { |
| 2604 if (name != 'length') return js.call('dartx.#', _propertyName(name)); | 2604 var code = declaration ? 'dart.extensionMember(#)' : 'dartx.#'; |
| 2605 return js.call(code, _propertyName(name)); |
| 2605 } | 2606 } |
| 2606 | 2607 |
| 2607 return _propertyName(name); | 2608 return _propertyName(name); |
| 2608 } | 2609 } |
| 2609 | 2610 |
| 2610 bool _externalOrNative(node) => | 2611 bool _externalOrNative(node) => |
| 2611 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 2612 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
| 2612 | 2613 |
| 2613 FunctionBody _functionBody(node) => | 2614 FunctionBody _functionBody(node) => |
| 2614 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 2615 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2699 | 2700 |
| 2700 /// A special kind of element created by the compiler, signifying a temporary | 2701 /// A special kind of element created by the compiler, signifying a temporary |
| 2701 /// variable. These objects use instance equality, and should be shared | 2702 /// variable. These objects use instance equality, and should be shared |
| 2702 /// everywhere in the tree where they are treated as the same variable. | 2703 /// everywhere in the tree where they are treated as the same variable. |
| 2703 class TemporaryVariableElement extends LocalVariableElementImpl { | 2704 class TemporaryVariableElement extends LocalVariableElementImpl { |
| 2704 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 2705 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
| 2705 | 2706 |
| 2706 int get hashCode => identityHashCode(this); | 2707 int get hashCode => identityHashCode(this); |
| 2707 bool operator ==(Object other) => identical(this, other); | 2708 bool operator ==(Object other) => identical(this, other); |
| 2708 } | 2709 } |
| OLD | NEW |