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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
| 6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
| 7 | 7 |
| 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 /// Helper class for emitting elements in the proper order to allow | 119 /// Helper class for emitting elements in the proper order to allow |
| 120 /// JS to load the module. | 120 /// JS to load the module. |
| 121 ElementLoader _loader; | 121 ElementLoader _loader; |
| 122 | 122 |
| 123 BuildUnit _buildUnit; | 123 BuildUnit _buildUnit; |
| 124 | 124 |
| 125 String _buildRoot; | 125 String _buildRoot; |
| 126 | 126 |
| 127 bool _superAllowed = true; | 127 bool _superAllowed = true; |
| 128 | 128 |
| 129 bool _inAngularTemplate = false; | |
| 130 | |
| 129 List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[]; | 131 List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[]; |
| 130 List<JS.Method> _superHelpers = <JS.Method>[]; | 132 List<JS.Method> _superHelpers = <JS.Method>[]; |
| 131 | 133 |
| 132 List<TypeParameterType> _typeParamInConst = null; | 134 List<TypeParameterType> _typeParamInConst = null; |
| 133 | 135 |
| 134 /// Whether we are currently generating code for the body of a `JS()` call. | 136 /// Whether we are currently generating code for the body of a `JS()` call. |
| 135 bool _isInForeignJS = false; | 137 bool _isInForeignJS = false; |
| 136 | 138 |
| 137 CodeGenerator(AnalysisContext c, this.options, this._extensionTypes) | 139 CodeGenerator(AnalysisContext c, this.options, this._extensionTypes) |
| 138 : context = c, | 140 : context = c, |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 | 419 |
| 418 if (item != null) _moduleItems.add(item); | 420 if (item != null) _moduleItems.add(item); |
| 419 } | 421 } |
| 420 | 422 |
| 421 void _declareBeforeUse(Element e) { | 423 void _declareBeforeUse(Element e) { |
| 422 _loader.declareBeforeUse(e, _emitDeclaration); | 424 _loader.declareBeforeUse(e, _emitDeclaration); |
| 423 } | 425 } |
| 424 | 426 |
| 425 @override | 427 @override |
| 426 void visitCompilationUnit(CompilationUnit unit) { | 428 void visitCompilationUnit(CompilationUnit unit) { |
| 429 _inAngularTemplate = | |
|
Jennifer Messerly
2016/05/26 18:19:02
can we have this guarded by a compile flag please?
| |
| 430 unit.element.source.fullName.endsWith(".template.dart"); | |
|
Jennifer Messerly
2016/05/26 18:19:02
So, this doesn't work... I should put a comment on
| |
| 431 | |
| 427 _constField = new ConstFieldVisitor(types, unit.element.source); | 432 _constField = new ConstFieldVisitor(types, unit.element.source); |
| 428 | 433 |
| 429 for (var declaration in unit.declarations) { | 434 for (var declaration in unit.declarations) { |
| 430 var element = declaration.element; | 435 var element = declaration.element; |
| 431 if (element != null) { | 436 if (element != null) { |
| 432 _emitDeclaration(element); | 437 _emitDeclaration(element); |
| 433 } else { | 438 } else { |
| 434 declaration.accept(this); | 439 declaration.accept(this); |
| 435 } | 440 } |
| 436 } | 441 } |
| 437 for (var directive in unit.directives) { | 442 for (var directive in unit.directives) { |
| 438 directive.accept(this); | 443 directive.accept(this); |
| 439 } | 444 } |
| 445 _inAngularTemplate = false; | |
| 440 } | 446 } |
| 441 | 447 |
| 442 @override | 448 @override |
| 443 void visitLibraryDirective(LibraryDirective node) {} | 449 void visitLibraryDirective(LibraryDirective node) {} |
| 444 | 450 |
| 445 @override | 451 @override |
| 446 void visitImportDirective(ImportDirective node) { | 452 void visitImportDirective(ImportDirective node) { |
| 447 // We don't handle imports here. | 453 // We don't handle imports here. |
| 448 // | 454 // |
| 449 // Instead, we collect imports whenever we need to generate a reference | 455 // Instead, we collect imports whenever we need to generate a reference |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 535 return js.call('dart.asInt(#)', jsFrom); | 541 return js.call('dart.asInt(#)', jsFrom); |
| 536 } | 542 } |
| 537 | 543 |
| 538 // A no-op in JavaScript. | 544 // A no-op in JavaScript. |
| 539 return jsFrom; | 545 return jsFrom; |
| 540 } | 546 } |
| 541 | 547 |
| 542 var type = _emitType(to, | 548 var type = _emitType(to, |
| 543 nameType: options.nameTypeTests || options.hoistTypeTests, | 549 nameType: options.nameTypeTests || options.hoistTypeTests, |
| 544 hoistType: options.hoistTypeTests); | 550 hoistType: options.hoistTypeTests); |
| 551 if (_inAngularTemplate) return jsFrom; | |
| 545 return js.call('dart.as(#, #)', [jsFrom, type]); | 552 return js.call('dart.as(#, #)', [jsFrom, type]); |
| 546 } | 553 } |
| 547 | 554 |
| 548 @override | 555 @override |
| 549 visitIsExpression(IsExpression node) { | 556 visitIsExpression(IsExpression node) { |
| 550 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. | 557 // Generate `is` as `dart.is` or `typeof` depending on the RHS type. |
| 551 JS.Expression result; | 558 JS.Expression result; |
| 552 var type = node.type.type; | 559 var type = node.type.type; |
| 553 var lhs = _visit(node.expression); | 560 var lhs = _visit(node.expression); |
| 554 var typeofName = _jsTypeofName(type); | 561 var typeofName = _jsTypeofName(type); |
| (...skipping 1158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1713 } | 1720 } |
| 1714 } | 1721 } |
| 1715 | 1722 |
| 1716 // TODO(jmesserly): various problems here, see: | 1723 // TODO(jmesserly): various problems here, see: |
| 1717 // https://github.com/dart-lang/dev_compiler/issues/116 | 1724 // https://github.com/dart-lang/dev_compiler/issues/116 |
| 1718 var paramType = param.element.type; | 1725 var paramType = param.element.type; |
| 1719 if (node is MethodDeclaration && _unsoundCovariant(paramType, true)) { | 1726 if (node is MethodDeclaration && _unsoundCovariant(paramType, true)) { |
| 1720 var castType = _emitType(paramType, | 1727 var castType = _emitType(paramType, |
| 1721 nameType: options.nameTypeTests || options.hoistTypeTests, | 1728 nameType: options.nameTypeTests || options.hoistTypeTests, |
| 1722 hoistType: options.hoistTypeTests); | 1729 hoistType: options.hoistTypeTests); |
| 1723 body.add(js.statement('dart.as(#, #);', [jsParam, castType])); | 1730 if (!_inAngularTemplate) { |
| 1731 body.add(js.statement('dart.as(#, #);', [jsParam, castType])); | |
| 1732 } | |
| 1724 } | 1733 } |
| 1725 } | 1734 } |
| 1726 return body.isEmpty ? null : _statement(body); | 1735 return body.isEmpty ? null : _statement(body); |
| 1727 } | 1736 } |
| 1728 | 1737 |
| 1729 /// Given a type [t], return whether or not t is unsoundly covariant. | 1738 /// Given a type [t], return whether or not t is unsoundly covariant. |
| 1730 /// If [contravariant] is true, then t appears in a contravariant | 1739 /// If [contravariant] is true, then t appears in a contravariant |
| 1731 /// position. | 1740 /// position. |
| 1732 bool _unsoundCovariant(DartType t, bool contravariant) { | 1741 bool _unsoundCovariant(DartType t, bool contravariant) { |
| 1733 if (t is TypeParameterType) { | 1742 if (t is TypeParameterType) { |
| (...skipping 776 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2510 } | 2519 } |
| 2511 | 2520 |
| 2512 target = _getTarget(lhs); | 2521 target = _getTarget(lhs); |
| 2513 id = lhs.propertyName; | 2522 id = lhs.propertyName; |
| 2514 } else if (lhs is PrefixedIdentifier) { | 2523 } else if (lhs is PrefixedIdentifier) { |
| 2515 target = lhs.prefix; | 2524 target = lhs.prefix; |
| 2516 id = lhs.identifier; | 2525 id = lhs.identifier; |
| 2517 } | 2526 } |
| 2518 | 2527 |
| 2519 if (target != null && DynamicInvoke.get(target)) { | 2528 if (target != null && DynamicInvoke.get(target)) { |
| 2529 if (_inAngularTemplate) { | |
| 2530 return _visit(rhs).toAssignExpression(_visit(lhs)); | |
| 2531 } | |
| 2520 return js.call('dart.dput(#, #, #)', | 2532 return js.call('dart.dput(#, #, #)', |
| 2521 [_visit(target), _emitMemberName(id.name), _visit(rhs)]); | 2533 [_visit(target), _emitMemberName(id.name), _visit(rhs)]); |
| 2522 } | 2534 } |
| 2523 | 2535 |
| 2524 return _visit(rhs).toAssignExpression(_visit(lhs)); | 2536 return _visit(rhs).toAssignExpression(_visit(lhs)); |
| 2525 } | 2537 } |
| 2526 | 2538 |
| 2527 JS.Expression _emitNullSafeSet(PropertyAccess node, Expression right) { | 2539 JS.Expression _emitNullSafeSet(PropertyAccess node, Expression right) { |
| 2528 // Emit `obj?.prop = expr` as: | 2540 // Emit `obj?.prop = expr` as: |
| 2529 // | 2541 // |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2640 List<JS.Expression> args, | 2652 List<JS.Expression> args, |
| 2641 List<JS.Expression> typeArgs) { | 2653 List<JS.Expression> typeArgs) { |
| 2642 var type = getStaticType(target); | 2654 var type = getStaticType(target); |
| 2643 var name = node.methodName.name; | 2655 var name = node.methodName.name; |
| 2644 var element = node.methodName.staticElement; | 2656 var element = node.methodName.staticElement; |
| 2645 bool isStatic = element is ExecutableElement && element.isStatic; | 2657 bool isStatic = element is ExecutableElement && element.isStatic; |
| 2646 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); | 2658 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); |
| 2647 | 2659 |
| 2648 JS.Expression jsTarget = _visit(target); | 2660 JS.Expression jsTarget = _visit(target); |
| 2649 if (DynamicInvoke.get(target) || DynamicInvoke.get(node.methodName)) { | 2661 if (DynamicInvoke.get(target) || DynamicInvoke.get(node.methodName)) { |
| 2662 if (_inAngularTemplate) { | |
| 2663 jsTarget = new JS.PropertyAccess(jsTarget, memberName); | |
| 2664 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | |
| 2665 return new JS.Call(jsTarget, args); | |
| 2666 } | |
| 2650 if (typeArgs != null) { | 2667 if (typeArgs != null) { |
| 2651 return js.call('dart.dgsend(#, #, #, #)', | 2668 return js.call('dart.dgsend(#, #, #, #)', |
| 2652 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); | 2669 [jsTarget, new JS.ArrayInitializer(typeArgs), memberName, args]); |
| 2653 } else { | 2670 } else { |
| 2654 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); | 2671 return js.call('dart.dsend(#, #, #)', [jsTarget, memberName, args]); |
| 2655 } | 2672 } |
| 2656 } | 2673 } |
| 2657 if (_isObjectMemberCall(target, name)) { | 2674 if (_isObjectMemberCall(target, name)) { |
| 2658 assert(typeArgs == null); // Object methods don't take type args. | 2675 assert(typeArgs == null); // Object methods don't take type args. |
| 2659 return js.call('dart.#(#, #)', [name, jsTarget, args]); | 2676 return js.call('dart.#(#, #)', [name, jsTarget, args]); |
| 2660 } | 2677 } |
| 2661 | 2678 |
| 2662 jsTarget = new JS.PropertyAccess(jsTarget, memberName); | 2679 jsTarget = new JS.PropertyAccess(jsTarget, memberName); |
| 2663 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 2680 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
| 2664 | 2681 |
| 2665 return new JS.Call(jsTarget, args); | 2682 return new JS.Call(jsTarget, args); |
| 2666 } | 2683 } |
| 2667 | 2684 |
| 2668 /// Emits a function call, to a top-level function, local function, or | 2685 /// Emits a function call, to a top-level function, local function, or |
| 2669 /// an expression. | 2686 /// an expression. |
| 2670 JS.Expression _emitFunctionCall(InvocationExpression node) { | 2687 JS.Expression _emitFunctionCall(InvocationExpression node) { |
| 2671 var fn = _visit(node.function); | 2688 var fn = _visit(node.function); |
| 2672 var args = _visit(node.argumentList); | 2689 var args = _visit(node.argumentList); |
| 2673 if (DynamicInvoke.get(node.function)) { | 2690 if (DynamicInvoke.get(node.function)) { |
| 2674 var typeArgs = _emitInvokeTypeArguments(node); | 2691 var typeArgs = _emitInvokeTypeArguments(node); |
| 2675 if (typeArgs != null) { | 2692 if (typeArgs != null) { |
| 2676 return js.call('dart.dgcall(#, #, #)', | 2693 return js.call('dart.dgcall(#, #, #)', |
| 2677 [fn, new JS.ArrayInitializer(typeArgs), args]); | 2694 [fn, new JS.ArrayInitializer(typeArgs), args]); |
| 2678 } else { | 2695 } else { |
| 2696 if (_inAngularTemplate) { | |
| 2697 return new JS.Call(fn, args); | |
| 2698 } | |
| 2679 return js.call('dart.dcall(#, #)', [fn, args]); | 2699 return js.call('dart.dcall(#, #)', [fn, args]); |
| 2680 } | 2700 } |
| 2681 } else { | 2701 } else { |
| 2682 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); | 2702 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); |
| 2683 } | 2703 } |
| 2684 } | 2704 } |
| 2685 | 2705 |
| 2686 JS.Expression _applyInvokeTypeArguments( | 2706 JS.Expression _applyInvokeTypeArguments( |
| 2687 JS.Expression target, InvocationExpression node) { | 2707 JS.Expression target, InvocationExpression node) { |
| 2688 var typeArgs = _emitInvokeTypeArguments(node); | 2708 var typeArgs = _emitInvokeTypeArguments(node); |
| (...skipping 1158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3847 if (type == null) return null; | 3867 if (type == null) return null; |
| 3848 return _emitFunctionTypeArguments(type, instantiated); | 3868 return _emitFunctionTypeArguments(type, instantiated); |
| 3849 } | 3869 } |
| 3850 | 3870 |
| 3851 JS.Expression _emitAccessInternal(Expression target, Element member, | 3871 JS.Expression _emitAccessInternal(Expression target, Element member, |
| 3852 String memberName, List<JS.Expression> typeArgs) { | 3872 String memberName, List<JS.Expression> typeArgs) { |
| 3853 bool isStatic = member is ClassMemberElement && member.isStatic; | 3873 bool isStatic = member is ClassMemberElement && member.isStatic; |
| 3854 var name = _emitMemberName(memberName, | 3874 var name = _emitMemberName(memberName, |
| 3855 type: getStaticType(target), isStatic: isStatic); | 3875 type: getStaticType(target), isStatic: isStatic); |
| 3856 if (DynamicInvoke.get(target)) { | 3876 if (DynamicInvoke.get(target)) { |
| 3877 if (_inAngularTemplate) { | |
| 3878 return js.call('#.#', [_visit(target), name]); | |
| 3879 } | |
| 3857 return js.call('dart.dload(#, #)', [_visit(target), name]); | 3880 return js.call('dart.dload(#, #)', [_visit(target), name]); |
| 3858 } | 3881 } |
| 3859 | 3882 |
| 3860 var jsTarget = _visit(target); | 3883 var jsTarget = _visit(target); |
| 3861 bool isSuper = jsTarget is JS.Super; | 3884 bool isSuper = jsTarget is JS.Super; |
| 3862 | 3885 |
| 3863 if (isSuper && member is FieldElement && !member.isSynthetic) { | 3886 if (isSuper && member is FieldElement && !member.isSynthetic) { |
| 3864 // If super.x is actually a field, then x is an instance property since | 3887 // If super.x is actually a field, then x is an instance property since |
| 3865 // subclasses cannot override x. | 3888 // subclasses cannot override x. |
| 3866 jsTarget = new JS.This(); | 3889 jsTarget = new JS.This(); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 3897 Expression target, String name, List<Expression> args) { | 3920 Expression target, String name, List<Expression> args) { |
| 3898 var type = getStaticType(target); | 3921 var type = getStaticType(target); |
| 3899 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); | 3922 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); |
| 3900 if (DynamicInvoke.get(target)) { | 3923 if (DynamicInvoke.get(target)) { |
| 3901 // dynamic dispatch | 3924 // dynamic dispatch |
| 3902 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name]; | 3925 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name]; |
| 3903 if (dynamicHelper != null) { | 3926 if (dynamicHelper != null) { |
| 3904 return js.call( | 3927 return js.call( |
| 3905 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); | 3928 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); |
| 3906 } | 3929 } |
| 3907 return js.call('dart.dsend(#, #, #)', | 3930 if (_inAngularTemplate) { |
| 3908 [_visit(target), memberName, _visitList(args)]); | 3931 return js |
| 3932 .call('#.#(#)', [_visit(target), memberName, _visitList(args)]); | |
| 3933 } else { | |
| 3934 return js.call('dart.dsend(#, #, #)', | |
| 3935 [_visit(target), memberName, _visitList(args)]); | |
| 3936 } | |
| 3909 } | 3937 } |
| 3910 | 3938 |
| 3911 // Generic dispatch to a statically known method. | 3939 // Generic dispatch to a statically known method. |
| 3912 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); | 3940 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); |
| 3913 } | 3941 } |
| 3914 | 3942 |
| 3915 @override | 3943 @override |
| 3916 visitIndexExpression(IndexExpression node) { | 3944 visitIndexExpression(IndexExpression node) { |
| 3917 var target = _getTarget(node); | 3945 var target = _getTarget(node); |
| 3918 if (_useNativeJsIndexer(target.staticType)) { | 3946 if (_useNativeJsIndexer(target.staticType)) { |
| (...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4632 } | 4660 } |
| 4633 | 4661 |
| 4634 bool isLibraryPrefix(Expression node) => | 4662 bool isLibraryPrefix(Expression node) => |
| 4635 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4663 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 4636 | 4664 |
| 4637 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4665 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 4638 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4666 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 4639 | 4667 |
| 4640 bool _isDartRuntime(LibraryElement l) => | 4668 bool _isDartRuntime(LibraryElement l) => |
| 4641 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4669 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |