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; |
11 import '../dart2jslib.dart' as dart2js; | 11 import '../dart2jslib.dart' as dart2js; |
12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
13 import '../dart_types.dart'; | 13 import '../dart_types.dart'; |
14 import '../elements/modelx.dart' as modelx; | 14 import '../elements/modelx.dart' as modelx; |
15 import '../universe/universe.dart'; | 15 import '../universe/universe.dart'; |
16 import '../tree/tree.dart' as tree show Modifiers; | 16 import '../tree/tree.dart' as tree show Modifiers; |
17 import '../ir/const_expression.dart'; | 17 import '../ir/const_expression.dart'; |
18 | 18 |
19 /// Translates the dart_tree IR to Dart frontend AST. | 19 /// Translates the dart_tree IR to Dart frontend AST. |
20 frontend.FunctionExpression emit(FunctionElement element, | 20 frontend.FunctionExpression emit(FunctionElement element, |
21 dart2js.TreeElementMapping treeElements, | 21 dart2js.TreeElementMapping treeElements, |
22 tree.FunctionDefinition definition) { | 22 tree.FunctionDefinition definition) { |
23 FunctionExpression fn = new ASTEmitter().emit(element, definition); | 23 FunctionExpression fn = new ASTEmitter().emit(definition); |
24 return new TreePrinter(treeElements).makeExpression(fn); | 24 return new TreePrinter(treeElements).makeExpression(fn); |
25 } | 25 } |
26 | 26 |
27 /// Translates the dart_tree IR to Dart backend AST. | 27 /// Translates the dart_tree IR to Dart backend AST. |
28 /// An instance of this class should only be used once; a fresh emitter | 28 /// An instance of this class should only be used once; a fresh emitter |
29 /// must be created for each function to be emitted. | 29 /// must be created for each function to be emitted. |
30 class ASTEmitter extends tree.Visitor<dynamic, Expression> { | 30 class ASTEmitter extends tree.Visitor<dynamic, Expression> { |
31 /// Variables to be hoisted at the top of the current function. | 31 /// Variables to be hoisted at the top of the current function. |
32 List<VariableDeclaration> variables = <VariableDeclaration>[]; | 32 List<VariableDeclaration> variables = <VariableDeclaration>[]; |
33 | 33 |
34 /// Maps variables to their name. | 34 /// Maps variables to their name. |
35 Map<tree.Variable, String> variableNames = <tree.Variable, String>{}; | 35 Map<tree.Variable, String> variableNames = <tree.Variable, String>{}; |
36 | 36 |
37 /// Maps local constants to their name. | 37 /// Maps local constants to their name. |
38 Map<VariableElement, String> constantNames = <VariableElement, String>{}; | 38 Map<VariableElement, String> constantNames = <VariableElement, String>{}; |
39 | 39 |
40 /// Maps variables to their declarations. | 40 /// Variables that have had their declaration created. |
41 Map<tree.Variable, VariableDeclaration> variableDeclarations = | 41 Set<tree.Variable> declaredVariables = new Set<tree.Variable>(); |
42 <tree.Variable, VariableDeclaration>{}; | |
43 | 42 |
44 /// Variable names that have already been used. Used to avoid name clashes. | 43 /// Variable names that have already been used. Used to avoid name clashes. |
45 Set<String> usedVariableNames = new Set<String>(); | 44 Set<String> usedVariableNames; |
46 | 45 |
47 /// Statements emitted by the most recent call to [visitStatement]. | 46 /// Statements emitted by the most recent call to [visitStatement]. |
48 List<Statement> statementBuffer = <Statement>[]; | 47 List<Statement> statementBuffer = <Statement>[]; |
49 | 48 |
50 /// The function currently being emitted. | 49 /// The function currently being emitted. |
51 FunctionElement functionElement; | 50 FunctionElement functionElement; |
52 | 51 |
53 /// Bookkeeping object needed to synthesize a variable declaration. | 52 /// Bookkeeping object needed to synthesize a variable declaration. |
54 modelx.VariableList variableList | 53 modelx.VariableList variableList |
55 = new modelx.VariableList(tree.Modifiers.EMPTY); | 54 = new modelx.VariableList(tree.Modifiers.EMPTY); |
56 | 55 |
57 /// Input to [visitStatement]. Denotes the statement that will execute next | 56 /// Input to [visitStatement]. Denotes the statement that will execute next |
58 /// if the statements produced by [visitStatement] complete normally. | 57 /// if the statements produced by [visitStatement] complete normally. |
59 /// Set to null if control will fall over the end of the method. | 58 /// Set to null if control will fall over the end of the method. |
60 tree.Statement fallthrough = null; | 59 tree.Statement fallthrough = null; |
61 | 60 |
62 /// Labels that could not be eliminated using fallthrough. | 61 /// Labels that could not be eliminated using fallthrough. |
63 Set<tree.Label> usedLabels = new Set<tree.Label>(); | 62 Set<tree.Label> usedLabels = new Set<tree.Label>(); |
64 | 63 |
65 /// The first dart_tree statement that is not converted to a variable | 64 /// The first dart_tree statement that is not converted to a variable |
66 /// initializer. | 65 /// initializer. |
67 tree.Statement firstStatement; | 66 tree.Statement firstStatement; |
68 | 67 |
69 FunctionExpression emit(FunctionElement element, | 68 /// Emitter for the enclosing function, or null if the current function is |
70 tree.FunctionDefinition definition) { | 69 /// not a local function. |
71 functionElement = element; | 70 ASTEmitter parent; |
72 | 71 |
73 Parameters parameters = emitParameters(definition.parameters); | 72 ASTEmitter() : usedVariableNames = new Set<String>(); |
| 73 |
| 74 ASTEmitter.inner(ASTEmitter parent) |
| 75 : this.parent = parent, |
| 76 usedVariableNames = parent.usedVariableNames; |
| 77 |
| 78 FunctionExpression emit(tree.FunctionDefinition definition) { |
| 79 functionElement = definition.element; |
| 80 |
| 81 Parameters parameters = emitParameters(definition.element.functionSignature)
; |
| 82 |
| 83 // Declare parameters. |
| 84 for (tree.Variable param in definition.parameters) { |
| 85 variableNames[param] = param.element.name; |
| 86 usedVariableNames.add(param.element.name); |
| 87 declaredVariables.add(param); |
| 88 } |
| 89 |
74 firstStatement = definition.body; | 90 firstStatement = definition.body; |
75 visitStatement(definition.body); | 91 visitStatement(definition.body); |
76 removeTrailingReturn(); | 92 removeTrailingReturn(); |
77 Statement body = new Block(statementBuffer); | |
78 | 93 |
79 // Some of the variable declarations have already been added | 94 // Some of the variable declarations have already been added |
80 // if their first assignment could be pulled into the initializer. | 95 // if their first assignment could be pulled into the initializer. |
81 // Add the remaining variable declarations now. | 96 // Add the remaining variable declarations now. |
82 for (tree.Variable variable in variableNames.keys) { | 97 for (tree.Variable variable in variableNames.keys) { |
83 if (variable.element is ParameterElement) continue; | 98 if (!declaredVariables.contains(variable)) { |
84 if (variableDeclarations.containsKey(variable)) continue; | 99 addDeclaration(variable); |
85 addDeclaration(variable); | 100 } |
86 } | 101 } |
87 | 102 |
88 // Add constant declarations. | 103 // Add constant declarations. |
89 List<VariableDeclaration> constants = <VariableDeclaration>[]; | 104 List<VariableDeclaration> constants = <VariableDeclaration>[]; |
90 for (ConstDeclaration constDecl in definition.localConstants) { | 105 for (ConstDeclaration constDecl in definition.localConstants) { |
91 if (!constantNames.containsKey(constDecl.element)) | 106 if (!constantNames.containsKey(constDecl.element)) |
92 continue; // Discard unused constants declarations. | 107 continue; // Discard unused constants declarations. |
93 String name = getConstantName(constDecl.element); | 108 String name = getConstantName(constDecl.element); |
94 Expression value = emitConstant(constDecl.expression); | 109 Expression value = emitConstant(constDecl.expression); |
95 VariableDeclaration decl = new VariableDeclaration(name, value); | 110 VariableDeclaration decl = new VariableDeclaration(name, value); |
96 decl.element = constDecl.element; | 111 decl.element = constDecl.element; |
97 constants.add(decl); | 112 constants.add(decl); |
98 } | 113 } |
99 | 114 |
100 List<Statement> bodyParts = []; | 115 List<Statement> bodyParts = []; |
101 if (constants.length > 0) { | 116 if (constants.length > 0) { |
102 bodyParts.add(new VariableDeclarations(constants, isConst: true)); | 117 bodyParts.add(new VariableDeclarations(constants, isConst: true)); |
103 } | 118 } |
104 if (variables.length > 0) { | 119 if (variables.length > 0) { |
105 bodyParts.add(new VariableDeclarations(variables)); | 120 bodyParts.add(new VariableDeclarations(variables)); |
106 } | 121 } |
107 bodyParts.add(body); | 122 bodyParts.addAll(statementBuffer); |
108 | 123 |
109 FunctionType functionType = element.type; | 124 FunctionType functionType = functionElement.type; |
110 | 125 |
111 return new FunctionExpression( | 126 return new FunctionExpression( |
112 parameters, | 127 parameters, |
113 new Block(bodyParts), | 128 new Block(bodyParts), |
114 name: element.name, | 129 name: functionElement.name, |
115 returnType: emitOptionalType(functionType.returnType)) | 130 returnType: emitOptionalType(functionType.returnType)) |
116 ..element = element; | 131 ..element = functionElement; |
117 } | 132 } |
118 | 133 |
119 void addDeclaration(tree.Variable variable, [Expression initializer]) { | 134 void addDeclaration(tree.Variable variable, [Expression initializer]) { |
120 assert(!variableDeclarations.containsKey(variable)); | 135 assert(!declaredVariables.contains(variable)); |
121 String name = getVariableName(variable); | 136 String name = getVariableName(variable); |
122 VariableDeclaration decl = new VariableDeclaration(name, initializer); | 137 VariableDeclaration decl = new VariableDeclaration(name, initializer); |
123 decl.element = variable.element; | 138 decl.element = variable.element; |
124 variableDeclarations[variable] = decl; | 139 declaredVariables.add(variable); |
125 variables.add(decl); | 140 variables.add(decl); |
126 } | 141 } |
127 | 142 |
128 /// Removes a trailing "return null" from [statementBuffer]. | 143 /// Removes a trailing "return null" from [statementBuffer]. |
129 void removeTrailingReturn() { | 144 void removeTrailingReturn() { |
130 if (statementBuffer.isEmpty) return; | 145 if (statementBuffer.isEmpty) return; |
131 if (statementBuffer.last is! Return) return; | 146 if (statementBuffer.last is! Return) return; |
132 Return ret = statementBuffer.last; | 147 Return ret = statementBuffer.last; |
133 Expression expr = ret.expression; | 148 Expression expr = ret.expression; |
134 if (expr is Literal && expr.value is dart2js.NullConstant) { | 149 if (expr is Literal && expr.value is dart2js.NullConstant) { |
135 statementBuffer.removeLast(); | 150 statementBuffer.removeLast(); |
136 } | 151 } |
137 } | 152 } |
138 | 153 |
139 Parameter emitParameterFromElement(ParameterElement element, [String name]) { | 154 Parameter emitParameterFromElement(ParameterElement element, [String name]) { |
140 if (name == null) { | 155 if (name == null) { |
141 name = element.name; | 156 name = element.name; |
142 } | 157 } |
143 if (element.functionSignature != null) { | 158 if (element.functionSignature != null) { |
144 FunctionSignature signature = element.functionSignature; | 159 FunctionSignature signature = element.functionSignature; |
145 TypeAnnotation returnType = emitOptionalType(signature.type.returnType); | 160 TypeAnnotation returnType = emitOptionalType(signature.type.returnType); |
146 Parameters innerParameters = new Parameters( | 161 Parameters innerParameters = emitParameters(signature); |
147 signature.requiredParameters.mapToList(emitParameterFromElement), | |
148 signature.optionalParameters.mapToList(emitParameterFromElement), | |
149 signature.optionalParametersAreNamed); | |
150 return new Parameter.function(name, returnType, innerParameters) | 162 return new Parameter.function(name, returnType, innerParameters) |
151 ..element = element; | 163 ..element = element; |
152 } else { | 164 } else { |
153 TypeAnnotation type = emitOptionalType(element.type); | 165 TypeAnnotation type = emitOptionalType(element.type); |
154 return new Parameter(name, type:type) | 166 return new Parameter(name, type:type) |
155 ..element = element; | 167 ..element = element; |
156 } | 168 } |
157 } | 169 } |
158 | 170 |
159 Parameter emitParameter(tree.Variable param) { | 171 Parameters emitParameters(FunctionSignature signature) { |
160 return emitParameterFromElement(param.element, getVariableName(param)); | 172 return new Parameters( |
161 } | 173 signature.requiredParameters.mapToList(emitParameterFromElement), |
162 | 174 signature.optionalParameters.mapToList(emitParameterFromElement), |
163 Parameters emitParameters(List<tree.Variable> params) { | 175 signature.optionalParametersAreNamed); |
164 return new Parameters(params.map(emitParameter).toList(growable:false)); | |
165 } | 176 } |
166 | 177 |
167 /// True if the two expressions are a reference to the same variable. | 178 /// True if the two expressions are a reference to the same variable. |
168 bool isSameVariable(Receiver e1, Receiver e2) { | 179 bool isSameVariable(Receiver e1, Receiver e2) { |
169 // TODO(asgerf): Using the annotated element isn't the best way to do this | 180 // TODO(asgerf): Using the annotated element isn't the best way to do this |
170 // since elements are supposed to go away from codegen when we discard the | 181 // since elements are supposed to go away from codegen when we discard the |
171 // old backend. | 182 // old backend. |
172 return e1 is Identifier && | 183 return e1 is Identifier && |
173 e2 is Identifier && | 184 e2 is Identifier && |
174 e1.element is VariableElement && | 185 e1.element is VariableElement && |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 savedBuffer.add(new Block(statementBuffer)); | 237 savedBuffer.add(new Block(statementBuffer)); |
227 } | 238 } |
228 fallthrough = savedFallthrough; | 239 fallthrough = savedFallthrough; |
229 statementBuffer = savedBuffer; | 240 statementBuffer = savedBuffer; |
230 visitStatement(stmt.next); | 241 visitStatement(stmt.next); |
231 } | 242 } |
232 | 243 |
233 /// Generates a name for the given variable and synthesizes an element for it, | 244 /// Generates a name for the given variable and synthesizes an element for it, |
234 /// if necessary. | 245 /// if necessary. |
235 String getVariableName(tree.Variable variable) { | 246 String getVariableName(tree.Variable variable) { |
| 247 // If the variable belongs to an enclosing function, ask the parent emitter |
| 248 // for the variable name. |
| 249 if (variable.host.element != functionElement) { |
| 250 return parent.getVariableName(variable); |
| 251 } |
| 252 |
| 253 // Get the name if we already have one. |
236 String name = variableNames[variable]; | 254 String name = variableNames[variable]; |
237 if (name != null) { | 255 if (name != null) { |
238 return name; | 256 return name; |
239 } | 257 } |
| 258 |
| 259 // Synthesize a variable name that isn't used elsewhere. |
| 260 // The [usedVariableNames] set is shared between nested emitters, |
| 261 // so this also prevents clash with variables in an enclosing/inner scope. |
| 262 // The renaming phase after codegen will further prefix local variables |
| 263 // so they cannot clash with top-level variables or fields. |
240 String prefix = variable.element == null ? 'v' : variable.element.name; | 264 String prefix = variable.element == null ? 'v' : variable.element.name; |
241 int counter = 0; | 265 int counter = 0; |
242 name = variable.element == null ? '$prefix$counter' : variable.element.name; | 266 name = variable.element == null ? '$prefix$counter' : variable.element.name; |
243 while (!usedVariableNames.add(name)) { | 267 while (!usedVariableNames.add(name)) { |
244 ++counter; | 268 ++counter; |
245 name = '$prefix$counter'; | 269 name = '$prefix$counter'; |
246 } | 270 } |
247 variableNames[variable] = name; | 271 variableNames[variable] = name; |
248 | 272 |
249 // Synthesize an element for the variable | 273 // Synthesize an element for the variable |
250 if (variable.element == null || name != variable.element.name) { | 274 if (variable.element == null || name != variable.element.name) { |
251 variable.element = new modelx.VariableElementX( | 275 variable.element = new modelx.VariableElementX( |
252 name, | 276 name, |
253 ElementKind.VARIABLE, | 277 ElementKind.VARIABLE, |
254 functionElement, | 278 functionElement, |
255 variableList, | 279 variableList, |
256 null); | 280 null); |
257 } | 281 } |
258 return name; | 282 return name; |
259 } | 283 } |
260 | 284 |
261 String getConstantName(VariableElement element) { | 285 String getConstantName(VariableElement element) { |
| 286 assert(element.kind == ElementKind.VARIABLE); |
| 287 if (element.enclosingElement != functionElement) { |
| 288 return parent.getConstantName(element); |
| 289 } |
262 String name = constantNames[element]; | 290 String name = constantNames[element]; |
263 if (name != null) { | 291 if (name != null) { |
264 return name; | 292 return name; |
265 } | 293 } |
266 String prefix = element.name; | 294 String prefix = element.name; |
267 int counter = 0; | 295 int counter = 0; |
268 name = element.name; | 296 name = element.name; |
269 while (!usedVariableNames.add(name)) { | 297 while (!usedVariableNames.add(name)) { |
270 ++counter; | 298 ++counter; |
271 name = '$prefix$counter'; | 299 name = '$prefix$counter'; |
272 } | 300 } |
273 constantNames[element] = name; | 301 constantNames[element] = name; |
274 return name; | 302 return name; |
275 } | 303 } |
276 | 304 |
| 305 bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull; |
| 306 |
277 void visitAssign(tree.Assign stmt) { | 307 void visitAssign(tree.Assign stmt) { |
| 308 // Try to emit a local function declaration. This is useful for functions |
| 309 // that may occur in expression context, but could not be inlined anywhere. |
| 310 if (stmt.variable.element is FunctionElement && |
| 311 stmt.definition is tree.FunctionExpression && |
| 312 !declaredVariables.contains(stmt.variable)) { |
| 313 tree.FunctionExpression functionExp = stmt.definition; |
| 314 FunctionExpression function = makeSubFunction(functionExp.definition); |
| 315 FunctionDeclaration decl = new FunctionDeclaration(function); |
| 316 statementBuffer.add(decl); |
| 317 declaredVariables.add(stmt.variable); |
| 318 visitStatement(stmt.next); |
| 319 return; |
| 320 } |
| 321 |
278 bool isFirstOccurrence = (variableNames[stmt.variable] == null); | 322 bool isFirstOccurrence = (variableNames[stmt.variable] == null); |
| 323 bool isDeclaredHere = stmt.variable.host.element == functionElement; |
279 String name = getVariableName(stmt.variable); | 324 String name = getVariableName(stmt.variable); |
280 Expression definition = visitExpression(stmt.definition); | 325 Expression definition = visitExpression(stmt.definition); |
281 if (firstStatement == stmt && isFirstOccurrence) { | 326 |
| 327 // Try to pull into initializer. |
| 328 if (firstStatement == stmt && isFirstOccurrence && isDeclaredHere) { |
| 329 if (isNullLiteral(definition)) definition = null; |
282 addDeclaration(stmt.variable, definition); | 330 addDeclaration(stmt.variable, definition); |
283 firstStatement = stmt.next; | 331 firstStatement = stmt.next; |
284 } else { | 332 visitStatement(stmt.next); |
285 statementBuffer.add(new ExpressionStatement(makeAssignment( | 333 return; |
286 visitVariable(stmt.variable), | |
287 definition))); | |
288 } | 334 } |
| 335 |
| 336 // Emit a variable declaration if we are required to do so. |
| 337 // This is to ensure that a fresh closure variable is created. |
| 338 if (stmt.isDeclaration) { |
| 339 assert(isFirstOccurrence); |
| 340 assert(isDeclaredHere); |
| 341 if (isNullLiteral(definition)) definition = null; |
| 342 VariableDeclaration decl = new VariableDeclaration(name, definition) |
| 343 ..element = stmt.variable.element; |
| 344 declaredVariables.add(stmt.variable); |
| 345 statementBuffer.add(new VariableDeclarations([decl])); |
| 346 visitStatement(stmt.next); |
| 347 return; |
| 348 } |
| 349 |
| 350 statementBuffer.add(new ExpressionStatement(makeAssignment( |
| 351 visitVariable(stmt.variable), |
| 352 definition))); |
289 visitStatement(stmt.next); | 353 visitStatement(stmt.next); |
290 } | 354 } |
291 | 355 |
292 void visitReturn(tree.Return stmt) { | 356 void visitReturn(tree.Return stmt) { |
293 Expression inner = visitExpression(stmt.value); | 357 Expression inner = visitExpression(stmt.value); |
294 statementBuffer.add(new Return(inner)); | 358 statementBuffer.add(new Return(inner)); |
295 } | 359 } |
296 | 360 |
297 void visitBreak(tree.Break stmt) { | 361 void visitBreak(tree.Break stmt) { |
298 tree.Statement fall = fallthrough; | 362 tree.Statement fall = fallthrough; |
(...skipping 25 matching lines...) Expand all Loading... |
324 List<Statement> thenBuffer = statementBuffer = <Statement>[]; | 388 List<Statement> thenBuffer = statementBuffer = <Statement>[]; |
325 visitStatement(stmt.thenStatement); | 389 visitStatement(stmt.thenStatement); |
326 List<Statement> elseBuffer = statementBuffer = <Statement>[]; | 390 List<Statement> elseBuffer = statementBuffer = <Statement>[]; |
327 visitStatement(stmt.elseStatement); | 391 visitStatement(stmt.elseStatement); |
328 savedBuffer.add( | 392 savedBuffer.add( |
329 new If(condition, new Block(thenBuffer), new Block(elseBuffer))); | 393 new If(condition, new Block(thenBuffer), new Block(elseBuffer))); |
330 statementBuffer = savedBuffer; | 394 statementBuffer = savedBuffer; |
331 } | 395 } |
332 | 396 |
333 void visitWhileTrue(tree.WhileTrue stmt) { | 397 void visitWhileTrue(tree.WhileTrue stmt) { |
334 List<Expression> updates = stmt.updates.reversed | |
335 .map(visitExpression) | |
336 .toList(growable:false); | |
337 | |
338 List<Statement> savedBuffer = statementBuffer; | 398 List<Statement> savedBuffer = statementBuffer; |
339 tree.Statement savedFallthrough = fallthrough; | 399 tree.Statement savedFallthrough = fallthrough; |
340 statementBuffer = <Statement>[]; | 400 statementBuffer = <Statement>[]; |
341 fallthrough = stmt; | 401 fallthrough = stmt; |
342 | 402 |
343 visitStatement(stmt.body); | 403 visitStatement(stmt.body); |
344 Statement body = new Block(statementBuffer); | 404 Statement body = new Block(statementBuffer); |
345 Statement statement = new For(null, null, updates, body); | 405 Statement statement = new While(new Literal(new dart2js.TrueConstant()), |
| 406 body); |
346 if (usedLabels.remove(stmt.label.name)) { | 407 if (usedLabels.remove(stmt.label.name)) { |
347 statement = new LabeledStatement(stmt.label.name, statement); | 408 statement = new LabeledStatement(stmt.label.name, statement); |
348 } | 409 } |
349 savedBuffer.add(statement); | 410 savedBuffer.add(statement); |
350 | 411 |
351 statementBuffer = savedBuffer; | 412 statementBuffer = savedBuffer; |
352 fallthrough = savedFallthrough; | 413 fallthrough = savedFallthrough; |
353 } | 414 } |
354 | 415 |
355 void visitWhileCondition(tree.WhileCondition stmt) { | 416 void visitWhileCondition(tree.WhileCondition stmt) { |
356 Expression condition = visitExpression(stmt.condition); | 417 Expression condition = visitExpression(stmt.condition); |
357 List<Expression> updates = stmt.updates.reversed | |
358 .map(visitExpression) | |
359 .toList(growable:false); | |
360 | 418 |
361 List<Statement> savedBuffer = statementBuffer; | 419 List<Statement> savedBuffer = statementBuffer; |
362 tree.Statement savedFallthrough = fallthrough; | 420 tree.Statement savedFallthrough = fallthrough; |
363 statementBuffer = <Statement>[]; | 421 statementBuffer = <Statement>[]; |
364 fallthrough = stmt; | 422 fallthrough = stmt; |
365 | 423 |
366 visitStatement(stmt.body); | 424 visitStatement(stmt.body); |
367 Statement body = new Block(statementBuffer); | 425 Statement body = new Block(statementBuffer); |
368 Statement statement; | 426 Statement statement; |
369 if (updates.isEmpty) { | 427 statement = new While(condition, body); |
370 // while(E) is the same as for(;E;), but the former is nicer | |
371 statement = new While(condition, body); | |
372 } else { | |
373 statement = new For(null, condition, updates, body); | |
374 } | |
375 if (usedLabels.remove(stmt.label.name)) { | 428 if (usedLabels.remove(stmt.label.name)) { |
376 statement = new LabeledStatement(stmt.label.name, statement); | 429 statement = new LabeledStatement(stmt.label.name, statement); |
377 } | 430 } |
378 savedBuffer.add(statement); | 431 savedBuffer.add(statement); |
379 | 432 |
380 statementBuffer = savedBuffer; | 433 statementBuffer = savedBuffer; |
381 fallthrough = savedFallthrough; | 434 fallthrough = savedFallthrough; |
382 | 435 |
383 visitStatement(stmt.next); | 436 visitStatement(stmt.next); |
384 } | 437 } |
385 | 438 |
386 Expression visitConstant(tree.Constant exp) { | 439 Expression visitConstant(tree.Constant exp) { |
387 return emitConstant(exp.expression); | 440 return emitConstant(exp.expression); |
388 } | 441 } |
389 | 442 |
390 Expression visitThis(tree.This exp) { | 443 Expression visitThis(tree.This exp) { |
391 return new This(); | 444 return new This(); |
392 } | 445 } |
393 | 446 |
394 Expression visitReifyTypeVar(tree.ReifyTypeVar exp) { | 447 Expression visitReifyTypeVar(tree.ReifyTypeVar exp) { |
395 return new ReifyTypeVar(exp.element.name) | 448 return new ReifyTypeVar(exp.typeVariable.name) |
396 ..element = exp.element; | 449 ..element = exp.typeVariable; |
397 } | 450 } |
398 | 451 |
399 Expression visitLiteralList(tree.LiteralList exp) { | 452 Expression visitLiteralList(tree.LiteralList exp) { |
400 return new LiteralList( | 453 return new LiteralList( |
401 exp.values.map(visitExpression).toList(growable: false), | 454 exp.values.map(visitExpression).toList(growable: false), |
402 typeArgument: emitOptionalType(exp.type.typeArguments.single)); | 455 typeArgument: emitOptionalType(exp.type.typeArguments.single)); |
403 } | 456 } |
404 | 457 |
405 Expression visitLiteralMap(tree.LiteralMap exp) { | 458 Expression visitLiteralMap(tree.LiteralMap exp) { |
406 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate( | 459 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate( |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 | 584 |
532 Expression visitNot(tree.Not exp) { | 585 Expression visitNot(tree.Not exp) { |
533 return new UnaryOperator('!', visitExpression(exp.operand)); | 586 return new UnaryOperator('!', visitExpression(exp.operand)); |
534 } | 587 } |
535 | 588 |
536 Expression visitVariable(tree.Variable exp) { | 589 Expression visitVariable(tree.Variable exp) { |
537 return new Identifier(getVariableName(exp)) | 590 return new Identifier(getVariableName(exp)) |
538 ..element = exp.element; | 591 ..element = exp.element; |
539 } | 592 } |
540 | 593 |
| 594 FunctionExpression makeSubFunction(tree.FunctionDefinition function) { |
| 595 return new ASTEmitter.inner(this).emit(function); |
| 596 } |
| 597 |
| 598 Expression visitFunctionExpression(tree.FunctionExpression exp) { |
| 599 return makeSubFunction(exp.definition)..name = null; |
| 600 } |
| 601 |
| 602 void visitFunctionDeclaration(tree.FunctionDeclaration node) { |
| 603 assert(variableNames[node.variable] == null); |
| 604 String name = getVariableName(node.variable); |
| 605 FunctionExpression inner = makeSubFunction(node.definition); |
| 606 inner.name = name; |
| 607 FunctionDeclaration decl = new FunctionDeclaration(inner); |
| 608 declaredVariables.add(node.variable); |
| 609 statementBuffer.add(decl); |
| 610 visitStatement(node.next); |
| 611 } |
| 612 |
541 TypeAnnotation emitType(DartType type) { | 613 TypeAnnotation emitType(DartType type) { |
542 if (type is GenericType) { | 614 if (type is GenericType) { |
543 return new TypeAnnotation( | 615 return new TypeAnnotation( |
544 type.element.name, | 616 type.element.name, |
545 type.typeArguments.map(emitType).toList(growable:false)) | 617 type.typeArguments.map(emitType).toList(growable:false)) |
546 ..dartType = type; | 618 ..dartType = type; |
547 } else if (type is VoidType) { | 619 } else if (type is VoidType) { |
548 return new TypeAnnotation('void') | 620 return new TypeAnnotation('void') |
549 ..dartType = type; | 621 ..dartType = type; |
550 } else if (type is TypeVariableType) { | 622 } else if (type is TypeVariableType) { |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
629 return new LiteralSymbol(exp.name); | 701 return new LiteralSymbol(exp.name); |
630 } | 702 } |
631 | 703 |
632 Expression visitType(TypeConstExp exp) { | 704 Expression visitType(TypeConstExp exp) { |
633 DartType type = exp.type; | 705 DartType type = exp.type; |
634 return new LiteralType(type.name) | 706 return new LiteralType(type.name) |
635 ..type = type; | 707 ..type = type; |
636 } | 708 } |
637 | 709 |
638 Expression visitVariable(VariableConstExp exp) { | 710 Expression visitVariable(VariableConstExp exp) { |
639 String name = parent.getConstantName(exp.element); | 711 Element element = exp.element; |
| 712 if (element.kind != ElementKind.VARIABLE) { |
| 713 return new Identifier(element.name)..element = element; |
| 714 } |
| 715 String name = parent.getConstantName(element); |
640 return new Identifier(name) | 716 return new Identifier(name) |
641 ..element = exp.element; | 717 ..element = element; |
642 } | 718 } |
643 | 719 |
644 Expression visitFunction(FunctionConstExp exp) { | 720 Expression visitFunction(FunctionConstExp exp) { |
645 return new Identifier(exp.element.name) | 721 return new Identifier(exp.element.name) |
646 ..element = exp.element; | 722 ..element = exp.element; |
647 } | 723 } |
648 | 724 |
649 } | 725 } |
| 726 |
| 727 /// Moves function parameters into a separate variable if one of its uses is |
| 728 /// shadowed by an inner function parameter. |
| 729 /// This artifact is necessary because function parameters cannot be renamed. |
| 730 class UnshadowParameters extends tree.RecursiveVisitor { |
| 731 |
| 732 /// Maps parameter names to their bindings. |
| 733 Map<String, tree.Variable> environment = <String, tree.Variable>{}; |
| 734 |
| 735 /// Parameters that are currently shadowed by another parameter. |
| 736 Set<tree.Variable> shadowedParameters = new Set<tree.Variable>(); |
| 737 |
| 738 /// Parameters that are used in a context where it is shadowed. |
| 739 Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>(); |
| 740 |
| 741 void unshadow(tree.FunctionDefinition definition) { |
| 742 visitFunctionDefinition(definition); |
| 743 } |
| 744 |
| 745 visitFunctionDefinition(tree.FunctionDefinition definition) { |
| 746 var oldShadow = shadowedParameters; |
| 747 var oldEnvironment = environment; |
| 748 environment = new Map<String, tree.Variable>.from(environment); |
| 749 shadowedParameters = new Set<tree.Variable>.from(shadowedParameters); |
| 750 for (tree.Variable param in definition.parameters) { |
| 751 tree.Variable oldVariable = environment[param.element.name]; |
| 752 if (oldVariable != null) { |
| 753 shadowedParameters.add(oldVariable); |
| 754 } |
| 755 environment[param.element.name] = param; |
| 756 } |
| 757 visitStatement(definition.body); |
| 758 environment = oldEnvironment; |
| 759 shadowedParameters = oldShadow; |
| 760 |
| 761 for (int i=0; i<definition.parameters.length; i++) { |
| 762 tree.Variable param = definition.parameters[i]; |
| 763 if (hasShadowedUse.remove(param)) { |
| 764 tree.Variable newParam = new tree.Variable(definition, param.element); |
| 765 definition.parameters[i] = newParam; |
| 766 definition.body = new tree.Assign(param, newParam, definition.body); |
| 767 newParam.writeCount = 1; // Being a parameter counts as a write. |
| 768 } |
| 769 } |
| 770 } |
| 771 |
| 772 visitVariable(tree.Variable variable) { |
| 773 if (shadowedParameters.contains(variable)) { |
| 774 hasShadowedUse.add(variable); |
| 775 } |
| 776 } |
| 777 |
| 778 } |
OLD | NEW |