Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 961513002: Flesh out dynamic invocation code (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Streamline ++ and -- in fallback case Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/codegen/ast_builder.dart ('k') | test/codegen/expect/dart/_interceptors.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « lib/src/codegen/ast_builder.dart ('k') | test/codegen/expect/dart/_interceptors.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698