| 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:collection' show HashSet; | 7 import 'dart:collection' show HashSet; |
| 8 import 'dart:io' show Directory, File; | 8 import 'dart:io' show Directory, File; |
| 9 | 9 |
| 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
| 12 import 'package:analyzer/src/generated/constant.dart'; | 12 import 'package:analyzer/src/generated/constant.dart'; |
| 13 import 'package:analyzer/src/generated/element.dart'; | 13 import 'package:analyzer/src/generated/element.dart'; |
| 14 import 'package:analyzer/src/generated/scanner.dart' | 14 import 'package:analyzer/src/generated/scanner.dart' |
| 15 show StringToken, Token, TokenType; | 15 show StringToken, Token, TokenType; |
| 16 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; | 16 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; |
| 17 import 'package:source_maps/source_maps.dart' show SourceMapSpan; | 17 import 'package:source_maps/source_maps.dart' show SourceMapSpan; |
| 18 import 'package:source_span/source_span.dart' show SourceLocation; | 18 import 'package:source_span/source_span.dart' show SourceLocation; |
| 19 import 'package:path/path.dart' as path; | 19 import 'package:path/path.dart' as path; |
| 20 | 20 |
| 21 import 'package:dev_compiler/src/codegen/ast_builder.dart' show AstBuilder; |
| 22 |
| 21 // TODO(jmesserly): import from its own package | 23 // TODO(jmesserly): import from its own package |
| 22 import 'package:dev_compiler/src/js/js_ast.dart' as JS; | 24 import 'package:dev_compiler/src/js/js_ast.dart' as JS; |
| 23 import 'package:dev_compiler/src/js/js_ast.dart' show js; | 25 import 'package:dev_compiler/src/js/js_ast.dart' show js; |
| 24 | 26 |
| 25 import 'package:dev_compiler/src/checker/rules.dart'; | 27 import 'package:dev_compiler/src/checker/rules.dart'; |
| 26 import 'package:dev_compiler/src/info.dart'; | 28 import 'package:dev_compiler/src/info.dart'; |
| 27 import 'package:dev_compiler/src/options.dart'; | 29 import 'package:dev_compiler/src/options.dart'; |
| 28 import 'package:dev_compiler/src/report.dart'; | 30 import 'package:dev_compiler/src/report.dart'; |
| 29 import 'package:dev_compiler/src/utils.dart'; | 31 import 'package:dev_compiler/src/utils.dart'; |
| 30 import 'code_generator.dart'; | 32 import 'code_generator.dart'; |
| (...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 } else { | 693 } else { |
| 692 result = new JS.VariableUse(name); | 694 result = new JS.VariableUse(name); |
| 693 } | 695 } |
| 694 | 696 |
| 695 if (typeArgs != null) { | 697 if (typeArgs != null) { |
| 696 result = js.call('#(#)', [result, typeArgs]); | 698 result = js.call('#(#)', [result, typeArgs]); |
| 697 } | 699 } |
| 698 return result; | 700 return result; |
| 699 } | 701 } |
| 700 | 702 |
| 703 JS.Node _emitDPutIfDynamic( |
| 704 Expression target, SimpleIdentifier id, Expression rhs) { |
| 705 if (rules.isDynamicTarget(target)) { |
| 706 return js.call('dart.dput(#, #, #)', [ |
| 707 _visit(target), |
| 708 js.string(id.name, "'"), |
| 709 _visit(rhs) |
| 710 ]); |
| 711 } else { |
| 712 return null; |
| 713 } |
| 714 } |
| 715 |
| 701 @override | 716 @override |
| 702 JS.Node visitAssignmentExpression(AssignmentExpression node) { | 717 JS.Node visitAssignmentExpression(AssignmentExpression node) { |
| 703 var lhs = node.leftHandSide; | 718 var lhs = node.leftHandSide; |
| 704 var rhs = node.rightHandSide; | 719 var rhs = node.rightHandSide; |
| 720 return _emitAssignment(lhs, rhs, node.parent); |
| 721 } |
| 722 |
| 723 JS.Node _emitAssignment(Expression lhs, Expression rhs, [AstNode parent]) { |
| 705 if (lhs is IndexExpression) { | 724 if (lhs is IndexExpression) { |
| 706 String code; | 725 String code; |
| 707 var target = _getTarget(lhs); | 726 var target = _getTarget(lhs); |
| 708 if (rules.isDynamicTarget(target)) { | 727 if (rules.isDynamicTarget(target)) { |
| 709 code = 'dart.dsetindex(#, #, #)'; | 728 code = 'dart.dsetindex(#, #, #)'; |
| 710 } else { | 729 } else { |
| 711 code = '#.set(#, #)'; | 730 code = '#.set(#, #)'; |
| 712 } | 731 } |
| 713 return js.call(code, [_visit(target), _visit(lhs.index), _visit(rhs)]); | 732 return js.call(code, [_visit(target), _visit(lhs.index), _visit(rhs)]); |
| 714 } | 733 } |
| 715 | 734 |
| 716 if (lhs is PropertyAccess) { | 735 if (lhs is PropertyAccess) { |
| 717 var target = _getTarget(lhs); | 736 var result = _emitDPutIfDynamic(_getTarget(lhs), lhs.propertyName, rhs); |
| 718 if (rules.isDynamicTarget(target)) { | 737 if (result != null) return result; |
| 719 return js.call('dart.dput(#, #, #)', [ | 738 } else if (lhs is PrefixedIdentifier) { |
| 720 _visit(target), | 739 // TODO(vsm): Is this the right code if the prefix is a library? |
| 721 js.string(lhs.propertyName.name, "'"), | 740 var result = _emitDPutIfDynamic(lhs.prefix, lhs.identifier, rhs); |
| 722 _visit(rhs) | 741 if (result != null) return result; |
| 723 ]); | |
| 724 } | |
| 725 } | 742 } |
| 726 | 743 |
| 727 if (node.parent is ExpressionStatement && | 744 if (parent is ExpressionStatement && |
| 728 rhs is CascadeExpression && | 745 rhs is CascadeExpression && |
| 729 _isStateless(lhs, rhs)) { | 746 _isStateless(lhs, rhs)) { |
| 730 // Special case: cascade assignment to a variable in a statement. | 747 // Special case: cascade assignment to a variable in a statement. |
| 731 // We can reuse the variable to desugar it: | 748 // We can reuse the variable to desugar it: |
| 732 // result = []..length = length; | 749 // result = []..length = length; |
| 733 // becomes: | 750 // becomes: |
| 734 // result = []; | 751 // result = []; |
| 735 // result.length = length; | 752 // result.length = length; |
| 736 var savedCascadeTemp = _cascadeTarget; | 753 var savedCascadeTemp = _cascadeTarget; |
| 737 _cascadeTarget = lhs; | 754 _cascadeTarget = lhs; |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1162 ]); | 1179 ]); |
| 1163 } else { | 1180 } else { |
| 1164 // Generic static-dispatch, user-defined operator code path. | 1181 // Generic static-dispatch, user-defined operator code path. |
| 1165 return js.call('#.#(#)', [_visit(left), opString, _visit(right)]); | 1182 return js.call('#.#(#)', [_visit(left), opString, _visit(right)]); |
| 1166 } | 1183 } |
| 1167 } | 1184 } |
| 1168 } | 1185 } |
| 1169 | 1186 |
| 1170 bool _isNull(Expression expr) => expr is NullLiteral; | 1187 bool _isNull(Expression expr) => expr is NullLiteral; |
| 1171 | 1188 |
| 1189 // TODO(jmesserly, vsm): Refactor this logic. |
| 1190 SimpleIdentifier _createTemporary(String name, DartType type) { |
| 1191 var id = |
| 1192 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0)); |
| 1193 id.staticElement = new LocalVariableElementImpl.forNode(id); |
| 1194 id.staticType = type; |
| 1195 return id; |
| 1196 } |
| 1197 |
| 1198 JS.Expression _emitPostfixIncrement(Expression expr, Token op) { |
| 1199 var tmp = _createTemporary('\$tmp', rules.getStaticType(expr)); |
| 1200 |
| 1201 // Increment and write |
| 1202 var one = AstBuilder.integerLiteral(1); |
| 1203 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one); |
| 1204 var write = _emitAssignment(expr, increment); |
| 1205 |
| 1206 var bindThis = _maybeBindThis(expr); |
| 1207 return js.call("((#) => (#, #))$bindThis(#)", [ |
| 1208 tmp.name, |
| 1209 write, |
| 1210 _visit(tmp), |
| 1211 _visit(expr) |
| 1212 ]); |
| 1213 } |
| 1214 |
| 1172 @override | 1215 @override |
| 1173 JS.Expression visitPostfixExpression(PostfixExpression node) { | 1216 JS.Expression visitPostfixExpression(PostfixExpression node) { |
| 1174 var op = node.operator; | 1217 var op = node.operator; |
| 1175 var expr = node.operand; | 1218 var expr = node.operand; |
| 1176 | 1219 |
| 1177 var dispatchType = rules.getStaticType(expr); | 1220 var dispatchType = rules.getStaticType(expr); |
| 1178 if (unaryOperationIsPrimitive(dispatchType)) { | 1221 if (unaryOperationIsPrimitive(dispatchType)) { |
| 1179 // TODO(vsm): When do Dart ops not map to JS? | 1222 // TODO(vsm): When do Dart ops not map to JS? |
| 1180 return js.call('#$op', notNull(expr)); | 1223 return js.call('#$op', notNull(expr)); |
| 1181 } else { | 1224 } else { |
| 1182 // TODO(vsm): Figure out operator calling convention / dispatch. | 1225 assert(op.lexeme == '++' || op.lexeme == '--'); |
| 1183 return visitExpression(node); | 1226 return _emitPostfixIncrement(expr, op); |
| 1184 } | 1227 } |
| 1185 } | 1228 } |
| 1186 | 1229 |
| 1230 JS.Expression _emitPrefixIncrement(Token op, Expression expr) { |
| 1231 var one = AstBuilder.integerLiteral(1); |
| 1232 var increment = AstBuilder.binaryExpression(expr, op.lexeme[0], one); |
| 1233 return _emitAssignment(expr, increment); |
| 1234 } |
| 1235 |
| 1187 @override | 1236 @override |
| 1188 JS.Expression visitPrefixExpression(PrefixExpression node) { | 1237 JS.Expression visitPrefixExpression(PrefixExpression node) { |
| 1189 var op = node.operator; | 1238 var op = node.operator; |
| 1190 var expr = node.operand; | 1239 var expr = node.operand; |
| 1191 | 1240 |
| 1192 var dispatchType = rules.getStaticType(expr); | 1241 var dispatchType = rules.getStaticType(expr); |
| 1193 if (unaryOperationIsPrimitive(dispatchType)) { | 1242 if (unaryOperationIsPrimitive(dispatchType)) { |
| 1194 // TODO(vsm): When do Dart ops not map to JS? | 1243 // TODO(vsm): When do Dart ops not map to JS? |
| 1195 return js.call('$op#', notNull(expr)); | 1244 return js.call('$op#', notNull(expr)); |
| 1196 } else { | 1245 } else { |
| 1197 // TODO(vsm): Figure out operator calling convention / dispatch. | 1246 // Increment or decrement requires expansion |
| 1198 return visitExpression(node); | 1247 if (op.lexeme == '++' || op.lexeme == '--') { |
| 1248 return _emitPrefixIncrement(op, expr); |
| 1249 } |
| 1250 } |
| 1251 |
| 1252 // Call the operator |
| 1253 var opString = _jsMemberName(op.lexeme, unary: true); |
| 1254 if (rules.isDynamicTarget(expr)) { |
| 1255 // dynamic dispatch |
| 1256 return js.call('dart.dunary(#, #)', [opString, _visit(expr)]); |
| 1257 } else if (_isJSBuiltinType(dispatchType)) { |
| 1258 return js.call( |
| 1259 '#.#(#)', [_emitTypeName(dispatchType), opString, _visit(expr)]); |
| 1260 } else { |
| 1261 // Generic static-dispatch, user-defined operator code path. |
| 1262 return js.call('#.#()', [_visit(expr), opString]); |
| 1199 } | 1263 } |
| 1200 } | 1264 } |
| 1201 | 1265 |
| 1202 // Cascades can contain [IndexExpression], [MethodInvocation] and | 1266 // Cascades can contain [IndexExpression], [MethodInvocation] and |
| 1203 // [PropertyAccess]. The code generation for those is handled in their | 1267 // [PropertyAccess]. The code generation for those is handled in their |
| 1204 // respective visit methods. | 1268 // respective visit methods. |
| 1205 @override | 1269 @override |
| 1206 JS.Node visitCascadeExpression(CascadeExpression node) { | 1270 JS.Node visitCascadeExpression(CascadeExpression node) { |
| 1207 var savedCascadeTemp = _cascadeTarget; | 1271 var savedCascadeTemp = _cascadeTarget; |
| 1208 | 1272 |
| (...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1963 | 2027 |
| 1964 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2028 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 1965 printer.mark(_location(node.end)); | 2029 printer.mark(_location(node.end)); |
| 1966 } | 2030 } |
| 1967 | 2031 |
| 1968 String _getIdentifier(AstNode node) { | 2032 String _getIdentifier(AstNode node) { |
| 1969 if (node is SimpleIdentifier) return node.name; | 2033 if (node is SimpleIdentifier) return node.name; |
| 1970 return null; | 2034 return null; |
| 1971 } | 2035 } |
| 1972 } | 2036 } |
| OLD | NEW |