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 ddc.src.codegen.js_codegen; | 5 library ddc.src.codegen.js_codegen; |
| 6 | 6 |
| 7 import 'dart:io' show Directory, File; | 7 import 'dart:io' show Directory, File; |
| 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 659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 670 } else { | 670 } else { |
| 671 result = new JS.VariableUse(name); | 671 result = new JS.VariableUse(name); |
| 672 } | 672 } |
| 673 | 673 |
| 674 if (typeArgs != null) { | 674 if (typeArgs != null) { |
| 675 result = js.call('#(#)', [result, typeArgs]); | 675 result = js.call('#(#)', [result, typeArgs]); |
| 676 } | 676 } |
| 677 return result; | 677 return result; |
| 678 } | 678 } |
| 679 | 679 |
| 680 JS.Node _generateDPutIfDynamic( | |
| 681 Expression target, SimpleIdentifier id, Expression rhs) { | |
| 682 if (rules.isDynamicTarget(target)) { | |
| 683 return js.call('dart.dput(#, #, #)', [ | |
| 684 target.accept(this), | |
| 685 js.string(id.name, "'"), | |
| 686 rhs.accept(this) | |
| 687 ]); | |
| 688 } else { | |
| 689 return null; | |
| 690 } | |
| 691 } | |
| 692 | |
| 680 @override | 693 @override |
| 681 JS.Node visitAssignmentExpression(AssignmentExpression node) { | 694 JS.Node visitAssignmentExpression(AssignmentExpression node) { |
| 682 var lhs = node.leftHandSide; | 695 var lhs = node.leftHandSide; |
| 683 var rhs = node.rightHandSide; | 696 var rhs = node.rightHandSide; |
| 697 return _generateAssignment(lhs, rhs, node.parent); | |
| 698 } | |
| 699 | |
| 700 JS.Node _generateAssignment(Expression lhs, Expression rhs, | |
|
Jennifer Messerly
2015/02/26 20:53:16
I've been using the "_emit" prefix. For better or
vsm
2015/03/03 21:06:12
Done.
| |
| 701 [AstNode parent]) { | |
| 684 if (lhs is IndexExpression) { | 702 if (lhs is IndexExpression) { |
| 685 String code; | 703 String code; |
| 686 var target = _getTarget(lhs); | 704 var target = _getTarget(lhs); |
| 687 if (rules.isDynamicTarget(target)) { | 705 if (rules.isDynamicTarget(target)) { |
| 688 code = 'dart.dsetindex(#, #, #)'; | 706 code = 'dart.dsetindex(#, #, #)'; |
| 689 } else { | 707 } else { |
| 690 code = '#.set(#, #)'; | 708 code = '#.set(#, #)'; |
| 691 } | 709 } |
| 692 return js.call(code, [ | 710 return js.call(code, [ |
| 693 target.accept(this), | 711 target.accept(this), |
| 694 lhs.index.accept(this), | 712 lhs.index.accept(this), |
| 695 rhs.accept(this) | 713 rhs.accept(this) |
| 696 ]); | 714 ]); |
| 697 } | 715 } |
| 698 | 716 |
| 699 if (lhs is PropertyAccess) { | 717 if (lhs is PropertyAccess) { |
| 700 var target = _getTarget(lhs); | 718 var result = |
| 701 if (rules.isDynamicTarget(target)) { | 719 _generateDPutIfDynamic(_getTarget(lhs), lhs.propertyName, rhs); |
| 702 return js.call('dart.dput(#, #, #)', [ | 720 if (result != null) return result; |
| 703 target.accept(this), | 721 } else if (lhs is PrefixedIdentifier) { |
|
Jennifer Messerly
2015/02/26 20:53:16
how does a prefixed identifier end up as a dynamic
vsm
2015/03/03 21:06:12
In sunflower, notes.textContent shows up as a Pref
| |
| 704 js.string(lhs.propertyName.name, "'"), | 722 // TODO(vsm): Is this the right code if the prefix is a library? |
| 705 rhs.accept(this) | 723 var result = _generateDPutIfDynamic(lhs.prefix, lhs.identifier, rhs); |
| 706 ]); | 724 if (result != null) return result; |
| 707 } | |
| 708 } | 725 } |
| 709 | 726 |
| 710 if (node.parent is ExpressionStatement && | 727 if (parent is ExpressionStatement && |
| 711 rhs is CascadeExpression && | 728 rhs is CascadeExpression && |
| 712 _isStateless(lhs, rhs)) { | 729 _isStateless(lhs, rhs)) { |
| 713 // Special case: cascade assignment to a variable in a statement. | 730 // Special case: cascade assignment to a variable in a statement. |
| 714 // We can reuse the variable to desugar it: | 731 // We can reuse the variable to desugar it: |
| 715 // result = []..length = length; | 732 // result = []..length = length; |
| 716 // becomes: | 733 // becomes: |
| 717 // result = []; | 734 // result = []; |
| 718 // result.length = length; | 735 // result.length = length; |
| 719 var savedCascadeTemp = _cascadeTarget; | 736 var savedCascadeTemp = _cascadeTarget; |
| 720 _cascadeTarget = lhs; | 737 _cascadeTarget = lhs; |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1086 } else { | 1103 } else { |
| 1087 // Generic static-dispatch, user-defined operator code path. | 1104 // Generic static-dispatch, user-defined operator code path. |
| 1088 return js.call( | 1105 return js.call( |
| 1089 '#.#(#)', [left.accept(this), opString, right.accept(this)]); | 1106 '#.#(#)', [left.accept(this), opString, right.accept(this)]); |
| 1090 } | 1107 } |
| 1091 } | 1108 } |
| 1092 } | 1109 } |
| 1093 | 1110 |
| 1094 bool _isNull(Expression expr) => expr is NullLiteral; | 1111 bool _isNull(Expression expr) => expr is NullLiteral; |
| 1095 | 1112 |
| 1113 JS.Expression _generateIncrement(Token op, Expression expr, bool prefix) { | |
| 1114 // TODO(vsm): Should we generate a runtime helper for this? | |
|
Jennifer Messerly
2015/02/26 20:53:16
yeah, for now i think that's the pattern. this loo
vsm
2015/03/03 21:06:12
Note - there is a free expression in the closure,
| |
| 1115 var tmp = '_'; | |
| 1116 var applied = prefix ? '$tmp$op' : '$op$tmp'; | |
| 1117 var id = | |
| 1118 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, tmp, 0)); | |
| 1119 id.staticElement = new LocalVariableElementImpl.forNode(id); | |
| 1120 id.staticType = expr.staticType; | |
| 1121 var assignment = _generateAssignment(expr, id); | |
| 1122 return js.call(''' | |
| 1123 (function () { | |
| 1124 var $tmp = #; | |
| 1125 if (typeof($tmp) != 'number') throw 'number expected'; | |
| 1126 var result = $applied; | |
| 1127 #; | |
| 1128 return result; | |
| 1129 })() | |
| 1130 ''', [expr.accept(this), assignment]); | |
| 1131 } | |
| 1132 | |
| 1096 @override | 1133 @override |
| 1097 JS.Expression visitPostfixExpression(PostfixExpression node) { | 1134 JS.Expression visitPostfixExpression(PostfixExpression node) { |
| 1098 var op = node.operator; | 1135 var op = node.operator; |
| 1099 var expr = node.operand; | 1136 var expr = node.operand; |
| 1100 | 1137 |
| 1101 var dispatchType = rules.getStaticType(expr); | 1138 var dispatchType = rules.getStaticType(expr); |
| 1102 if (unaryOperationIsPrimitive(dispatchType)) { | 1139 if (unaryOperationIsPrimitive(dispatchType)) { |
| 1103 // TODO(vsm): When do Dart ops not map to JS? | 1140 // TODO(vsm): When do Dart ops not map to JS? |
| 1104 return js.call('#$op', notNull(expr)); | 1141 return js.call('#$op', notNull(expr)); |
| 1105 } else { | 1142 } else { |
| 1106 // TODO(vsm): Figure out operator calling convention / dispatch. | 1143 assert(op.lexeme == '++' || op.lexeme == '--'); |
| 1107 return visitExpression(node); | 1144 return _generateIncrement(op, expr, false); |
|
Jennifer Messerly
2015/02/26 20:53:17
nit: use named arg `prefix: false`
vsm
2015/03/03 21:06:12
Done.
| |
| 1108 } | 1145 } |
| 1109 } | 1146 } |
| 1110 | 1147 |
| 1111 @override | 1148 @override |
| 1112 JS.Expression visitPrefixExpression(PrefixExpression node) { | 1149 JS.Expression visitPrefixExpression(PrefixExpression node) { |
| 1113 var op = node.operator; | 1150 var op = node.operator; |
| 1114 var expr = node.operand; | 1151 var expr = node.operand; |
| 1115 | 1152 |
| 1116 var dispatchType = rules.getStaticType(expr); | 1153 var dispatchType = rules.getStaticType(expr); |
| 1117 if (unaryOperationIsPrimitive(dispatchType)) { | 1154 if (unaryOperationIsPrimitive(dispatchType)) { |
| 1118 // TODO(vsm): When do Dart ops not map to JS? | 1155 // TODO(vsm): When do Dart ops not map to JS? |
| 1119 return js.call('$op#', notNull(expr)); | 1156 return js.call('$op#', notNull(expr)); |
| 1120 } else { | 1157 } else { |
| 1121 // TODO(vsm): Figure out operator calling convention / dispatch. | 1158 if (op.lexeme == '++' || op.lexeme == '--') { |
| 1122 return visitExpression(node); | 1159 return _generateIncrement(op, expr, true); |
| 1160 } | |
| 1123 } | 1161 } |
| 1162 // TODO(vsm): Expand out. | |
| 1163 return visitExpression(node); | |
|
vsm
2015/02/26 00:34:00
Should this just be:
x['-']()
? Or similar? T
Jennifer Messerly
2015/02/26 20:53:17
IMO, name should be "unary-" unless we find a good
| |
| 1124 } | 1164 } |
| 1125 | 1165 |
| 1126 // Cascades can contain [IndexExpression], [MethodInvocation] and | 1166 // Cascades can contain [IndexExpression], [MethodInvocation] and |
| 1127 // [PropertyAccess]. The code generation for those is handled in their | 1167 // [PropertyAccess]. The code generation for those is handled in their |
| 1128 // respective visit methods. | 1168 // respective visit methods. |
| 1129 @override | 1169 @override |
| 1130 JS.Node visitCascadeExpression(CascadeExpression node) { | 1170 JS.Node visitCascadeExpression(CascadeExpression node) { |
| 1131 var savedCascadeTemp = _cascadeTarget; | 1171 var savedCascadeTemp = _cascadeTarget; |
| 1132 | 1172 |
| 1133 var parent = node.parent; | 1173 var parent = node.parent; |
| (...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1705 /// Choose a canonical name from the library element. | 1745 /// Choose a canonical name from the library element. |
| 1706 /// This never uses the library's name (the identifier in the `library` | 1746 /// This never uses the library's name (the identifier in the `library` |
| 1707 /// declaration) as it doesn't have any meaningful rules enforced. | 1747 /// declaration) as it doesn't have any meaningful rules enforced. |
| 1708 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); | 1748 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); |
| 1709 | 1749 |
| 1710 /// Path to file that will be generated for [info]. | 1750 /// Path to file that will be generated for [info]. |
| 1711 // TODO(jmesserly): library directory should be relative to its package | 1751 // TODO(jmesserly): library directory should be relative to its package |
| 1712 // root. For example, "package:dev_compiler/src/codegen/js_codegen.dart" would b e: | 1752 // root. For example, "package:dev_compiler/src/codegen/js_codegen.dart" would b e: |
| 1713 // "ddc/src/codegen/js_codegen.js" under the output directory. | 1753 // "ddc/src/codegen/js_codegen.js" under the output directory. |
| 1714 String jsOutputPath(LibraryInfo info) => '${info.name}/${info.name}.js'; | 1754 String jsOutputPath(LibraryInfo info) => '${info.name}/${info.name}.js'; |
| OLD | NEW |