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

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: Fix ++ and -- 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?
Jennifer Messerly 2015/03/04 16:03:51 ah, I think the PrefixedIdentifier branch makes se
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 JS.Expression _emitIncrement(Token op, Expression expr, {bool prefix}) {
1190 assert(prefix != null);
1191
1192 // TODO(vsm): Avoid collisions.
1193 var tmp1 = '_t1';
Jennifer Messerly 2015/03/04 16:03:51 so far we've been using `$` for compiler generated
vsm 2015/03/04 17:55:30 Done.
1194 var tmp2 = '_t2';
1195
1196 // Read
1197 var read = _visit(expr);
1198
1199 // Increment
1200 var one = AstBuilder.integerLiteral(1);
1201 var binary = AstBuilder.binaryExpression(expr, op.lexeme[0], one);
Jennifer Messerly 2015/03/04 16:03:51 hmmm. Should this be `id` instead of `expr` as the
vsm 2015/03/04 17:55:30 good catch! fixed.
1202 var increment = _visit(binary);
Jennifer Messerly 2015/03/04 16:03:51 this could be directly `visitBinaryExpression` sin
vsm 2015/03/04 17:55:30 This ends up being a little complicated. I'm feed
1203
1204 // Write
1205 var id =
1206 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, tmp1, 0));
Jennifer Messerly 2015/03/04 16:03:51 maybe a TODO: I think we had to do something simil
vsm 2015/03/04 17:55:30 I factored this out a bit.
1207 id.staticElement = new LocalVariableElementImpl.forNode(id);
1208 id.staticType = expr.staticType;
1209 var write = _emitAssignment(expr, id);
1210
1211 return js.call('''
1212 (function () {
Jennifer Messerly 2015/03/04 16:03:51 I think you want an `=>` function here. Otherwise
1213 var $tmp1 = #;
Jennifer Messerly 2015/03/04 16:03:51 one warning I got from Stephen was to make sure to
1214 var $tmp2 = #;
1215 #;
1216 return ${prefix ? tmp2 : tmp1};
Jennifer Messerly 2015/03/04 16:03:51 hmmm, I wonder if we can do better for prefix and
vsm 2015/03/04 17:55:30 Nice idea! I will try this. In the postfix, dyna
1217 })()
1218 ''', [read, increment, write]);
1219 }
1220
1172 @override 1221 @override
1173 JS.Expression visitPostfixExpression(PostfixExpression node) { 1222 JS.Expression visitPostfixExpression(PostfixExpression node) {
1174 var op = node.operator; 1223 var op = node.operator;
1175 var expr = node.operand; 1224 var expr = node.operand;
1176 1225
1177 var dispatchType = rules.getStaticType(expr); 1226 var dispatchType = rules.getStaticType(expr);
1178 if (unaryOperationIsPrimitive(dispatchType)) { 1227 if (unaryOperationIsPrimitive(dispatchType)) {
1179 // TODO(vsm): When do Dart ops not map to JS? 1228 // TODO(vsm): When do Dart ops not map to JS?
1180 return js.call('#$op', notNull(expr)); 1229 return js.call('#$op', notNull(expr));
1181 } else { 1230 } else {
1182 // TODO(vsm): Figure out operator calling convention / dispatch. 1231 assert(op.lexeme == '++' || op.lexeme == '--');
1183 return visitExpression(node); 1232 var result = _emitIncrement(op, expr, prefix: false);
1233 return (result != null) ? result : visitExpression(node);
1184 } 1234 }
1185 } 1235 }
1186 1236
1187 @override 1237 @override
1188 JS.Expression visitPrefixExpression(PrefixExpression node) { 1238 JS.Expression visitPrefixExpression(PrefixExpression node) {
1189 var op = node.operator; 1239 var op = node.operator;
1190 var expr = node.operand; 1240 var expr = node.operand;
1191 1241
1192 var dispatchType = rules.getStaticType(expr); 1242 var dispatchType = rules.getStaticType(expr);
1193 if (unaryOperationIsPrimitive(dispatchType)) { 1243 if (unaryOperationIsPrimitive(dispatchType)) {
1194 // TODO(vsm): When do Dart ops not map to JS? 1244 // TODO(vsm): When do Dart ops not map to JS?
1195 return js.call('$op#', notNull(expr)); 1245 return js.call('$op#', notNull(expr));
1196 } else { 1246 } else {
1197 // TODO(vsm): Figure out operator calling convention / dispatch. 1247 // Increment or decrement must be numerical
1198 return visitExpression(node); 1248 if (op.lexeme == '++' || op.lexeme == '--') {
1249 var result = _emitIncrement(op, expr, prefix: true);
1250 return (result != null) ? result : visitExpression(node);
1251 }
1252 }
1253 // TODO(vsm): Statically invoke the operator if the type is known.
1254 // Fall back to dynamic dispatch.
1255 var opString = _jsMemberName(op.lexeme, unary: true);
1256 if (rules.isDynamicTarget(expr)) {
1257 // dynamic dispatch
1258 return js.call('dart.dunary(#, #)', [opString, _visit(expr)]);
1259 } else if (_isJSBuiltinType(dispatchType)) {
1260 return js.call(
1261 '#.#(#)', [_emitTypeName(dispatchType), opString, _visit(expr)]);
1262 } else {
1263 // Generic static-dispatch, user-defined operator code path.
1264 return js.call('#.#()', [_visit(expr), opString]);
1199 } 1265 }
1200 } 1266 }
1201 1267
1202 // Cascades can contain [IndexExpression], [MethodInvocation] and 1268 // Cascades can contain [IndexExpression], [MethodInvocation] and
1203 // [PropertyAccess]. The code generation for those is handled in their 1269 // [PropertyAccess]. The code generation for those is handled in their
1204 // respective visit methods. 1270 // respective visit methods.
1205 @override 1271 @override
1206 JS.Node visitCascadeExpression(CascadeExpression node) { 1272 JS.Node visitCascadeExpression(CascadeExpression node) {
1207 var savedCascadeTemp = _cascadeTarget; 1273 var savedCascadeTemp = _cascadeTarget;
1208 1274
(...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after
1963 2029
1964 // TODO(jmesserly): in many cases marking the end will be unncessary. 2030 // TODO(jmesserly): in many cases marking the end will be unncessary.
1965 printer.mark(_location(node.end)); 2031 printer.mark(_location(node.end));
1966 } 2032 }
1967 2033
1968 String _getIdentifier(AstNode node) { 2034 String _getIdentifier(AstNode node) {
1969 if (node is SimpleIdentifier) return node.name; 2035 if (node is SimpleIdentifier) return node.name;
1970 return null; 2036 return null;
1971 } 2037 }
1972 } 2038 }
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