| OLD | NEW |
| 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 dart_codegen; | 5 library dart_codegen; |
| 6 | 6 |
| 7 import 'dart_tree.dart' as tree; | 7 import 'dart_tree.dart' as tree; |
| 8 import 'dart_printer.dart'; | 8 import 'dart_printer.dart'; |
| 9 import 'dart_tree_printer.dart' show TreePrinter; | 9 import 'dart_tree_printer.dart' show TreePrinter; |
| 10 import '../tree/tree.dart' as frontend; | 10 import '../tree/tree.dart' as frontend; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 tree.FunctionDefinition definition) { | 21 tree.FunctionDefinition definition) { |
| 22 FunctionExpression fn = new ASTEmitter().emit(element, definition); | 22 FunctionExpression fn = new ASTEmitter().emit(element, definition); |
| 23 return new TreePrinter(treeElements).makeExpression(fn); | 23 return new TreePrinter(treeElements).makeExpression(fn); |
| 24 } | 24 } |
| 25 | 25 |
| 26 /// Translates the dart_tree IR to Dart backend AST. | 26 /// Translates the dart_tree IR to Dart backend AST. |
| 27 class ASTEmitter extends tree.Visitor<dynamic, Expression> { | 27 class ASTEmitter extends tree.Visitor<dynamic, Expression> { |
| 28 /// Variables to be hoisted at the top of the current function. | 28 /// Variables to be hoisted at the top of the current function. |
| 29 List<VariableDeclaration> variables; | 29 List<VariableDeclaration> variables; |
| 30 | 30 |
| 31 /// Set of variables that have had their declaration inserted in [variables]. | 31 /// Maps variables to their name. |
| 32 Set<tree.Variable> seenVariables; | 32 /// These variables have had their declaration inserted in [variables]. |
| 33 Map<tree.Variable, String> variableNames; |
| 34 |
| 35 /// Variable names that have already been used. Used to avoid name clashes. |
| 36 Set<String> usedVariableNames; |
| 33 | 37 |
| 34 /// Statements emitted by the most recent call to [visitStatement]. | 38 /// Statements emitted by the most recent call to [visitStatement]. |
| 35 List<Statement> statementBuffer; | 39 List<Statement> statementBuffer; |
| 36 | 40 |
| 37 /// The function currently being emitted. | 41 /// The function currently being emitted. |
| 38 FunctionElement functionElement; | 42 FunctionElement functionElement; |
| 39 | 43 |
| 40 /// Bookkeeping object needed to synthesize a variable declaration. | 44 /// Bookkeeping object needed to synthesize a variable declaration. |
| 41 modelx.VariableList variableList; | 45 modelx.VariableList variableList; |
| 42 | 46 |
| 43 /// Input to [visitStatement]. Denotes the statement that will execute next | 47 /// Input to [visitStatement]. Denotes the statement that will execute next |
| 44 /// if the statements produced by [visitStatement] complete normally. | 48 /// if the statements produced by [visitStatement] complete normally. |
| 45 /// Set to null if control will fall over the end of the method. | 49 /// Set to null if control will fall over the end of the method. |
| 46 tree.Statement fallthrough; | 50 tree.Statement fallthrough; |
| 47 | 51 |
| 48 /// Labels that could not be eliminated using fallthrough. | 52 /// Labels that could not be eliminated using fallthrough. |
| 49 Set<tree.Label> usedLabels; | 53 Set<tree.Label> usedLabels; |
| 50 | 54 |
| 51 FunctionExpression emit(FunctionElement element, | 55 FunctionExpression emit(FunctionElement element, |
| 52 tree.FunctionDefinition definition) { | 56 tree.FunctionDefinition definition) { |
| 53 functionElement = element; | 57 functionElement = element; |
| 54 variables = <VariableDeclaration>[]; | 58 variables = <VariableDeclaration>[]; |
| 55 statementBuffer = <Statement>[]; | 59 statementBuffer = <Statement>[]; |
| 56 seenVariables = new Set<tree.Variable>(); | 60 variableNames = <tree.Variable, String>{}; |
| 57 tree.Variable.counter = 0; | 61 usedVariableNames = new Set<String>(); |
| 58 variableList = new modelx.VariableList(tree.Modifiers.EMPTY); | 62 variableList = new modelx.VariableList(tree.Modifiers.EMPTY); |
| 59 fallthrough = null; | 63 fallthrough = null; |
| 60 usedLabels = new Set<tree.Label>(); | 64 usedLabels = new Set<tree.Label>(); |
| 61 | 65 |
| 62 Parameters parameters = emitParameters(definition.parameters); | 66 Parameters parameters = emitParameters(definition.parameters); |
| 63 visitStatement(definition.body); | 67 visitStatement(definition.body); |
| 64 removeTrailingReturn(); | 68 removeTrailingReturn(); |
| 65 Statement body = new Block(statementBuffer); | 69 Statement body = new Block(statementBuffer); |
| 66 if (variables.length > 0) { | 70 if (variables.length > 0) { |
| 67 Statement head = new VariableDeclarations(variables); | 71 Statement head = new VariableDeclarations(variables); |
| 68 body = new Block([head, body]); | 72 body = new Block([head, body]); |
| 69 } | 73 } |
| 70 | 74 |
| 71 FunctionType functionType = element.type; | 75 FunctionType functionType = element.type; |
| 72 | 76 |
| 73 variables = null; | 77 variables = null; |
| 74 statementBuffer = null; | 78 statementBuffer = null; |
| 75 functionElement = null; | 79 functionElement = null; |
| 76 variableList = null; | 80 variableList = null; |
| 77 seenVariables = null; | 81 variableNames = null; |
| 82 usedVariableNames = null; |
| 78 usedLabels = null; | 83 usedLabels = null; |
| 79 | 84 |
| 80 return new FunctionExpression( | 85 return new FunctionExpression( |
| 81 parameters, | 86 parameters, |
| 82 body, | 87 body, |
| 83 name: element.name, | 88 name: element.name, |
| 84 returnType: emitOptionalType(functionType.returnType)) | 89 returnType: emitOptionalType(functionType.returnType)) |
| 85 ..element = element; | 90 ..element = element; |
| 86 } | 91 } |
| 87 | 92 |
| 88 /// Removes a trailing "return null" from [statementBuffer]. | 93 /// Removes a trailing "return null" from [statementBuffer]. |
| 89 void removeTrailingReturn() { | 94 void removeTrailingReturn() { |
| 90 if (statementBuffer.isEmpty) return; | 95 if (statementBuffer.isEmpty) return; |
| 91 if (statementBuffer.last is! Return) return; | 96 if (statementBuffer.last is! Return) return; |
| 92 Return ret = statementBuffer.last; | 97 Return ret = statementBuffer.last; |
| 93 Expression expr = ret.expression; | 98 Expression expr = ret.expression; |
| 94 if (expr is Literal && expr.value is dart2js.NullConstant) { | 99 if (expr is Literal && expr.value is dart2js.NullConstant) { |
| 95 statementBuffer.removeLast(); | 100 statementBuffer.removeLast(); |
| 96 } | 101 } |
| 97 } | 102 } |
| 98 | 103 |
| 99 Parameter emitParameter(tree.Variable param) { | 104 Parameter emitParameter(tree.Variable param) { |
| 100 seenVariables.add(param); | 105 String name = getVariableName(param); |
| 101 ParameterElement element = param.element; | 106 ParameterElement element = param.element; |
| 102 TypeAnnotation type = emitOptionalType(element.type); | 107 TypeAnnotation type = emitOptionalType(element.type); |
| 103 return new Parameter(element.name, type:type) | 108 return new Parameter(name, type:type) |
| 104 ..element = element; | 109 ..element = element; |
| 105 } | 110 } |
| 106 | 111 |
| 107 Parameters emitParameters(List<tree.Variable> params) { | 112 Parameters emitParameters(List<tree.Variable> params) { |
| 108 return new Parameters(params.map(emitParameter).toList(growable:false)); | 113 return new Parameters(params.map(emitParameter).toList(growable:false)); |
| 109 } | 114 } |
| 110 | 115 |
| 111 /// True if the two expressions are a reference to the same variable. | 116 /// True if the two expressions are a reference to the same variable. |
| 112 bool isSameVariable(Expression e1, Expression e2) { | 117 bool isSameVariable(Expression e1, Expression e2) { |
| 113 // TODO(asgerf): Using the annotated element isn't the best way to do this | 118 // TODO(asgerf): Using the annotated element isn't the best way to do this |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 savedBuffer.add(new LabeledStatement(stmt.label.name, | 172 savedBuffer.add(new LabeledStatement(stmt.label.name, |
| 168 new Block(statementBuffer))); | 173 new Block(statementBuffer))); |
| 169 } else { | 174 } else { |
| 170 savedBuffer.add(new Block(statementBuffer)); | 175 savedBuffer.add(new Block(statementBuffer)); |
| 171 } | 176 } |
| 172 fallthrough = savedFallthrough; | 177 fallthrough = savedFallthrough; |
| 173 statementBuffer = savedBuffer; | 178 statementBuffer = savedBuffer; |
| 174 visitStatement(stmt.next); | 179 visitStatement(stmt.next); |
| 175 } | 180 } |
| 176 | 181 |
| 177 void visitAssign(tree.Assign stmt) { | 182 /// Generates a name for the given variable and synthesizes an element for it, |
| 178 // Synthesize an element for the variable, if necessary. | 183 /// if necessary. |
| 179 if (stmt.variable.element == null) { | 184 String getVariableName(tree.Variable variable) { |
| 180 stmt.variable.element = new modelx.VariableElementX( | 185 String name = variableNames[variable]; |
| 181 stmt.variable.name, | 186 if (name != null) { |
| 187 return name; |
| 188 } |
| 189 String prefix = variable.element == null ? 'v' : variable.element.name; |
| 190 int counter = 0; |
| 191 name = variable.element == null ? '$prefix$counter' : variable.element.name; |
| 192 while (!usedVariableNames.add(name)) { |
| 193 ++counter; |
| 194 name = '$prefix$counter'; |
| 195 } |
| 196 variableNames[variable] = name; |
| 197 |
| 198 // Synthesize an element for the variable |
| 199 if (variable.element == null || name != variable.element.name) { |
| 200 variable.element = new modelx.VariableElementX( |
| 201 name, |
| 182 ElementKind.VARIABLE, | 202 ElementKind.VARIABLE, |
| 183 functionElement, | 203 functionElement, |
| 184 variableList, | 204 variableList, |
| 185 null); | 205 null); |
| 186 } | 206 } |
| 187 if (seenVariables.add(stmt.variable)) { | 207 if (variable.element is! ParameterElement) { |
| 188 variables.add(new VariableDeclaration(stmt.variable.name) | 208 variables.add(new VariableDeclaration(name) |
| 189 ..element = stmt.variable.element); | 209 ..element = variable.element); |
| 190 } | 210 } |
| 211 return name; |
| 212 } |
| 213 |
| 214 void visitAssign(tree.Assign stmt) { |
| 215 String name = getVariableName(stmt.variable); |
| 191 statementBuffer.add(new ExpressionStatement(makeAssignment( | 216 statementBuffer.add(new ExpressionStatement(makeAssignment( |
| 192 visitVariable(stmt.variable), | 217 visitVariable(stmt.variable), |
| 193 visitExpression(stmt.definition)))); | 218 visitExpression(stmt.definition)))); |
| 194 visitStatement(stmt.next); | 219 visitStatement(stmt.next); |
| 195 } | 220 } |
| 196 | 221 |
| 197 void visitReturn(tree.Return stmt) { | 222 void visitReturn(tree.Return stmt) { |
| 198 Expression inner = visitExpression(stmt.value); | 223 Expression inner = visitExpression(stmt.value); |
| 199 statementBuffer.add(new Return(inner)); | 224 statementBuffer.add(new Return(inner)); |
| 200 } | 225 } |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 return new BinaryOperator(visitExpression(exp.left), | 437 return new BinaryOperator(visitExpression(exp.left), |
| 413 exp.operator, | 438 exp.operator, |
| 414 visitExpression(exp.right)); | 439 visitExpression(exp.right)); |
| 415 } | 440 } |
| 416 | 441 |
| 417 Expression visitNot(tree.Not exp) { | 442 Expression visitNot(tree.Not exp) { |
| 418 return new UnaryOperator('!', visitExpression(exp.operand)); | 443 return new UnaryOperator('!', visitExpression(exp.operand)); |
| 419 } | 444 } |
| 420 | 445 |
| 421 Expression visitVariable(tree.Variable exp) { | 446 Expression visitVariable(tree.Variable exp) { |
| 422 return new Identifier(exp.name) | 447 return new Identifier(getVariableName(exp)) |
| 423 ..element = exp.element; | 448 ..element = exp.element; |
| 424 } | 449 } |
| 425 | 450 |
| 426 TypeAnnotation emitType(DartType type) { | 451 TypeAnnotation emitType(DartType type) { |
| 427 if (type is GenericType) { // TODO(asgerf): faster Link.map | 452 if (type is GenericType) { // TODO(asgerf): faster Link.map |
| 428 return new TypeAnnotation( | 453 return new TypeAnnotation( |
| 429 type.element.name, | 454 type.element.name, |
| 430 type.typeArguments.toList(growable:false) | 455 type.typeArguments.toList(growable:false) |
| 431 .map(emitType).toList(growable:false)) | 456 .map(emitType).toList(growable:false)) |
| 432 ..dartType = type; | 457 ..dartType = type; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 dart2js.StringConstant nameConstant = constant.fields[0]; | 502 dart2js.StringConstant nameConstant = constant.fields[0]; |
| 478 String nameString = nameConstant.value.slowToString(); | 503 String nameString = nameConstant.value.slowToString(); |
| 479 return new LiteralSymbol(nameString); | 504 return new LiteralSymbol(nameString); |
| 480 } else { | 505 } else { |
| 481 throw "Unsupported constant: $constant"; | 506 throw "Unsupported constant: $constant"; |
| 482 } | 507 } |
| 483 } | 508 } |
| 484 } | 509 } |
| 485 } | 510 } |
| 486 | 511 |
| OLD | NEW |