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

Side by Side Diff: pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart

Issue 1088493002: Assignment expressions in tree IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Comments Created 5 years, 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 backend_ast_emitter; 5 library backend_ast_emitter;
6 6
7 import '../tree_ir/tree_ir_nodes.dart' as tree; 7 import '../tree_ir/tree_ir_nodes.dart' as tree;
8 import 'backend_ast_nodes.dart'; 8 import 'backend_ast_nodes.dart';
9 import '../constants/expressions.dart'; 9 import '../constants/expressions.dart';
10 import '../constants/values.dart'; 10 import '../constants/values.dart';
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 if (variable.element == null || name != variable.element.name) { 135 if (variable.element == null || name != variable.element.name) {
136 // TODO(johnniwinther): Replace by synthetic [Entity]. 136 // TODO(johnniwinther): Replace by synthetic [Entity].
137 variable.element = new _SyntheticLocalVariableElement( 137 variable.element = new _SyntheticLocalVariableElement(
138 name, 138 name,
139 currentElement, 139 currentElement,
140 variableList); 140 variableList);
141 } 141 }
142 return name; 142 return name;
143 } 143 }
144 144
145 /// Adds declarations for all variables that are still undeclared.
146 void declareRemainingVariables() {
147 // These variables can be referenced from other variable initializers if
148 // they are set by an assignment expression, so we declare variables before
149 // those with initializers.
150 List<VariableDeclaration> declarations = <VariableDeclaration>[];
151 for (tree.Variable variable in variableNames.keys) {
152 if (!declaredVariables.contains(variable)) {
153 String name = getVariableName(variable);
154 VariableDeclaration decl = new VariableDeclaration(name);
155 decl.element = variable.element;
156 declarations.add(decl);
157 declaredVariables.add(variable);
158 }
159 }
160 // Prepend all variables at once to avoid quadratic blowup.
161 variables.insertAll(0, declarations);
162 }
163
145 String getConstantName(VariableElement element) { 164 String getConstantName(VariableElement element) {
146 assert(element.kind == ElementKind.VARIABLE); 165 assert(element.kind == ElementKind.VARIABLE);
147 if (element.enclosingElement != currentElement) { 166 if (element.enclosingElement != currentElement) {
148 return _parent.getConstantName(element); 167 return _parent.getConstantName(element);
149 } 168 }
150 String name = constantNames[element]; 169 String name = constantNames[element];
151 if (name != null) { 170 if (name != null) {
152 return name; 171 return name;
153 } 172 }
154 String prefix = element.name; 173 String prefix = element.name;
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 return visitInitializer(initializer, context); 313 return visitInitializer(initializer, context);
295 }).toList(); 314 }).toList();
296 315
297 context.firstStatement = definition.body; 316 context.firstStatement = definition.body;
298 visitStatement(definition.body, context); 317 visitStatement(definition.body, context);
299 context.removeTrailingReturn(_recognizeTrailingReturn); 318 context.removeTrailingReturn(_recognizeTrailingReturn);
300 319
301 // Some of the variable declarations have already been added 320 // Some of the variable declarations have already been added
302 // if their first assignment could be pulled into the initializer. 321 // if their first assignment could be pulled into the initializer.
303 // Add the remaining variable declarations now. 322 // Add the remaining variable declarations now.
304 for (tree.Variable variable in context.variableNames.keys) { 323 context.declareRemainingVariables();
305 if (!context.declaredVariables.contains(variable)) {
306 context.addDeclaration(variable);
307 }
308 }
309 324
310 // Add constant declarations. 325 // Add constant declarations.
311 List<VariableDeclaration> constants = <VariableDeclaration>[]; 326 List<VariableDeclaration> constants = <VariableDeclaration>[];
312 for (ConstDeclaration constDecl in definition.localConstants) { 327 for (ConstDeclaration constDecl in definition.localConstants) {
313 if (!context.constantNames.containsKey(constDecl.element)) { 328 if (!context.constantNames.containsKey(constDecl.element)) {
314 continue; // Discard unused constants declarations. 329 continue; // Discard unused constants declarations.
315 } 330 }
316 String name = context.getConstantName(constDecl.element); 331 String name = context.getConstantName(constDecl.element);
317 Expression value = 332 Expression value =
318 ConstantEmitter.createExpression(constDecl.expression, context); 333 ConstantEmitter.createExpression(constDecl.expression, context);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 if (definition.isEmpty) { 378 if (definition.isEmpty) {
364 body = new EmptyStatement(); 379 body = new EmptyStatement();
365 } else { 380 } else {
366 context.firstStatement = definition.body; 381 context.firstStatement = definition.body;
367 visitStatement(definition.body, context); 382 visitStatement(definition.body, context);
368 context.removeTrailingReturn(_recognizeTrailingReturn); 383 context.removeTrailingReturn(_recognizeTrailingReturn);
369 384
370 // Some of the variable declarations have already been added 385 // Some of the variable declarations have already been added
371 // if their first assignment could be pulled into the initializer. 386 // if their first assignment could be pulled into the initializer.
372 // Add the remaining variable declarations now. 387 // Add the remaining variable declarations now.
373 for (tree.Variable variable in context.variableNames.keys) { 388 context.declareRemainingVariables();
374 if (!context.declaredVariables.contains(variable) &&
375 !context.handlerVariables.contains(variable)) {
376 context.addDeclaration(variable);
377 }
378 }
379 389
380 // Add constant declarations. 390 // Add constant declarations.
381 List<VariableDeclaration> constants = <VariableDeclaration>[]; 391 List<VariableDeclaration> constants = <VariableDeclaration>[];
382 for (ConstDeclaration constDecl in definition.localConstants) { 392 for (ConstDeclaration constDecl in definition.localConstants) {
383 if (!context.constantNames.containsKey(constDecl.element)) { 393 if (!context.constantNames.containsKey(constDecl.element)) {
384 continue; // Discard unused constants declarations. 394 continue; // Discard unused constants declarations.
385 } 395 }
386 String name = context.getConstantName(constDecl.element); 396 String name = context.getConstantName(constDecl.element);
387 Expression value = 397 Expression value =
388 ConstantEmitter.createExpression(constDecl.expression, context); 398 ConstantEmitter.createExpression(constDecl.expression, context);
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 if (context.removeUsedLabel(label)) { 501 if (context.removeUsedLabel(label)) {
492 context.addStatement(new LabeledStatement(label.name, statement)); 502 context.addStatement(new LabeledStatement(label.name, statement));
493 } else { 503 } else {
494 context.addStatement(statement); 504 context.addStatement(statement);
495 } 505 }
496 } 506 }
497 507
498 @override 508 @override
499 void visitExpressionStatement(tree.ExpressionStatement stmt, 509 void visitExpressionStatement(tree.ExpressionStatement stmt,
500 BuilderContext<Statement> context) { 510 BuilderContext<Statement> context) {
511 if (stmt.expression is tree.Assign) {
512 emitAssignStatement(stmt.expression, stmt, context);
513 return;
514 }
501 Expression e = visitExpression(stmt.expression, context); 515 Expression e = visitExpression(stmt.expression, context);
502 context.addStatement(new ExpressionStatement(e)); 516 context.addStatement(new ExpressionStatement(e));
517 visitStatement(stmt.next, context);
518 }
503 519
504 visitStatement(stmt.next, context); 520 @override
521 void visitVariableDeclaration(tree.VariableDeclaration node,
522 BuilderContext<Statement> context) {
523 Expression value = visitExpression(node.value, context);
524 String name = context.getVariableName(node.variable);
525 VariableDeclaration decl = new VariableDeclaration(name, value)
526 ..element = node.variable.element;
527 context.declaredVariables.add(node.variable);
528 context.addStatement(new VariableDeclarations([decl]));
529 visitStatement(node.next, context);
505 } 530 }
506 531
507 @override 532 @override
508 void visitLabeledStatement(tree.LabeledStatement stmt, 533 void visitLabeledStatement(tree.LabeledStatement stmt,
509 BuilderContext<Statement> context) { 534 BuilderContext<Statement> context) {
510 Block block = visitInSubContext(stmt.body, context, fallthrough: stmt.next); 535 Block block = visitInSubContext(stmt.body, context, fallthrough: stmt.next);
511 addLabeledStatement(stmt.label, block, context); 536 addLabeledStatement(stmt.label, block, context);
512 537
513 visitStatement(stmt.next, context); 538 visitStatement(stmt.next, context);
514 } 539 }
515 540
516 bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull; 541 bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull;
517 542
518 @override 543 void emitAssignStatement(tree.Assign assign,
519 void visitAssign(tree.Assign stmt, 544 tree.Statement statement,
520 BuilderContext<Statement> context) { 545 BuilderContext<Statement> context) {
521 // Try to emit a local function declaration. This is useful for functions 546 // Try to emit a local function declaration. This is useful for functions
522 // that may occur in expression context, but could not be inlined anywhere. 547 // that may occur in expression context, but could not be inlined anywhere.
523 if (stmt.variable.element is FunctionElement && 548 if (assign.variable.element is FunctionElement &&
524 stmt.value is tree.FunctionExpression && 549 assign.value is tree.FunctionExpression &&
525 !context.declaredVariables.contains(stmt.variable) && 550 !context.declaredVariables.contains(assign.variable) &&
526 stmt.variable.writeCount == 1) { 551 assign.variable.writeCount == 1) {
527 tree.FunctionExpression functionExp = stmt.value; 552 tree.FunctionExpression functionExp = assign.value;
528 FunctionExpression function = 553 FunctionExpression function =
529 makeSubFunction(functionExp.definition, context); 554 makeSubFunction(functionExp.definition, context);
530 FunctionDeclaration decl = new FunctionDeclaration(function); 555 FunctionDeclaration decl = new FunctionDeclaration(function);
531 context.addStatement(decl); 556 context.addStatement(decl);
532 context.declaredVariables.add(stmt.variable); 557 context.declaredVariables.add(assign.variable);
533 558
534 visitStatement(stmt.next, context); 559 visitStatement(statement.next, context);
535 return; 560 return;
536 } 561 }
537 562
538 bool isFirstOccurrence = (context.variableNames[stmt.variable] == null); 563 Expression definition = visitExpression(assign.value, context);
539 bool isDeclaredHere = stmt.variable.host == context.currentElement; 564 bool isFirstOccurrence = (context.variableNames[assign.variable] == null);
540 String name = context.getVariableName(stmt.variable); 565 bool isDeclaredHere = assign.variable.host == context.currentElement;
541 Expression definition = visitExpression(stmt.value, context); 566 bool isFirstStatement = context.firstStatement == statement;
567 String name = context.getVariableName(assign.variable);
542 568
543 // Try to pull into initializer. 569 // Try to pull into initializer.
544 if (context.firstStatement == stmt && isFirstOccurrence && isDeclaredHere) { 570 if (isFirstStatement && isFirstOccurrence && isDeclaredHere) {
545 if (isNullLiteral(definition)) definition = null; 571 if (isNullLiteral(definition)) definition = null;
546 context.addDeclaration(stmt.variable, definition); 572 context.addDeclaration(assign.variable, definition);
547 context.firstStatement = stmt.next; 573 context.firstStatement = statement.next;
548 visitStatement(stmt.next, context); 574 visitStatement(statement.next, context);
549 return;
550 }
551
552 // Emit a variable declaration if we are required to do so.
553 // For captured variables, this ensures that a fresh variable is created.
554 if (stmt.isDeclaration) {
555 assert(isFirstOccurrence);
556 assert(isDeclaredHere);
557 if (isNullLiteral(definition)) definition = null;
558 VariableDeclaration decl = new VariableDeclaration(name, definition)
559 ..element = stmt.variable.element;
560 context.declaredVariables.add(stmt.variable);
561 context.addStatement(new VariableDeclarations([decl]));
562 visitStatement(stmt.next, context);
563 return; 575 return;
564 } 576 }
565 577
566 context.addStatement(new ExpressionStatement(makeAssignment( 578 context.addStatement(new ExpressionStatement(makeAssignment(
567 context.makeVariableAccess(stmt.variable), 579 context.makeVariableAccess(assign.variable),
568 definition))); 580 definition)));
569 visitStatement(stmt.next, context); 581 visitStatement(statement.next, context);
570 } 582 }
571 583
572 @override 584 @override
573 void visitReturn(tree.Return stmt, 585 void visitReturn(tree.Return stmt,
574 BuilderContext<Statement> context) { 586 BuilderContext<Statement> context) {
575 if (context.currentElement.isGenerativeConstructor && 587 if (context.currentElement.isGenerativeConstructor &&
576 !context.inInitializer) { 588 !context.inInitializer) {
577 assert(() { 589 assert(() {
578 tree.Expression value = stmt.value; 590 tree.Expression value = stmt.value;
579 return value is tree.Constant && value.value.isNull; 591 return value is tree.Constant && value.value.isNull;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 void visitTry(tree.Try stmt, 658 void visitTry(tree.Try stmt,
647 BuilderContext<Statement> context) { 659 BuilderContext<Statement> context) {
648 Block tryBody = visitInSubContext(stmt.tryBody, context); 660 Block tryBody = visitInSubContext(stmt.tryBody, context);
649 Block catchBody = visitInSubContext(stmt.catchBody, context); 661 Block catchBody = visitInSubContext(stmt.catchBody, context);
650 CatchBlock catchBlock; 662 CatchBlock catchBlock;
651 tree.Variable exceptionVariable = stmt.catchParameters[0]; 663 tree.Variable exceptionVariable = stmt.catchParameters[0];
652 context.handlerVariables.add(exceptionVariable); 664 context.handlerVariables.add(exceptionVariable);
653 VariableDeclaration exceptionParameter = 665 VariableDeclaration exceptionParameter =
654 new VariableDeclaration(context.getVariableName(exceptionVariable)); 666 new VariableDeclaration(context.getVariableName(exceptionVariable));
655 exceptionParameter.element = exceptionVariable.element; 667 exceptionParameter.element = exceptionVariable.element;
668 stmt.catchParameters.forEach(context.declaredVariables.add);
656 if (stmt.catchParameters.length == 2) { 669 if (stmt.catchParameters.length == 2) {
657 tree.Variable stackTraceVariable = stmt.catchParameters[1]; 670 tree.Variable stackTraceVariable = stmt.catchParameters[1];
658 context.handlerVariables.add(stackTraceVariable); 671 context.handlerVariables.add(stackTraceVariable);
659 VariableDeclaration stackTraceParameter = 672 VariableDeclaration stackTraceParameter =
660 new VariableDeclaration(context.getVariableName(stackTraceVariable)); 673 new VariableDeclaration(context.getVariableName(stackTraceVariable));
661 stackTraceParameter.element = stackTraceVariable.element; 674 stackTraceParameter.element = stackTraceVariable.element;
662 catchBlock = new CatchBlock(catchBody, 675 catchBlock = new CatchBlock(catchBody,
663 exceptionVar: exceptionParameter, 676 exceptionVar: exceptionParameter,
664 stackVar: stackTraceParameter); 677 stackVar: stackTraceParameter);
665 } else { 678 } else {
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
871 BuilderContext<Statement> context) { 884 BuilderContext<Statement> context) {
872 return new UnaryOperator('!', visitExpression(exp.operand, context)); 885 return new UnaryOperator('!', visitExpression(exp.operand, context));
873 } 886 }
874 887
875 @override 888 @override
876 Expression visitVariableUse(tree.VariableUse exp, 889 Expression visitVariableUse(tree.VariableUse exp,
877 BuilderContext<Statement> context) { 890 BuilderContext<Statement> context) {
878 return context.makeVariableAccess(exp.variable); 891 return context.makeVariableAccess(exp.variable);
879 } 892 }
880 893
894 @override
895 Expression visitAssign(tree.Assign node, BuilderContext<Statement> context) {
896 // This is called only when an assignment occurs in expression context.
897 return makeAssignment(
898 context.makeVariableAccess(node.variable),
899 visitExpression(node.value, context));
900 }
901
881 FunctionExpression makeSubFunction(tree.FunctionDefinition function, 902 FunctionExpression makeSubFunction(tree.FunctionDefinition function,
882 BuilderContext<Statement> context) { 903 BuilderContext<Statement> context) {
883 return visitFunctionDefinition(function, 904 return visitFunctionDefinition(function,
884 new BuilderContext<Statement>.inner(context)); 905 new BuilderContext<Statement>.inner(context));
885 } 906 }
886 907
887 @override 908 @override
888 Expression visitFunctionExpression(tree.FunctionExpression exp, 909 Expression visitFunctionExpression(tree.FunctionExpression exp,
889 BuilderContext<Statement> context) { 910 BuilderContext<Statement> context) {
890 return makeSubFunction(exp.definition, context)..name = null; 911 return makeSubFunction(exp.definition, context)..name = null;
891 } 912 }
892 913
893 @override 914 @override
894 void visitFunctionDeclaration(tree.FunctionDeclaration node, 915 void visitFunctionDeclaration(tree.FunctionDeclaration node,
895 BuilderContext<Statement> context) { 916 BuilderContext<Statement> context) {
896 assert(context.variableNames[node.variable] == null); 917 assert(context.variableNames[node.variable] == null);
897 String name = context.getVariableName(node.variable); 918 String name = context.getVariableName(node.variable);
898 FunctionExpression inner = makeSubFunction(node.definition, context); 919 FunctionExpression inner = makeSubFunction(node.definition, context);
899 inner.name = name; 920 inner.name = name;
900 FunctionDeclaration decl = new FunctionDeclaration(inner); 921 FunctionDeclaration decl = new FunctionDeclaration(inner);
901 context.declaredVariables.add(node.variable); 922 context.declaredVariables.add(node.variable);
902 context.addStatement(decl); 923 context.addStatement(decl);
903 visitStatement(node.next, context); 924 visitStatement(node.next, context);
904 } 925 }
905 926
906 List<Statement> buildInInitializerContext(tree.Statement root, 927 List<Statement> buildInInitializerContext(tree.Statement root,
907 BuilderContext context) { 928 BuilderContext context) {
908 BuilderContext inner = new BuilderContext<Statement>.initializer(context); 929 BuilderContext inner = new BuilderContext<Statement>.initializer(context);
909 inner.currentElement = context.currentElement; 930 inner.currentElement = context.currentElement;
931 inner.firstStatement = root;
910 visitStatement(root, inner); 932 visitStatement(root, inner);
911 List<Statement> bodyParts; 933 List<Statement> bodyParts;
912 for (tree.Variable variable in inner.variableNames.keys) { 934 for (tree.Variable variable in inner.variableNames.keys) {
913 if (!context.declaredVariables.contains(variable)) { 935 if (!context.declaredVariables.contains(variable) &&
936 !inner.declaredVariables.contains(variable)) {
914 inner.addDeclaration(variable); 937 inner.addDeclaration(variable);
915 } 938 }
916 } 939 }
917 if (inner.variables.length > 0) { 940 if (inner.variables.length > 0) {
918 bodyParts = new List<Statement>(); 941 bodyParts = new List<Statement>();
919 bodyParts.add(new VariableDeclarations(inner.variables)); 942 bodyParts.add(new VariableDeclarations(inner.variables));
920 bodyParts.addAll(inner.statements); 943 bodyParts.addAll(inner.statements);
921 } else { 944 } else {
922 bodyParts = inner.statements; 945 bodyParts = inner.statements;
923 } 946 }
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after
1283 environment = oldEnvironment; 1306 environment = oldEnvironment;
1284 shadowedParameters = oldShadow; 1307 shadowedParameters = oldShadow;
1285 1308
1286 for (int i=0; i<definition.parameters.length; i++) { 1309 for (int i=0; i<definition.parameters.length; i++) {
1287 tree.Variable param = definition.parameters[i]; 1310 tree.Variable param = definition.parameters[i];
1288 if (hasShadowedUse.remove(param)) { 1311 if (hasShadowedUse.remove(param)) {
1289 tree.Variable newParam = new tree.Variable(definition.element, 1312 tree.Variable newParam = new tree.Variable(definition.element,
1290 param.element); 1313 param.element);
1291 definition.parameters[i] = newParam; 1314 definition.parameters[i] = newParam;
1292 definition.replaceEachBody((tree.Statement body) { 1315 definition.replaceEachBody((tree.Statement body) {
1293 return new tree.Assign(param, new tree.VariableUse(newParam), body); 1316 return tree.Assign.makeStatement(
1317 param,
1318 new tree.VariableUse(newParam),
1319 body);
1294 }); 1320 });
1295 newParam.writeCount = 1; // Being a parameter counts as a write. 1321 newParam.writeCount = 1; // Being a parameter counts as a write.
1296 param.writeCount--; // Not a parameter anymore. 1322 param.writeCount--; // Not a parameter anymore.
1297 } 1323 }
1298 } 1324 }
1299 } 1325 }
1300 1326
1301 @override 1327 @override
1302 void visitInnerFunction(tree.FunctionDefinition definition) { 1328 void visitInnerFunction(tree.FunctionDefinition definition) {
1303 unshadowFunction(definition); 1329 unshadowFunction(definition);
(...skipping 19 matching lines...) Expand all
1323 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null); 1349 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null);
1324 1350
1325 ExecutableElement get executableContext => enclosingElement; 1351 ExecutableElement get executableContext => enclosingElement;
1326 1352
1327 ExecutableElement get memberContext => executableContext.memberContext; 1353 ExecutableElement get memberContext => executableContext.memberContext;
1328 1354
1329 bool get isLocal => true; 1355 bool get isLocal => true;
1330 1356
1331 LibraryElement get implementationLibrary => enclosingElement.library; 1357 LibraryElement get implementationLibrary => enclosingElement.library;
1332 } 1358 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/dart_backend/backend.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698