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

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: Revert runtime changes 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 | « no previous file | 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;
(...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 } else { 691 } else {
692 result = new JS.VariableUse(name); 692 result = new JS.VariableUse(name);
693 } 693 }
694 694
695 if (typeArgs != null) { 695 if (typeArgs != null) {
696 result = js.call('#(#)', [result, typeArgs]); 696 result = js.call('#(#)', [result, typeArgs]);
697 } 697 }
698 return result; 698 return result;
699 } 699 }
700 700
701 JS.Node _emitDPutIfDynamic(
702 Expression target, SimpleIdentifier id, Expression rhs) {
703 if (rules.isDynamicTarget(target)) {
704 return js.call('dart.dput(#, #, #)', [
705 _visit(target),
706 js.string(id.name, "'"),
707 _visit(rhs)
708 ]);
709 } else {
710 return null;
711 }
712 }
713
701 @override 714 @override
702 JS.Node visitAssignmentExpression(AssignmentExpression node) { 715 JS.Node visitAssignmentExpression(AssignmentExpression node) {
703 var lhs = node.leftHandSide; 716 var lhs = node.leftHandSide;
704 var rhs = node.rightHandSide; 717 var rhs = node.rightHandSide;
718 return _emitAssignment(lhs, rhs, node.parent);
719 }
720
721 JS.Node _emitAssignment(Expression lhs, Expression rhs, [AstNode parent]) {
705 if (lhs is IndexExpression) { 722 if (lhs is IndexExpression) {
706 String code; 723 String code;
707 var target = _getTarget(lhs); 724 var target = _getTarget(lhs);
708 if (rules.isDynamicTarget(target)) { 725 if (rules.isDynamicTarget(target)) {
709 code = 'dart.dsetindex(#, #, #)'; 726 code = 'dart.dsetindex(#, #, #)';
710 } else { 727 } else {
711 code = '#.set(#, #)'; 728 code = '#.set(#, #)';
712 } 729 }
713 return js.call(code, [_visit(target), _visit(lhs.index), _visit(rhs)]); 730 return js.call(code, [_visit(target), _visit(lhs.index), _visit(rhs)]);
714 } 731 }
715 732
716 if (lhs is PropertyAccess) { 733 if (lhs is PropertyAccess) {
717 var target = _getTarget(lhs); 734 var result = _emitDPutIfDynamic(_getTarget(lhs), lhs.propertyName, rhs);
718 if (rules.isDynamicTarget(target)) { 735 if (result != null) return result;
719 return js.call('dart.dput(#, #, #)', [ 736 } else if (lhs is PrefixedIdentifier) {
720 _visit(target), 737 // TODO(vsm): Is this the right code if the prefix is a library?
Jennifer Messerly 2015/03/04 01:09:31 how can this happen? I don't think PrefixedIdentif
Siggi Cherem (dart-lang) 2015/03/04 03:56:07 My understanding is that PrefixedIdentifier is use
721 js.string(lhs.propertyName.name, "'"), 738 var result = _emitDPutIfDynamic(lhs.prefix, lhs.identifier, rhs);
722 _visit(rhs) 739 if (result != null) return result;
723 ]);
724 }
725 } 740 }
726 741
727 if (node.parent is ExpressionStatement && 742 if (parent is ExpressionStatement &&
728 rhs is CascadeExpression && 743 rhs is CascadeExpression &&
729 _isStateless(lhs, rhs)) { 744 _isStateless(lhs, rhs)) {
730 // Special case: cascade assignment to a variable in a statement. 745 // Special case: cascade assignment to a variable in a statement.
731 // We can reuse the variable to desugar it: 746 // We can reuse the variable to desugar it:
732 // result = []..length = length; 747 // result = []..length = length;
733 // becomes: 748 // becomes:
734 // result = []; 749 // result = [];
735 // result.length = length; 750 // result.length = length;
736 var savedCascadeTemp = _cascadeTarget; 751 var savedCascadeTemp = _cascadeTarget;
737 _cascadeTarget = lhs; 752 _cascadeTarget = lhs;
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after
1162 ]); 1177 ]);
1163 } else { 1178 } else {
1164 // Generic static-dispatch, user-defined operator code path. 1179 // Generic static-dispatch, user-defined operator code path.
1165 return js.call('#.#(#)', [_visit(left), opString, _visit(right)]); 1180 return js.call('#.#(#)', [_visit(left), opString, _visit(right)]);
1166 } 1181 }
1167 } 1182 }
1168 } 1183 }
1169 1184
1170 bool _isNull(Expression expr) => expr is NullLiteral; 1185 bool _isNull(Expression expr) => expr is NullLiteral;
1171 1186
1187 JS.Expression _emitIncrement(Token op, Expression expr, {bool prefix}) {
1188 assert(prefix != null);
1189
1190 // TODO(vsm): If the expression has a side effect, we need something differe nt.
Jennifer Messerly 2015/03/04 01:09:31 long line
vsm 2015/03/04 14:59:27 removed
1191 if (!_isStateless(expr) &&
vsm 2015/03/04 00:54:21 Actually, I think this is unnecessary...
Jennifer Messerly 2015/03/04 01:09:31 right, your temps are handling this? consider `fo
vsm 2015/03/04 14:59:27 right
1192 (expr is! SimpleIdentifier ||
1193 (expr as SimpleIdentifier).staticElement is! LocalVariableElement)) {
1194 return null;
1195 }
1196
1197 // TODO(vsm): Should we generate a runtime helper for this?
1198 var tmp = '_';
1199 var applied = prefix ? '$tmp$op' : '$op$tmp';
vsm 2015/03/04 00:54:21 This might not be a number. I'll change this to c
Jennifer Messerly 2015/03/04 01:09:31 yeah. ideally it could "desugar" to `expr += 1`, a
vsm 2015/03/04 14:59:27 mapping to x = x + 1 for now, but yeah.
1200 var id =
1201 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, tmp, 0));
1202 id.staticElement = new LocalVariableElementImpl.forNode(id);
1203 id.staticType = expr.staticType;
1204 var assignment = _emitAssignment(expr, id);
1205 return js.call('''
1206 (function () {
1207 var $tmp = #;
1208 if (typeof($tmp) != 'number') throw 'number expected';
1209 var result = $applied;
1210 #;
1211 return result;
1212 })()
1213 ''', [expr.accept(this), assignment]);
1214 }
1215
1172 @override 1216 @override
1173 JS.Expression visitPostfixExpression(PostfixExpression node) { 1217 JS.Expression visitPostfixExpression(PostfixExpression node) {
1174 var op = node.operator; 1218 var op = node.operator;
1175 var expr = node.operand; 1219 var expr = node.operand;
1176 1220
1177 var dispatchType = rules.getStaticType(expr); 1221 var dispatchType = rules.getStaticType(expr);
1178 if (unaryOperationIsPrimitive(dispatchType)) { 1222 if (unaryOperationIsPrimitive(dispatchType)) {
1179 // TODO(vsm): When do Dart ops not map to JS? 1223 // TODO(vsm): When do Dart ops not map to JS?
1180 return js.call('#$op', notNull(expr)); 1224 return js.call('#$op', notNull(expr));
1181 } else { 1225 } else {
1182 // TODO(vsm): Figure out operator calling convention / dispatch. 1226 assert(op.lexeme == '++' || op.lexeme == '--');
1183 return visitExpression(node); 1227 var result = _emitIncrement(op, expr, prefix: false);
1228 return (result != null) ? result : visitExpression(node);
1184 } 1229 }
1185 } 1230 }
1186 1231
1187 @override 1232 @override
1188 JS.Expression visitPrefixExpression(PrefixExpression node) { 1233 JS.Expression visitPrefixExpression(PrefixExpression node) {
1189 var op = node.operator; 1234 var op = node.operator;
1190 var expr = node.operand; 1235 var expr = node.operand;
1191 1236
1192 var dispatchType = rules.getStaticType(expr); 1237 var dispatchType = rules.getStaticType(expr);
1193 if (unaryOperationIsPrimitive(dispatchType)) { 1238 if (unaryOperationIsPrimitive(dispatchType)) {
1194 // TODO(vsm): When do Dart ops not map to JS? 1239 // TODO(vsm): When do Dart ops not map to JS?
1195 return js.call('$op#', notNull(expr)); 1240 return js.call('$op#', notNull(expr));
1196 } else { 1241 } else {
1197 // TODO(vsm): Figure out operator calling convention / dispatch. 1242 // Increment or decrement must be numerical
1198 return visitExpression(node); 1243 if (op.lexeme == '++' || op.lexeme == '--') {
1244 var result = _emitIncrement(op, expr, prefix: true);
1245 return (result != null) ? result : visitExpression(node);
1246 }
1247 }
1248 // TODO(vsm): Statically invoke the operator if the type is known.
1249 // Fall back to dynamic dispatch.
1250 var opString = _jsMemberName(op.lexeme, unary: true);
1251 if (rules.isDynamicTarget(expr)) {
1252 // dynamic dispatch
1253 return js.call('dart.dunary(#, #)', [opString, _visit(expr)]);
1254 } else if (_isJSBuiltinType(dispatchType)) {
1255 return js.call(
1256 '#.#(#)', [_emitTypeName(dispatchType), opString, _visit(expr)]);
1257 } else {
1258 // Generic static-dispatch, user-defined operator code path.
1259 return js.call('#.#()', [_visit(expr), opString]);
1199 } 1260 }
1200 } 1261 }
1201 1262
1202 // Cascades can contain [IndexExpression], [MethodInvocation] and 1263 // Cascades can contain [IndexExpression], [MethodInvocation] and
1203 // [PropertyAccess]. The code generation for those is handled in their 1264 // [PropertyAccess]. The code generation for those is handled in their
1204 // respective visit methods. 1265 // respective visit methods.
1205 @override 1266 @override
1206 JS.Node visitCascadeExpression(CascadeExpression node) { 1267 JS.Node visitCascadeExpression(CascadeExpression node) {
1207 var savedCascadeTemp = _cascadeTarget; 1268 var savedCascadeTemp = _cascadeTarget;
1208 1269
(...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after
1963 2024
1964 // TODO(jmesserly): in many cases marking the end will be unncessary. 2025 // TODO(jmesserly): in many cases marking the end will be unncessary.
1965 printer.mark(_location(node.end)); 2026 printer.mark(_location(node.end));
1966 } 2027 }
1967 2028
1968 String _getIdentifier(AstNode node) { 2029 String _getIdentifier(AstNode node) {
1969 if (node is SimpleIdentifier) return node.name; 2030 if (node is SimpleIdentifier) return node.name;
1970 return null; 2031 return null;
1971 } 2032 }
1972 } 2033 }
OLDNEW
« no previous file with comments | « no previous file | test/codegen/expect/dart/_interceptors.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698