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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/dart_backend/dart_codegen.dart

Issue 366853007: dart2dart: Support for inner functions in new IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: SVN rebase Created 6 years, 5 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 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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698