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: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; |
| (...skipping 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1058 | 1058 |
| 1059 bool typeIsNonNullablePrimitiveInJS(DartType t) => | 1059 bool typeIsNonNullablePrimitiveInJS(DartType t) => |
| 1060 typeIsPrimitiveInJS(t) && rules.isNonNullableType(t); | 1060 typeIsPrimitiveInJS(t) && rules.isNonNullableType(t); |
| 1061 | 1061 |
| 1062 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => | 1062 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => |
| 1063 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); | 1063 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); |
| 1064 | 1064 |
| 1065 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); | 1065 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); |
| 1066 | 1066 |
| 1067 bool _isNonNullableExpression(Expression expr) { | 1067 bool _isNonNullableExpression(Expression expr) { |
| 1068 // If the type is non-nullable, no further checking needed. | |
| 1069 if (rules.isNonNullableType(rules.getStaticType(expr))) return true; | |
| 1070 | |
| 1068 // TODO(vsm): Revisit whether we really need this when we get | 1071 // TODO(vsm): Revisit whether we really need this when we get |
| 1069 // better non-nullability in the type system. | 1072 // better non-nullability in the type system. |
| 1070 | 1073 |
| 1071 if (expr is Literal && expr is! NullLiteral) { | 1074 if (expr is Literal && expr is! NullLiteral) { |
| 1072 return true; | 1075 return true; |
| 1073 } | 1076 } |
| 1074 if (expr is ParenthesizedExpression) { | 1077 if (expr is ParenthesizedExpression) { |
| 1075 return _isNonNullableExpression(expr.expression); | 1078 return _isNonNullableExpression(expr.expression); |
| 1076 } | 1079 } |
| 1077 DartType type = null; | 1080 DartType type = null; |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 1105 if (!types.split('|').contains('Null')) { | 1108 if (!types.split('|').contains('Null')) { |
| 1106 return true; | 1109 return true; |
| 1107 } | 1110 } |
| 1108 } | 1111 } |
| 1109 } | 1112 } |
| 1110 } | 1113 } |
| 1111 return false; | 1114 return false; |
| 1112 } | 1115 } |
| 1113 | 1116 |
| 1114 JS.Expression notNull(Expression expr) { | 1117 JS.Expression notNull(Expression expr) { |
| 1115 var type = rules.getStaticType(expr); | 1118 if (_isNonNullableExpression(expr)) { |
| 1116 if (rules.isNonNullableType(type) || _isNonNullableExpression(expr)) { | |
| 1117 return _visit(expr); | 1119 return _visit(expr); |
| 1118 } else { | 1120 } else { |
| 1119 return js.call('dart.notNull(#)', _visit(expr)); | 1121 return js.call('dart.notNull(#)', _visit(expr)); |
| 1120 } | 1122 } |
| 1121 } | 1123 } |
| 1122 | 1124 |
| 1123 @override | 1125 @override |
| 1124 JS.Expression visitBinaryExpression(BinaryExpression node) { | 1126 JS.Expression visitBinaryExpression(BinaryExpression node) { |
| 1125 var op = node.operator; | 1127 var op = node.operator; |
| 1126 var left = node.leftOperand; | 1128 var left = node.leftOperand; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1189 // TODO(jmesserly, vsm): Refactor this logic. | 1191 // TODO(jmesserly, vsm): Refactor this logic. |
| 1190 SimpleIdentifier _createTemporary(String name, DartType type) { | 1192 SimpleIdentifier _createTemporary(String name, DartType type) { |
| 1191 var id = | 1193 var id = |
| 1192 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0)); | 1194 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, 0)); |
| 1193 id.staticElement = new LocalVariableElementImpl.forNode(id); | 1195 id.staticElement = new LocalVariableElementImpl.forNode(id); |
| 1194 id.staticType = type; | 1196 id.staticType = type; |
| 1195 return id; | 1197 return id; |
| 1196 } | 1198 } |
| 1197 | 1199 |
| 1198 JS.Expression _emitPostfixIncrement(Expression expr, Token op) { | 1200 JS.Expression _emitPostfixIncrement(Expression expr, Token op) { |
| 1199 var tmp = _createTemporary('\$tmp', rules.getStaticType(expr)); | 1201 var type = rules.getStaticType(expr); |
| 1202 assert(type != null); | |
| 1203 var tmp = _createTemporary('\$tmp', type); | |
| 1200 | 1204 |
| 1201 // Increment and write | 1205 // Increment and write |
| 1202 var one = AstBuilder.integerLiteral(1); | 1206 var one = AstBuilder.integerLiteral(1); |
| 1207 one.staticType = rules.provider.intType; | |
| 1203 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one); | 1208 var increment = AstBuilder.binaryExpression(tmp, op.lexeme[0], one); |
| 1209 increment.staticType = type; | |
| 1204 var write = _emitAssignment(expr, increment); | 1210 var write = _emitAssignment(expr, increment); |
| 1205 | 1211 |
| 1206 var bindThis = _maybeBindThis(expr); | 1212 var bindThis = _maybeBindThis(expr); |
| 1207 return js.call("((#) => (#, #))$bindThis(#)", [ | 1213 return js.call("((#) => (#, #))$bindThis(#)", [ |
| 1208 tmp.name, | 1214 tmp.name, |
| 1209 write, | 1215 write, |
| 1210 _visit(tmp), | 1216 _visit(tmp), |
| 1211 _visit(expr) | 1217 _visit(expr) |
| 1212 ]); | 1218 ]); |
| 1213 } | 1219 } |
| 1214 | 1220 |
| 1215 @override | 1221 @override |
| 1216 JS.Expression visitPostfixExpression(PostfixExpression node) { | 1222 JS.Expression visitPostfixExpression(PostfixExpression node) { |
| 1217 var op = node.operator; | 1223 var op = node.operator; |
| 1218 var expr = node.operand; | 1224 var expr = node.operand; |
| 1219 | 1225 |
| 1226 if (node.parent is Statement) { | |
| 1227 // Prefix code is simpler. If the expr result isn't used, fall to that. | |
| 1228 return _emitPrefixExpression(op, expr); | |
| 1229 } | |
| 1230 | |
| 1220 var dispatchType = rules.getStaticType(expr); | 1231 var dispatchType = rules.getStaticType(expr); |
| 1221 if (unaryOperationIsPrimitive(dispatchType)) { | 1232 if (unaryOperationIsPrimitive(dispatchType)) { |
| 1222 // TODO(vsm): When do Dart ops not map to JS? | 1233 if (_isNonNullableExpression(expr)) { |
| 1223 return js.call('#$op', notNull(expr)); | 1234 return js.call('#$op', _visit(expr)); |
| 1224 } else { | 1235 } |
| 1225 assert(op.lexeme == '++' || op.lexeme == '--'); | |
| 1226 return _emitPostfixIncrement(expr, op); | |
| 1227 } | 1236 } |
| 1237 | |
| 1238 assert(op.lexeme == '++' || op.lexeme == '--'); | |
| 1239 return _emitPostfixIncrement(expr, op); | |
| 1228 } | 1240 } |
| 1229 | 1241 |
| 1230 JS.Expression _emitPrefixIncrement(Token op, Expression expr) { | 1242 JS.Expression _emitPrefixIncrement(Token op, Expression expr) { |
| 1231 var one = AstBuilder.integerLiteral(1); | 1243 var one = AstBuilder.integerLiteral(1); |
| 1232 var increment = AstBuilder.binaryExpression(expr, op.lexeme[0], one); | 1244 var increment = AstBuilder.binaryExpression(expr, op.lexeme[0], one); |
| 1233 return _emitAssignment(expr, increment); | 1245 return _emitAssignment(expr, increment); |
| 1234 } | 1246 } |
| 1235 | 1247 |
| 1236 @override | 1248 @override |
| 1237 JS.Expression visitPrefixExpression(PrefixExpression node) { | 1249 JS.Expression visitPrefixExpression(PrefixExpression node) { |
| 1238 var op = node.operator; | 1250 var op = node.operator; |
|
Jennifer Messerly
2015/03/04 20:08:47
I might be tempted to get rid of these assignments
vsm
2015/03/04 20:55:56
Done.
| |
| 1239 var expr = node.operand; | 1251 var expr = node.operand; |
| 1252 return _emitPrefixExpression(op, expr); | |
| 1253 } | |
| 1240 | 1254 |
| 1255 JS.Expression _emitPrefixExpression(Token op, Expression expr) { | |
| 1241 var dispatchType = rules.getStaticType(expr); | 1256 var dispatchType = rules.getStaticType(expr); |
| 1242 if (unaryOperationIsPrimitive(dispatchType)) { | 1257 if (unaryOperationIsPrimitive(dispatchType)) { |
| 1243 // TODO(vsm): When do Dart ops not map to JS? | 1258 if (_isNonNullableExpression(expr)) { |
| 1244 return js.call('$op#', notNull(expr)); | 1259 return js.call('$op#', _visit(expr)); |
| 1260 } else if (op.lexeme == '++' || op.lexeme == '--') { | |
| 1261 // We need a null check, so the increment must be expanded out. | |
| 1262 var mathop = op.lexeme[0]; | |
| 1263 return js.call('# = # $mathop 1', [_visit(expr), notNull(expr)]); | |
| 1264 } else { | |
| 1265 return js.call('$op#', notNull(expr)); | |
| 1266 } | |
| 1245 } else { | 1267 } else { |
| 1246 // Increment or decrement requires expansion | 1268 // Increment or decrement requires expansion. |
| 1247 if (op.lexeme == '++' || op.lexeme == '--') { | 1269 if (op.lexeme == '++' || op.lexeme == '--') { |
| 1248 return _emitPrefixIncrement(op, expr); | 1270 return _emitPrefixIncrement(op, expr); |
| 1249 } | 1271 } |
| 1250 } | 1272 } |
| 1251 | 1273 |
| 1252 // Call the operator | 1274 // Call the operator |
| 1253 var opString = _jsMemberName(op.lexeme, unary: true); | 1275 var opString = _jsMemberName(op.lexeme, unary: true); |
| 1254 if (rules.isDynamicTarget(expr)) { | 1276 if (rules.isDynamicTarget(expr)) { |
| 1255 // dynamic dispatch | 1277 // dynamic dispatch |
| 1256 return js.call('dart.dunary(#, #)', [opString, _visit(expr)]); | 1278 return js.call('dart.dunary(#, #)', [opString, _visit(expr)]); |
| (...skipping 764 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2021 | 2043 |
| 2022 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2044 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 2023 printer.mark(_location(node.end)); | 2045 printer.mark(_location(node.end)); |
| 2024 } | 2046 } |
| 2025 | 2047 |
| 2026 String _getIdentifier(AstNode node) { | 2048 String _getIdentifier(AstNode node) { |
| 2027 if (node is SimpleIdentifier) return node.name; | 2049 if (node is SimpleIdentifier) return node.name; |
| 2028 return null; | 2050 return null; |
| 2029 } | 2051 } |
| 2030 } | 2052 } |
| OLD | NEW |