| 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 code_generator; | 5 library code_generator; |
| 6 | 6 |
| 7 import 'glue.dart'; | 7 import 'glue.dart'; |
| 8 | 8 |
| 9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; | 9 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir; |
| 10 import '../../js/js.dart' as js; | 10 import '../../js/js.dart' as js; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 | 52 |
| 53 CodeGenerator(this.glue, this.registry); | 53 CodeGenerator(this.glue, this.registry); |
| 54 | 54 |
| 55 /// Generates JavaScript code for the body of [function]. | 55 /// Generates JavaScript code for the body of [function]. |
| 56 js.Fun buildFunction(tree_ir.FunctionDefinition function) { | 56 js.Fun buildFunction(tree_ir.FunctionDefinition function) { |
| 57 currentFunction = function.element; | 57 currentFunction = function.element; |
| 58 visitStatement(function.body); | 58 visitStatement(function.body); |
| 59 | 59 |
| 60 List<js.Parameter> parameters = new List<js.Parameter>(); | 60 List<js.Parameter> parameters = new List<js.Parameter>(); |
| 61 Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>(); | 61 Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>(); |
| 62 Set<String> declaredVariables = new Set<String>(); |
| 62 | 63 |
| 63 for (tree_ir.Variable parameter in function.parameters) { | 64 for (tree_ir.Variable parameter in function.parameters) { |
| 64 String name = getVariableName(parameter); | 65 String name = getVariableName(parameter); |
| 65 parameters.add(new js.Parameter(name)); | 66 parameters.add(new js.Parameter(name)); |
| 66 parameterSet.add(parameter); | 67 parameterSet.add(parameter); |
| 68 declaredVariables.add(name); |
| 67 } | 69 } |
| 68 | 70 |
| 69 List<js.VariableInitialization> jsVariables = <js.VariableInitialization>[]; | 71 List<js.VariableInitialization> jsVariables = <js.VariableInitialization>[]; |
| 70 | 72 |
| 73 // Declare variables with an initializer. Pull statements into the |
| 74 // initializer until we find a statement that cannot be pulled in. |
| 75 int accumulatorIndex = 0; |
| 76 while (accumulatorIndex < accumulator.length) { |
| 77 js.Node node = accumulator[accumulatorIndex]; |
| 78 |
| 79 // Check that node is an assignment to a local variable. |
| 80 if (node is! js.ExpressionStatement) break; |
| 81 js.ExpressionStatement stmt = node; |
| 82 if (stmt.expression is! js.Assignment) break; |
| 83 js.Assignment assign = stmt.expression; |
| 84 if (assign.leftHandSide is! js.VariableUse) break; |
| 85 if (assign.op != null) break; // Compound assignment. |
| 86 js.VariableUse use = assign.leftHandSide; |
| 87 |
| 88 // We cannot declare a variable more than once. |
| 89 if (!declaredVariables.add(use.name)) break; |
| 90 |
| 91 js.VariableInitialization jsVariable = new js.VariableInitialization( |
| 92 new js.VariableDeclaration(use.name), |
| 93 assign.value); |
| 94 jsVariables.add(jsVariable); |
| 95 |
| 96 ++accumulatorIndex; |
| 97 } |
| 98 |
| 99 // Discard the statements that were pulled in the initializer. |
| 100 if (accumulatorIndex > 0) { |
| 101 accumulator = accumulator.sublist(accumulatorIndex); |
| 102 } |
| 103 |
| 104 // Declare remaining variables. |
| 71 for (tree_ir.Variable variable in variableNames.keys) { | 105 for (tree_ir.Variable variable in variableNames.keys) { |
| 72 if (parameterSet.contains(variable)) continue; | |
| 73 String name = getVariableName(variable); | 106 String name = getVariableName(variable); |
| 107 if (declaredVariables.contains(name)) continue; |
| 74 js.VariableInitialization jsVariable = new js.VariableInitialization( | 108 js.VariableInitialization jsVariable = new js.VariableInitialization( |
| 75 new js.VariableDeclaration(name), | 109 new js.VariableDeclaration(name), |
| 76 null); | 110 null); |
| 77 jsVariables.add(jsVariable); | 111 jsVariables.add(jsVariable); |
| 78 } | 112 } |
| 79 | 113 |
| 80 if (jsVariables.length > 0) { | 114 if (jsVariables.length > 0) { |
| 81 // Would be nice to avoid inserting at the beginning of list. | 115 // Would be nice to avoid inserting at the beginning of list. |
| 82 accumulator.insert(0, new js.ExpressionStatement( | 116 accumulator.insert(0, new js.ExpressionStatement( |
| 83 new js.VariableDeclarationList(jsVariables))); | 117 new js.VariableDeclarationList(jsVariables))); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 100 // Functions are not nested in the JS backend. | 134 // Functions are not nested in the JS backend. |
| 101 assert(variable.host == currentFunction); | 135 assert(variable.host == currentFunction); |
| 102 | 136 |
| 103 // Get the name if we already have one. | 137 // Get the name if we already have one. |
| 104 String name = variableNames[variable]; | 138 String name = variableNames[variable]; |
| 105 if (name != null) { | 139 if (name != null) { |
| 106 return name; | 140 return name; |
| 107 } | 141 } |
| 108 | 142 |
| 109 // Synthesize a variable name that isn't used elsewhere. | 143 // Synthesize a variable name that isn't used elsewhere. |
| 110 // The [usedVariableNames] set is shared between nested emitters, | |
| 111 // so this also prevents clash with variables in an enclosing/inner scope. | |
| 112 // The renaming phase after codegen will further prefix local variables | |
| 113 // so they cannot clash with top-level variables or fields. | |
| 114 String prefix = variable.element == null ? 'v' : variable.element.name; | 144 String prefix = variable.element == null ? 'v' : variable.element.name; |
| 115 int counter = 0; | 145 int counter = 0; |
| 116 name = glue.safeVariableName(variable.element == null | 146 name = glue.safeVariableName(variable.element == null |
| 117 ? '$prefix$counter' | 147 ? '$prefix$counter' |
| 118 : variable.element.name); | 148 : variable.element.name); |
| 119 while (!usedVariableNames.add(name)) { | 149 while (!usedVariableNames.add(name)) { |
| 120 ++counter; | 150 ++counter; |
| 121 name = '$prefix$counter'; | 151 name = '$prefix$counter'; |
| 122 } | 152 } |
| 123 variableNames[variable] = name; | 153 variableNames[variable] = name; |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 593 | 623 |
| 594 @override | 624 @override |
| 595 visitFunctionDeclaration(tree_ir.FunctionDeclaration node) { | 625 visitFunctionDeclaration(tree_ir.FunctionDeclaration node) { |
| 596 return errorUnsupportedNode(node); | 626 return errorUnsupportedNode(node); |
| 597 } | 627 } |
| 598 | 628 |
| 599 errorUnsupportedNode(tree_ir.DartSpecificNode node) { | 629 errorUnsupportedNode(tree_ir.DartSpecificNode node) { |
| 600 throw "Unsupported node in JS backend: $node"; | 630 throw "Unsupported node in JS backend: $node"; |
| 601 } | 631 } |
| 602 } | 632 } |
| OLD | NEW |