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

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

Issue 1155463005: dart2js cps: Remove dart2dart from cps pipeline and clean up. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 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
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;
8 import 'backend_ast_nodes.dart'; 7 import 'backend_ast_nodes.dart';
9 import '../constants/expressions.dart';
10 import '../constants/values.dart';
11 import '../dart_types.dart'; 8 import '../dart_types.dart';
12 import '../elements/elements.dart'; 9 import '../elements/elements.dart';
13 import '../elements/modelx.dart' as modelx;
14 import '../universe/universe.dart';
15 import '../tree/tree.dart' as tree show Modifiers;
16
17 /// Translates the dart_tree IR to Dart backend AST.
18 RootNode emit(tree.RootNode root) {
19 return new ASTEmitter().emit(root);
20 }
21
22 // TODO(johnniwinther): Split into function/block state.
23 class BuilderContext<T> {
24 /// Builder context for the enclosing function, or null if the current
25 /// function is not a local function.
26 BuilderContext<T> _parent;
27
28 /// Variables to be hoisted at the top of the current function.
29 final List<VariableDeclaration> variables = <VariableDeclaration>[];
30
31 /// Maps variables to their name.
32 final Map<tree.Variable, String> variableNames;
33
34 /// Maps local constants to their name.
35 final Map<VariableElement, String> constantNames =
36 <VariableElement, String>{};
37
38 /// Variables that have had their declaration created.
39 final Set<tree.Variable> declaredVariables = new Set<tree.Variable>();
40
41 /// Variables that are used as catch handler parameters.
42 final Set<tree.Variable> handlerVariables = new Set<tree.Variable>();
43
44 /// Variable names that have already been used. Used to avoid name clashes.
45 final Set<String> usedVariableNames;
46
47 /// Statements emitted by the most recent call to [visitStatement].
48 List<T> _statementBuffer = <T>[];
49
50 /// The element currently being emitted.
51 ExecutableElement currentElement;
52
53 /// Bookkeeping object needed to synthesize a variable declaration.
54 final modelx.VariableList variableList
55 = new modelx.VariableList(tree.Modifiers.EMPTY);
56
57 /// Input to [visitStatement]. Denotes the statement that will execute next
58 /// if the statements produced by [visitStatement] complete normally.
59 /// Set to null if control will fall over the end of the method.
60 tree.Statement fallthrough = null;
61
62 /// Labels that could not be eliminated using fallthrough.
63 final Set<tree.Label> _usedLabels = new Set<tree.Label>();
64
65 final bool inInitializer;
66
67 /// The first dart_tree statement that is not converted to a variable
68 /// initializer.
69 tree.Statement firstStatement;
70
71 BuilderContext() : usedVariableNames = new Set<String>(),
72 inInitializer = false,
73 variableNames = <tree.Variable, String>{};
74
75 BuilderContext.inner(BuilderContext<T> parent)
76 : this._parent = parent,
77 usedVariableNames = parent.usedVariableNames,
78 inInitializer = false,
79 variableNames = <tree.Variable, String>{};
80
81 BuilderContext.initializer(BuilderContext<T> parent)
82 : this._parent = parent,
83 usedVariableNames = parent.usedVariableNames,
84 inInitializer = true,
85 variableNames =
86 new Map<tree.Variable, String>.from(parent.variableNames);
87
88 // TODO(johnniwinther): Fully encapsulate handling of parameter, variable
89 // and local function declarations.
90 void addDeclaration(tree.Variable variable, [Expression initializer]) {
91 assert(!declaredVariables.contains(variable));
92 String name = getVariableName(variable);
93 VariableDeclaration decl = new VariableDeclaration(name, initializer);
94 decl.element = variable.element;
95 declaredVariables.add(variable);
96 variables.add(decl);
97 }
98
99 /// Creates an [Identifier] referring to the given variable.
100 Expression makeVariableAccess(tree.Variable variable) {
101 return new Identifier(getVariableName(variable))
102 ..element = variable.element;
103 }
104
105 /// Generates a name for the given variable and synthesizes an element for it,
106 /// if necessary.
107 String getVariableName(tree.Variable variable) {
108 // If the variable belongs to an enclosing function, ask the parent emitter
109 // for the variable name.
110 if (!inInitializer && variable.host != currentElement) {
111 return _parent.getVariableName(variable);
112 }
113
114 // Get the name if we already have one.
115 String name = variableNames[variable];
116 if (name != null) {
117 return name;
118 }
119
120 // Synthesize a variable name that isn't used elsewhere.
121 // The [usedVariableNames] set is shared between nested emitters,
122 // so this also prevents clash with variables in an enclosing/inner scope.
123 // The renaming phase after codegen will further prefix local variables
124 // so they cannot clash with top-level variables or fields.
125 String prefix = variable.element == null ? 'v' : variable.element.name;
126 int counter = 0;
127 name = variable.element == null ? '$prefix$counter' : variable.element.name;
128 while (!usedVariableNames.add(name)) {
129 ++counter;
130 name = '$prefix$counter';
131 }
132 variableNames[variable] = name;
133
134 // Synthesize an element for the variable
135 if (variable.element == null || name != variable.element.name) {
136 // TODO(johnniwinther): Replace by synthetic [Entity].
137 variable.element = new _SyntheticLocalVariableElement(
138 name,
139 currentElement,
140 variableList);
141 }
142 return name;
143 }
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
164 String getConstantName(VariableElement element) {
165 assert(element.kind == ElementKind.VARIABLE);
166 if (element.enclosingElement != currentElement) {
167 return _parent.getConstantName(element);
168 }
169 String name = constantNames[element];
170 if (name != null) {
171 return name;
172 }
173 String prefix = element.name;
174 int counter = 0;
175 name = element.name;
176 while (!usedVariableNames.add(name)) {
177 ++counter;
178 name = '$prefix$counter';
179 }
180 constantNames[element] = name;
181 return name;
182 }
183
184 List<T> inSubcontext(f(BuilderContext<T> subcontext),
185 {tree.Statement fallthrough}) {
186 List<T> savedBuffer = this._statementBuffer;
187 tree.Statement savedFallthrough = this.fallthrough;
188 List<T> buffer = this._statementBuffer = <T>[];
189 if (fallthrough != null) {
190 this.fallthrough = fallthrough;
191 }
192 f(this);
193 this.fallthrough = savedFallthrough;
194 this._statementBuffer = savedBuffer;
195 return buffer;
196 }
197
198 /// Removes a trailing "return null" from the current block.
199 void removeTrailingReturn(bool isReturnNull(T statement)) {
200 if (_statementBuffer.isEmpty) return;
201 if (isReturnNull(_statementBuffer.last)) {
202 _statementBuffer.removeLast();
203 }
204 }
205
206 /// Register [label] as used.
207 void useLabel(tree.Label label) {
208 _usedLabels.add(label);
209 }
210
211 /// Remove [label] and return `true` if it was used.
212 bool removeUsedLabel(tree.Label label) {
213 return _usedLabels.remove(label);
214 }
215
216 /// Add [statement] to the current block.
217 void addStatement(T statement) {
218 _statementBuffer.add(statement);
219 }
220
221 /// The statements in the current block.
222 Iterable<T> get statements => _statementBuffer;
223 }
224
225 /// Translates the dart_tree IR to Dart backend AST.
226 /// An instance of this class should only be used once; a fresh emitter
227 /// must be created for each function to be emitted.
228 class ASTEmitter
229 extends tree.StatementVisitor1<dynamic, BuilderContext<Statement>>
230 with tree.ExpressionVisitor1<Expression, BuilderContext<Statement>>,
231 tree.RootVisitor1<RootNode, BuilderContext<Statement>>,
232 tree.InitializerVisitor1<Initializer, BuilderContext<Statement>> {
233
234 RootNode emit(tree.RootNode node) {
235 return visitRootNode(node, new BuilderContext<Statement>());
236 }
237
238 @override
239 FieldDefinition visitFieldDefinition(tree.FieldDefinition definition,
240 BuilderContext<Statement> context) {
241 context.currentElement = definition.element;
242 Expression initializer;
243 if (!definition.isEmpty) {
244 visitStatement(definition.body, context);
245 List<Statement> bodyParts;
246 for (tree.Variable variable in context.variableNames.keys) {
247 if (!context.declaredVariables.contains(variable)) {
248 context.addDeclaration(variable);
249 }
250 }
251 if (context.variables.length > 0) {
252 bodyParts = new List<Statement>();
253 bodyParts.add(new VariableDeclarations(context.variables));
254 bodyParts.addAll(context.statements);
255 } else {
256 bodyParts = context.statements;
257 }
258 initializer = ensureExpression(bodyParts);
259 }
260
261 return new FieldDefinition(definition.element, initializer);
262 }
263
264 /// Returns an expression that will evaluate all of [bodyParts].
265 /// If [bodyParts] is a single [Return] return its value.
266 /// Otherwise wrap the body-parts in an immediately invoked closure.
267 Expression ensureExpression(List<Statement> bodyParts) {
268 if (bodyParts.length == 1) {
269 Statement onlyStatement = bodyParts.single;
270 if (onlyStatement is Return) {
271 return onlyStatement.expression;
272 }
273 }
274 Statement body = new Block(bodyParts);
275 FunctionExpression function =
276 new FunctionExpression(new Parameters([]), body);
277 function.element = null;
278 return new CallFunction(function, []);
279 }
280
281 bool _recognizeTrailingReturn(Statement statement) {
282 if (statement is Return) {
283 Expression expr = statement.expression;
284 if (expr == null || expr is Literal && expr.value.isNull) {
285 return true;
286 }
287 }
288 return false;
289 }
290
291 @override
292 FunctionExpression visitConstructorDefinition(
293 tree.ConstructorDefinition definition,
294 BuilderContext<Statement> context) {
295 context.currentElement = definition.element;
296
297 Parameters parameters = emitRootParameters(
298 definition, definition.defaultParameterValues, context);
299
300 // Declare parameters.
301 for (tree.Variable param in definition.parameters) {
302 context.variableNames[param] = param.element.name;
303 context.usedVariableNames.add(param.element.name);
304 context.declaredVariables.add(param);
305 }
306
307 List<Initializer> initializers;
308 Statement body;
309
310 if (!definition.isEmpty) {
311 initializers =
312 definition.initializers.map((tree.Initializer initializer) {
313 return visitInitializer(initializer, context);
314 }).toList();
315
316 context.firstStatement = definition.body;
317 visitStatement(definition.body, context);
318 context.removeTrailingReturn(_recognizeTrailingReturn);
319
320 // Some of the variable declarations have already been added
321 // if their first assignment could be pulled into the initializer.
322 // Add the remaining variable declarations now.
323 context.declareRemainingVariables();
324
325 // Add constant declarations.
326 List<VariableDeclaration> constants = <VariableDeclaration>[];
327 for (ConstDeclaration constDecl in definition.localConstants) {
328 if (!context.constantNames.containsKey(constDecl.element)) {
329 continue; // Discard unused constants declarations.
330 }
331 String name = context.getConstantName(constDecl.element);
332 Expression value =
333 ConstantEmitter.createExpression(constDecl.expression, context);
334 VariableDeclaration decl = new VariableDeclaration(name, value);
335 decl.element = constDecl.element;
336 constants.add(decl);
337 }
338
339 List<Statement> bodyParts = [];
340 if (constants.length > 0) {
341 bodyParts.add(new VariableDeclarations(constants, isConst: true));
342 }
343 if (context.variables.length > 0) {
344 bodyParts.add(new VariableDeclarations(context.variables));
345 }
346 bodyParts.addAll(context.statements);
347 body = new Block(bodyParts);
348 }
349 return new ConstructorDefinition(
350 parameters,
351 body,
352 initializers,
353 context.currentElement.name,
354 definition.element.isConst)..element = context.currentElement;
355 }
356
357 @override
358 FunctionExpression visitFunctionDefinition(
359 tree.FunctionDefinition definition,
360 BuilderContext<Statement> context) {
361 context.currentElement = definition.element;
362
363 Parameters parameters = emitRootParameters(
364 definition, definition.defaultParameterValues, context);
365
366 // Declare parameters.
367 for (tree.Variable param in definition.parameters) {
368 context.variableNames[param] = param.element.name;
369 context.usedVariableNames.add(param.element.name);
370 context.declaredVariables.add(param);
371 }
372
373 Statement body;
374 if (definition.isEmpty) {
375 body = new EmptyStatement();
376 } else {
377 context.firstStatement = definition.body;
378 visitStatement(definition.body, context);
379 context.removeTrailingReturn(_recognizeTrailingReturn);
380
381 // Some of the variable declarations have already been added
382 // if their first assignment could be pulled into the initializer.
383 // Add the remaining variable declarations now.
384 context.declareRemainingVariables();
385
386 // Add constant declarations.
387 List<VariableDeclaration> constants = <VariableDeclaration>[];
388 for (ConstDeclaration constDecl in definition.localConstants) {
389 if (!context.constantNames.containsKey(constDecl.element)) {
390 continue; // Discard unused constants declarations.
391 }
392 String name = context.getConstantName(constDecl.element);
393 Expression value =
394 ConstantEmitter.createExpression(constDecl.expression, context);
395 VariableDeclaration decl = new VariableDeclaration(name, value);
396 decl.element = constDecl.element;
397 constants.add(decl);
398 }
399
400 List<Statement> bodyParts = [];
401 if (constants.length > 0) {
402 bodyParts.add(new VariableDeclarations(constants, isConst: true));
403 }
404 if (context.variables.length > 0) {
405 bodyParts.add(new VariableDeclarations(context.variables));
406 }
407 bodyParts.addAll(context.statements);
408
409 body = new Block(bodyParts);
410 }
411 FunctionType functionType = context.currentElement.type;
412
413 return new FunctionExpression(
414 parameters,
415 body,
416 name: context.currentElement.name,
417 returnType: TypeGenerator.createOptionalType(functionType.returnType),
418 isGetter: context.currentElement.isGetter,
419 isSetter: context.currentElement.isSetter)
420 ..element = context.currentElement;
421 }
422
423 /// Emits parameters that are not nested inside other parameters.
424 /// Root parameters can have default values, while inner parameters cannot.
425 Parameters emitRootParameters(tree.RootNode function,
426 List<ConstantExpression> defaults,
427 BuilderContext<Statement> context) {
428 FunctionType functionType = function.element.type;
429 List<Parameter> required = TypeGenerator.createParameters(
430 functionType.parameterTypes,
431 context: context,
432 elements: function.parameters.map((p) => p.element));
433 bool optionalParametersAreNamed = !functionType.namedParameters.isEmpty;
434 List<Parameter> optional = TypeGenerator.createParameters(
435 optionalParametersAreNamed
436 ? functionType.namedParameterTypes
437 : functionType.optionalParameterTypes,
438 context: context,
439 defaultValues: defaults,
440 elements: function.parameters.skip(required.length)
441 .map((p) => p.element));
442 return new Parameters(required, optional, optionalParametersAreNamed);
443 }
444
445 /// True if the two expressions are a reference to the same variable.
446 bool isSameVariable(Receiver e1, Receiver e2) {
447 return e1 is Identifier &&
448 e2 is Identifier &&
449 e1.element is VariableElement &&
450 e1.element == e2.element;
451 }
452
453 Expression makeAssignment(Expression target, Expression value) {
454 // Try to print as compound assignment or increment
455 if (value is BinaryOperator && isCompoundableOperator(value.operator)) {
456 Receiver leftOperand = value.left;
457 Expression rightOperand = value.right;
458 bool valid = false;
459 if (isSameVariable(target, leftOperand)) {
460 valid = true;
461 } else if (target is FieldExpression &&
462 leftOperand is FieldExpression &&
463 isSameVariable(target.object, leftOperand.object) &&
464 target.fieldName == leftOperand.fieldName) {
465 valid = true;
466 } else if (target is IndexExpression &&
467 leftOperand is IndexExpression &&
468 isSameVariable(target.object, leftOperand.object) &&
469 isSameVariable(target.index, leftOperand.index)) {
470 valid = true;
471 }
472 if (valid) {
473 if (rightOperand is Literal && rightOperand.value.isOne &&
474 (value.operator == '+' || value.operator == '-')) {
475 return new Increment.prefix(target, value.operator + value.operator);
476 } else {
477 return new Assignment(target, value.operator + '=', rightOperand);
478 }
479 }
480 }
481 // Fall back to regular assignment
482 return new Assignment(target, '=', value);
483 }
484
485 Block visitInSubContext(tree.Statement statement,
486 BuilderContext<Statement> context,
487 {tree.Statement fallthrough}) {
488 return new Block(context.inSubcontext(
489 (BuilderContext<Statement> subcontext) {
490 visitStatement(statement, subcontext);
491 }, fallthrough: fallthrough));
492 }
493
494 void addLabeledStatement(tree.Label label,
495 Statement statement,
496 BuilderContext<Statement> context) {
497 if (context.removeUsedLabel(label)) {
498 context.addStatement(new LabeledStatement(label.name, statement));
499 } else {
500 context.addStatement(statement);
501 }
502 }
503
504 @override
505 void visitExpressionStatement(tree.ExpressionStatement stmt,
506 BuilderContext<Statement> context) {
507 if (stmt.expression is tree.Assign) {
508 emitAssignStatement(stmt.expression, stmt, context);
509 return;
510 }
511 Expression e = visitExpression(stmt.expression, context);
512 context.addStatement(new ExpressionStatement(e));
513 visitStatement(stmt.next, context);
514 }
515
516 @override
517 void visitVariableDeclaration(tree.VariableDeclaration node,
518 BuilderContext<Statement> context) {
519 Expression value = visitExpression(node.value, context);
520 String name = context.getVariableName(node.variable);
521 VariableDeclaration decl = new VariableDeclaration(name, value)
522 ..element = node.variable.element;
523 context.declaredVariables.add(node.variable);
524 context.addStatement(new VariableDeclarations([decl]));
525 visitStatement(node.next, context);
526 }
527
528 @override
529 void visitLabeledStatement(tree.LabeledStatement stmt,
530 BuilderContext<Statement> context) {
531 Block block = visitInSubContext(stmt.body, context, fallthrough: stmt.next);
532 addLabeledStatement(stmt.label, block, context);
533
534 visitStatement(stmt.next, context);
535 }
536
537 bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull;
538
539 void emitAssignStatement(tree.Assign assign,
540 tree.Statement statement,
541 BuilderContext<Statement> context) {
542 // Try to emit a local function declaration. This is useful for functions
543 // that may occur in expression context, but could not be inlined anywhere.
544 if (assign.variable.element is FunctionElement &&
545 assign.value is tree.FunctionExpression &&
546 !context.declaredVariables.contains(assign.variable) &&
547 assign.variable.writeCount == 1) {
548 tree.FunctionExpression functionExp = assign.value;
549 FunctionExpression function =
550 makeSubFunction(functionExp.definition, context);
551 FunctionDeclaration decl = new FunctionDeclaration(function);
552 context.addStatement(decl);
553 context.declaredVariables.add(assign.variable);
554
555 visitStatement(statement.next, context);
556 return;
557 }
558
559 Expression definition = visitExpression(assign.value, context);
560 bool isFirstOccurrence = (context.variableNames[assign.variable] == null);
561 bool isDeclaredHere = assign.variable.host == context.currentElement;
562 bool isFirstStatement = context.firstStatement == statement;
563
564 // Try to pull into initializer.
565 if (isFirstStatement && isFirstOccurrence && isDeclaredHere) {
566 if (isNullLiteral(definition)) definition = null;
567 context.addDeclaration(assign.variable, definition);
568 context.firstStatement = statement.next;
569 visitStatement(statement.next, context);
570 return;
571 }
572
573 context.addStatement(new ExpressionStatement(makeAssignment(
574 context.makeVariableAccess(assign.variable),
575 definition)));
576 visitStatement(statement.next, context);
577 }
578
579 @override
580 void visitReturn(tree.Return stmt, BuilderContext<Statement> context) {
581 if (context.currentElement.isGenerativeConstructor &&
582 !context.inInitializer) {
583 assert(() {
584 tree.Expression value = stmt.value;
585 return value is tree.Constant && value.value.isNull;
586 });
587 context.addStatement(new Return(null));
588 } else {
589 Expression inner = visitExpression(stmt.value, context);
590 context.addStatement(new Return(inner));
591 }
592 }
593
594 @override
595 void visitThrow(tree.Throw stmt, BuilderContext<Statement> context) {
596 Expression value = visitExpression(stmt.value, context);
597 context.addStatement(new ExpressionStatement(new Throw(value)));
598 }
599
600 @override
601 void visitRethrow(tree.Rethrow stmt, BuilderContext<Statement> context) {
602 context.addStatement(new Rethrow());
603 }
604
605 @override
606 void visitBreak(tree.Break stmt, BuilderContext<Statement> context) {
607 tree.Statement fall = context.fallthrough;
608 if (stmt.target.binding.next == fall) {
609 // Fall through to break target
610 } else if (fall is tree.Break && fall.target == stmt.target) {
611 // Fall through to equivalent break
612 } else {
613 context.useLabel(stmt.target);
614 context.addStatement(new Break(stmt.target.name));
615 }
616 }
617
618 @override
619 void visitContinue(tree.Continue stmt,
620 BuilderContext<Statement> context) {
621 tree.Statement fall = context.fallthrough;
622 if (stmt.target.binding == fall) {
623 // Fall through to continue target
624 } else if (fall is tree.Continue && fall.target == stmt.target) {
625 // Fall through to equivalent continue
626 } else {
627 context.useLabel(stmt.target);
628 context.addStatement(new Continue(stmt.target.name));
629 }
630 }
631
632 @override
633 void visitIf(tree.If stmt,
634 BuilderContext<Statement> context) {
635 Expression condition = visitExpression(stmt.condition, context);
636 Block thenBlock = visitInSubContext(stmt.thenStatement, context);
637 Block elseBlock= visitInSubContext(stmt.elseStatement, context);
638 context.addStatement(new If(condition, thenBlock, elseBlock));
639 }
640
641 @override
642 void visitWhileTrue(tree.WhileTrue stmt,
643 BuilderContext<Statement> context) {
644 Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
645 Statement statement =
646 new While(new Literal(new TrueConstantValue()), body);
647 addLabeledStatement(stmt.label, statement, context);
648 }
649
650 @override
651 void visitWhileCondition(tree.WhileCondition stmt,
652 BuilderContext<Statement> context) {
653 Expression condition = visitExpression(stmt.condition, context);
654 Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
655 Statement statement = new While(condition, body);
656 addLabeledStatement(stmt.label, statement, context);
657
658 visitStatement(stmt.next, context);
659 }
660
661 @override
662 void visitTry(tree.Try stmt,
663 BuilderContext<Statement> context) {
664 Block tryBody = visitInSubContext(stmt.tryBody, context);
665 Block catchBody = visitInSubContext(stmt.catchBody, context);
666 CatchBlock catchBlock;
667 tree.Variable exceptionVariable = stmt.catchParameters[0];
668 context.handlerVariables.add(exceptionVariable);
669 VariableDeclaration exceptionParameter =
670 new VariableDeclaration(context.getVariableName(exceptionVariable));
671 exceptionParameter.element = exceptionVariable.element;
672 stmt.catchParameters.forEach(context.declaredVariables.add);
673 if (stmt.catchParameters.length == 2) {
674 tree.Variable stackTraceVariable = stmt.catchParameters[1];
675 context.handlerVariables.add(stackTraceVariable);
676 VariableDeclaration stackTraceParameter =
677 new VariableDeclaration(context.getVariableName(stackTraceVariable));
678 stackTraceParameter.element = stackTraceVariable.element;
679 catchBlock = new CatchBlock(catchBody,
680 exceptionVar: exceptionParameter,
681 stackVar: stackTraceParameter);
682 } else {
683 assert(stmt.catchParameters.length == 1);
684 catchBlock = new CatchBlock(catchBody,
685 exceptionVar: exceptionParameter);
686 }
687 context.addStatement(new Try(tryBody, <CatchBlock>[catchBlock], null));
688 }
689
690 @override
691 Expression visitConstant(tree.Constant exp,
692 BuilderContext<Statement> context) {
693 return ConstantEmitter.createExpression(exp.expression, context);
694 }
695
696 @override
697 Expression visitThis(tree.This exp,
698 BuilderContext<Statement> context) {
699 return new This();
700 }
701
702 @override
703 Expression visitReifyTypeVar(tree.ReifyTypeVar exp,
704 BuilderContext<Statement> context) {
705 return new ReifyTypeVar(exp.typeVariable.name)
706 ..element = exp.typeVariable;
707 }
708
709 List<Expression> visitExpressions(List<tree.Expression> expressions,
710 BuilderContext<Statement> context) {
711 return expressions.map((expression) => visitExpression(expression, context))
712 .toList(growable: false);
713 }
714
715 @override
716 Expression visitLiteralList(tree.LiteralList exp,
717 BuilderContext<Statement> context) {
718 return new LiteralList(visitExpressions(exp.values, context),
719 typeArgument:
720 TypeGenerator.createOptionalType(exp.type.typeArguments.single));
721 }
722
723 @override
724 Expression visitLiteralMap(tree.LiteralMap exp,
725 BuilderContext<Statement> context) {
726 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
727 exp.entries.length,
728 (i) => new LiteralMapEntry(
729 visitExpression(exp.entries[i].key, context),
730 visitExpression(exp.entries[i].value, context)));
731 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
732 ? null
733 : exp.type.typeArguments.map(TypeGenerator.createType)
734 .toList(growable: false);
735 return new LiteralMap(entries, typeArguments: typeArguments);
736 }
737
738 @override
739 Expression visitTypeOperator(tree.TypeOperator exp,
740 BuilderContext<Statement> context) {
741 return new TypeOperator(visitExpression(exp.value, context),
742 exp.operator,
743 TypeGenerator.createType(exp.type));
744 }
745
746 List<Argument> emitArguments(List<Expression> arguments,
747 Selector selector) {
748 int positionalArgumentCount = selector.positionalArgumentCount;
749 List<Argument> result = new List<Argument>.generate(positionalArgumentCount,
750 (i) => arguments[i]);
751 for (int i = 0; i < selector.namedArgumentCount; ++i) {
752 result.add(new NamedArgument(selector.namedArguments[i],
753 arguments[positionalArgumentCount + i]));
754 }
755 return result;
756 }
757
758 List<Expression> visitArgumentList(List<tree.Expression> arguments,
759 BuilderContext context) {
760 return arguments
761 .map((tree.Expression argument) => visitExpression(argument, context))
762 .toList();
763 }
764
765 @override
766 Expression visitInvokeStatic(tree.InvokeStatic exp,
767 BuilderContext<Statement> context) {
768 switch (exp.selector.kind) {
769 case SelectorKind.GETTER:
770 return new Identifier(exp.target.name)..element = exp.target;
771
772 case SelectorKind.SETTER:
773 return new Assignment(
774 new Identifier(exp.target.name)..element = exp.target,
775 '=',
776 visitExpression(exp.arguments[0], context));
777
778 case SelectorKind.CALL:
779 return new CallStatic(
780 null, exp.target.name,
781 emitArguments(visitArgumentList(exp.arguments, context),
782 exp.selector))
783 ..element = exp.target;
784
785 default:
786 throw "Unexpected selector kind: ${exp.selector.kind}";
787 }
788 }
789
790 Expression emitMethodCall(tree.Invoke exp, Receiver receiver,
791 BuilderContext<Statement> context) {
792 List<Argument> args =
793 emitArguments(visitArgumentList(exp.arguments, context), exp.selector);
794 switch (exp.selector.kind) {
795 case SelectorKind.CALL:
796 if (exp.selector.name == "call") {
797 return new CallFunction(receiver, args);
798 }
799 return new CallMethod(receiver, exp.selector.name, args);
800
801 case SelectorKind.OPERATOR:
802 if (args.length == 0) {
803 String name = exp.selector.name;
804 if (name == 'unary-') {
805 name = '-';
806 }
807 return new UnaryOperator(name, receiver);
808 }
809 return new BinaryOperator(receiver, exp.selector.name, args[0]);
810
811 case SelectorKind.GETTER:
812 return new FieldExpression(receiver, exp.selector.name);
813
814 case SelectorKind.SETTER:
815 return makeAssignment(
816 new FieldExpression(receiver, exp.selector.name),
817 args[0]);
818
819 case SelectorKind.INDEX:
820 Expression e = new IndexExpression(receiver, args[0]);
821 if (args.length == 2) {
822 e = makeAssignment(e, args[1]);
823 }
824 return e;
825
826 default:
827 throw "Unexpected selector in InvokeMethod: ${exp.selector.kind}";
828 }
829 }
830
831 @override
832 Expression visitInvokeMethod(tree.InvokeMethod exp,
833 BuilderContext<Statement> context) {
834 Expression receiver = visitExpression(exp.receiver, context);
835 return emitMethodCall(exp, receiver, context);
836 }
837
838 @override
839 Expression visitInvokeMethodDirectly(tree.InvokeMethodDirectly exp,
840 BuilderContext<Statement> context) {
841 // When targeting Dart, InvokeMethodDirectly is only used for super calls.
842 // The receiver is known to be `this`, and the target method is a method
843 // on the super class. So we just translate it as a method call with the
844 // super receiver.
845 return emitMethodCall(exp, new SuperReceiver(), context);
846 }
847
848 @override
849 Expression visitInvokeConstructor(tree.InvokeConstructor exp,
850 BuilderContext<Statement> context) {
851 List<Argument> args =
852 emitArguments(visitArgumentList(exp.arguments, context), exp.selector);
853 FunctionElement constructor = exp.target;
854 String name = constructor.name.isEmpty ? null : constructor.name;
855 return new CallNew(TypeGenerator.createType(exp.type),
856 args,
857 constructorName: name,
858 isConst: exp.constant != null)
859 ..constructor = constructor
860 ..dartType = exp.type;
861 }
862
863 @override
864 Expression visitConcatenateStrings(tree.ConcatenateStrings exp,
865 BuilderContext<Statement> context) {
866 return new StringConcat(visitExpressions(exp.arguments, context));
867 }
868
869 @override
870 Expression visitConditional(tree.Conditional exp,
871 BuilderContext<Statement> context) {
872 return new Conditional(
873 visitExpression(exp.condition, context),
874 visitExpression(exp.thenExpression, context),
875 visitExpression(exp.elseExpression, context));
876 }
877
878 @override
879 Expression visitLogicalOperator(tree.LogicalOperator exp,
880 BuilderContext<Statement> context) {
881 return new BinaryOperator(visitExpression(exp.left, context),
882 exp.operator,
883 visitExpression(exp.right, context));
884 }
885
886 @override
887 Expression visitNot(tree.Not exp,
888 BuilderContext<Statement> context) {
889 return new UnaryOperator('!', visitExpression(exp.operand, context));
890 }
891
892 @override
893 Expression visitVariableUse(tree.VariableUse exp,
894 BuilderContext<Statement> context) {
895 return context.makeVariableAccess(exp.variable);
896 }
897
898 @override
899 Expression visitAssign(tree.Assign node, BuilderContext<Statement> context) {
900 // This is called only when an assignment occurs in expression context.
901 return makeAssignment(
902 context.makeVariableAccess(node.variable),
903 visitExpression(node.value, context));
904 }
905
906 FunctionExpression makeSubFunction(tree.FunctionDefinition function,
907 BuilderContext<Statement> context) {
908 return visitFunctionDefinition(function,
909 new BuilderContext<Statement>.inner(context));
910 }
911
912 @override
913 Expression visitFunctionExpression(tree.FunctionExpression exp,
914 BuilderContext<Statement> context) {
915 return makeSubFunction(exp.definition, context)..name = null;
916 }
917
918 @override
919 void visitFunctionDeclaration(tree.FunctionDeclaration node,
920 BuilderContext<Statement> context) {
921 assert(context.variableNames[node.variable] == null);
922 String name = context.getVariableName(node.variable);
923 FunctionExpression inner = makeSubFunction(node.definition, context);
924 inner.name = name;
925 FunctionDeclaration decl = new FunctionDeclaration(inner);
926 context.declaredVariables.add(node.variable);
927 context.addStatement(decl);
928 visitStatement(node.next, context);
929 }
930
931 List<Statement> buildInInitializerContext(tree.Statement root,
932 BuilderContext context) {
933 BuilderContext inner = new BuilderContext<Statement>.initializer(context);
934 inner.currentElement = context.currentElement;
935 inner.firstStatement = root;
936 visitStatement(root, inner);
937 List<Statement> bodyParts;
938 for (tree.Variable variable in inner.variableNames.keys) {
939 if (!context.declaredVariables.contains(variable) &&
940 !inner.declaredVariables.contains(variable)) {
941 inner.addDeclaration(variable);
942 }
943 }
944 if (inner.variables.length > 0) {
945 bodyParts = new List<Statement>();
946 bodyParts.add(new VariableDeclarations(inner.variables));
947 bodyParts.addAll(inner.statements);
948 } else {
949 bodyParts = inner.statements;
950 }
951 return bodyParts;
952 }
953
954 @override
955 Initializer visitFieldInitializer(tree.FieldInitializer node,
956 BuilderContext<Statement> context) {
957 return new FieldInitializer(node.element,
958 ensureExpression(buildInInitializerContext(node.body, context)));
959 }
960
961 @override
962 Initializer visitSuperInitializer(tree.SuperInitializer node,
963 BuilderContext<Statement> context) {
964 List<Argument> arguments = node.arguments.map((tree.Statement argument) {
965 return ensureExpression(buildInInitializerContext(argument, context));
966 }).toList();
967 return new SuperInitializer(node.target,
968 emitArguments(arguments, node.selector));
969 }
970
971 @override
972 Expression visitGetStatic(tree.GetStatic node,
973 BuilderContext<Statement> context) {
974 return new Identifier(node.element.name)..element = node.element;
975 }
976
977 @override
978 Expression visitSetStatic(tree.SetStatic node,
979 BuilderContext<Statement> context) {
980 Expression target =
981 new Identifier(node.element.name)..element = node.element;
982 Expression value = visitExpression(node.value, context);
983 return makeAssignment(target, value);
984 }
985
986 @override
987 Expression visitTypeExpression(tree.TypeExpression node, arg) {
988 throw '$node not supported by dart backend';
989 }
990
991 @override
992 visitGetField(tree.GetField node, arg) => errorUnsupportedNode(node);
993
994 @override
995 visitSetField(tree.SetField node, arg) => errorUnsupportedNode(node);
996
997 @override
998 visitCreateBox(tree.CreateBox node, arg) => errorUnsupportedNode(node);
999
1000 @override
1001 visitCreateInstance(tree.CreateInstance node, arg) {
1002 return errorUnsupportedNode(node);
1003 }
1004
1005 @override
1006 visitCreateInvocationMirror(tree.CreateInvocationMirror node, arg) {
1007 return errorUnsupportedNode(node);
1008 }
1009
1010 @override
1011 Expression visitReadTypeVariable(tree.ReadTypeVariable node, arg) {
1012 return errorUnsupportedNode(node);
1013 }
1014
1015 @override
1016 Expression visitReifyRuntimeType(tree.ReifyRuntimeType node, arg) {
1017 return errorUnsupportedNode(node);
1018 }
1019
1020 errorUnsupportedNode(tree.JsSpecificNode node) {
1021 throw '$node not supported by dart backend';
1022 }
1023
1024 }
1025 10
1026 class TypeGenerator { 11 class TypeGenerator {
1027 12
1028 /// TODO(johnniwinther): Remove this when issue 21283 has been resolved. 13 /// TODO(johnniwinther): Remove this when issue 21283 has been resolved.
1029 static int pseudoNameCounter = 0; 14 static int pseudoNameCounter = 0;
1030 15
1031 static Parameter emitParameter(DartType type, 16 static Parameter emitParameter(DartType type,
1032 BuilderContext<Statement> context,
1033 {String name, 17 {String name,
1034 Element element, 18 Element element}) {
1035 ConstantExpression defaultValue}) {
1036 if (name == null && element != null) { 19 if (name == null && element != null) {
1037 name = element.name; 20 name = element.name;
1038 } 21 }
1039 if (name == null) { 22 if (name == null) {
1040 name = '_${pseudoNameCounter++}'; 23 name = '_${pseudoNameCounter++}';
1041 } 24 }
1042 Parameter parameter; 25 Parameter parameter;
1043 if (type.isFunctionType) { 26 if (type.isFunctionType) {
1044 FunctionType functionType = type; 27 FunctionType functionType = type;
1045 TypeAnnotation returnType = createOptionalType(functionType.returnType); 28 TypeAnnotation returnType = createOptionalType(functionType.returnType);
1046 Parameters innerParameters = 29 Parameters innerParameters =
1047 createParametersFromType(functionType); 30 createParametersFromType(functionType);
1048 parameter = new Parameter.function(name, returnType, innerParameters); 31 parameter = new Parameter.function(name, returnType, innerParameters);
1049 } else { 32 } else {
1050 TypeAnnotation typeAnnotation = createOptionalType(type); 33 TypeAnnotation typeAnnotation = createOptionalType(type);
1051 parameter = new Parameter(name, type: typeAnnotation); 34 parameter = new Parameter(name, type: typeAnnotation);
1052 } 35 }
1053 parameter.element = element; 36 parameter.element = element;
1054 if (defaultValue != null && !defaultValue.value.isNull) {
1055 parameter.defaultValue =
1056 ConstantEmitter.createExpression(defaultValue, context);
1057 }
1058 return parameter; 37 return parameter;
1059 } 38 }
1060 39
1061 static Parameters createParametersFromType(FunctionType functionType) { 40 static Parameters createParametersFromType(FunctionType functionType) {
1062 pseudoNameCounter = 0; 41 pseudoNameCounter = 0;
1063 if (functionType.namedParameters.isEmpty) { 42 if (functionType.namedParameters.isEmpty) {
1064 return new Parameters( 43 return new Parameters(
1065 createParameters(functionType.parameterTypes), 44 createParameters(functionType.parameterTypes),
1066 createParameters(functionType.optionalParameterTypes), 45 createParameters(functionType.optionalParameterTypes),
1067 false); 46 false);
1068 } else { 47 } else {
1069 return new Parameters( 48 return new Parameters(
1070 createParameters(functionType.parameterTypes), 49 createParameters(functionType.parameterTypes),
1071 createParameters(functionType.namedParameterTypes, 50 createParameters(functionType.namedParameterTypes,
1072 names: functionType.namedParameters), 51 names: functionType.namedParameters),
1073 true); 52 true);
1074 } 53 }
1075 } 54 }
1076 55
1077 static List<Parameter> createParameters( 56 static List<Parameter> createParameters(
1078 Iterable<DartType> parameterTypes, 57 Iterable<DartType> parameterTypes,
1079 {BuilderContext<Statement> context, 58 {Iterable<String> names: const <String>[],
1080 Iterable<String> names: const <String>[],
1081 Iterable<ConstantExpression> defaultValues: const <ConstantExpression>[],
1082 Iterable<Element> elements: const <Element>[]}) { 59 Iterable<Element> elements: const <Element>[]}) {
1083 Iterator<String> name = names.iterator; 60 Iterator<String> name = names.iterator;
1084 Iterator<ConstantExpression> defaultValue = defaultValues.iterator;
1085 Iterator<Element> element = elements.iterator; 61 Iterator<Element> element = elements.iterator;
1086 return parameterTypes.map((DartType type) { 62 return parameterTypes.map((DartType type) {
1087 name.moveNext(); 63 name.moveNext();
1088 defaultValue.moveNext();
1089 element.moveNext(); 64 element.moveNext();
1090 return emitParameter(type, context, 65 return emitParameter(type,
1091 name: name.current, 66 name: name.current,
1092 defaultValue: defaultValue.current,
1093 element: element.current); 67 element: element.current);
1094 }).toList(); 68 }).toList();
1095 } 69 }
1096 70
1097 /// Like [createTypeAnnotation] except the dynamic type is converted to null. 71 /// Like [createTypeAnnotation] except the dynamic type is converted to null.
1098 static TypeAnnotation createOptionalType(DartType type) { 72 static TypeAnnotation createOptionalType(DartType type) {
1099 if (type.treatAsDynamic) { 73 if (type.treatAsDynamic) {
1100 return null; 74 return null;
1101 } else { 75 } else {
1102 return createType(type); 76 return createType(type);
(...skipping 19 matching lines...) Expand all
1122 } else if (type is DynamicType) { 96 } else if (type is DynamicType) {
1123 return new TypeAnnotation("dynamic") 97 return new TypeAnnotation("dynamic")
1124 ..dartType = type; 98 ..dartType = type;
1125 } else if (type is MalformedType) { 99 } else if (type is MalformedType) {
1126 return new TypeAnnotation(type.name) 100 return new TypeAnnotation(type.name)
1127 ..dartType = type; 101 ..dartType = type;
1128 } else { 102 } else {
1129 throw "Unsupported type annotation: $type"; 103 throw "Unsupported type annotation: $type";
1130 } 104 }
1131 } 105 }
1132
1133 } 106 }
1134
1135
1136 class ConstantEmitter
1137 extends ConstantExpressionVisitor<Expression, BuilderContext<Statement>> {
1138 const ConstantEmitter();
1139
1140 /// Creates the [Expression] for the constant [exp].
1141 static Expression createExpression(ConstantExpression exp,
1142 BuilderContext<Statement> context) {
1143 return const ConstantEmitter().visit(exp, context);
1144 }
1145
1146 Expression handlePrimitiveConstant(PrimitiveConstantValue value) {
1147 // Num constants may be negative, while literals must be non-negative:
1148 // Literals are non-negative in the specification, and a negated literal
1149 // parses as a call to unary `-`. The AST unparser assumes literals are
1150 // non-negative and relies on this to avoid incorrectly generating `--`,
1151 // the predecrement operator.
1152 // Translate such constants into their positive value wrapped by
1153 // the unary minus operator.
1154 if (value.isNum) {
1155 NumConstantValue numConstant = value;
1156 if (numConstant.primitiveValue.isNegative) {
1157 return negatedLiteral(numConstant);
1158 }
1159 }
1160 return new Literal(value);
1161 }
1162
1163 List<Expression> visitExpressions(List<ConstantExpression> expressions,
1164 BuilderContext<Statement> context) {
1165 return expressions.map((expression) => visit(expression, context))
1166 .toList(growable: false);
1167 }
1168
1169 @override
1170 Expression visitBool(BoolConstantExpression exp,
1171 BuilderContext<Statement> context) {
1172 return handlePrimitiveConstant(exp.value);
1173 }
1174
1175 @override
1176 Expression visitInt(IntConstantExpression exp,
1177 BuilderContext<Statement> context) {
1178 return handlePrimitiveConstant(exp.value);
1179 }
1180
1181 @override
1182 Expression visitDouble(DoubleConstantExpression exp,
1183 BuilderContext<Statement> context) {
1184 return handlePrimitiveConstant(exp.value);
1185 }
1186
1187 @override
1188 Expression visitString(StringConstantExpression exp,
1189 BuilderContext<Statement> context) {
1190 return handlePrimitiveConstant(exp.value);
1191 }
1192
1193 @override
1194 Expression visitNull(NullConstantExpression exp,
1195 BuilderContext<Statement> context) {
1196 return handlePrimitiveConstant(exp.value);
1197 }
1198
1199 /// Given a negative num constant, returns the corresponding positive
1200 /// literal wrapped by a unary minus operator.
1201 Expression negatedLiteral(NumConstantValue constant) {
1202 assert(constant.primitiveValue.isNegative);
1203 NumConstantValue positiveConstant;
1204 if (constant.isInt) {
1205 positiveConstant = new IntConstantValue(-constant.primitiveValue);
1206 } else if (constant.isDouble) {
1207 positiveConstant = new DoubleConstantValue(-constant.primitiveValue);
1208 } else {
1209 throw "Unexpected type of NumConstant: $constant";
1210 }
1211 return new UnaryOperator('-', new Literal(positiveConstant));
1212 }
1213
1214 @override
1215 Expression visitList(ListConstantExpression exp,
1216 BuilderContext<Statement> context) {
1217 return new LiteralList(
1218 visitExpressions(exp.values, context),
1219 isConst: true,
1220 typeArgument:
1221 TypeGenerator.createOptionalType(exp.type.typeArguments.single));
1222 }
1223
1224 @override
1225 Expression visitMap(MapConstantExpression exp,
1226 BuilderContext<Statement> context) {
1227 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
1228 exp.values.length,
1229 (i) => new LiteralMapEntry(visit(exp.keys[i], context),
1230 visit(exp.values[i], context)));
1231 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
1232 ? null
1233 : exp.type.typeArguments.map(TypeGenerator.createType).toList();
1234 return new LiteralMap(entries, isConst: true, typeArguments: typeArguments);
1235 }
1236
1237 @override
1238 Expression visitConstructed(ConstructedConstantExpression exp,
1239 BuilderContext<Statement> context) {
1240 int positionalArgumentCount = exp.callStructure.positionalArgumentCount;
1241 List<Argument> args = new List<Argument>.generate(
1242 positionalArgumentCount,
1243 (i) => visit(exp.arguments[i], context));
1244 for (int i = 0; i < exp.callStructure.namedArgumentCount; ++i) {
1245 args.add(new NamedArgument(exp.callStructure.namedArguments[i],
1246 visit(exp.arguments[positionalArgumentCount + i], context)));
1247 }
1248
1249 FunctionElement constructor = exp.target;
1250 String name = constructor.name.isEmpty ? null : constructor.name;
1251 return new CallNew(TypeGenerator.createType(exp.type),
1252 args,
1253 constructorName: name,
1254 isConst: true)
1255 ..constructor = constructor
1256 ..dartType = exp.type;
1257 }
1258
1259 @override
1260 Expression visitConcatenate(ConcatenateConstantExpression exp,
1261 BuilderContext<Statement> context) {
1262
1263 return new StringConcat(visitExpressions(exp.expressions, context));
1264 }
1265
1266 @override
1267 Expression visitSymbol(SymbolConstantExpression exp,
1268 BuilderContext<Statement> context) {
1269 return new LiteralSymbol(exp.name);
1270 }
1271
1272 @override
1273 Expression visitType(TypeConstantExpression exp,
1274 BuilderContext<Statement> context) {
1275 DartType type = exp.type;
1276 return new LiteralType(type.name)
1277 ..type = type;
1278 }
1279
1280 @override
1281 Expression visitVariable(VariableConstantExpression exp,
1282 BuilderContext<Statement> context) {
1283 Element element = exp.element;
1284 if (element.kind != ElementKind.VARIABLE) {
1285 return new Identifier(element.name)..element = element;
1286 }
1287 String name = context.getConstantName(element);
1288 return new Identifier(name)
1289 ..element = element;
1290 }
1291
1292 @override
1293 Expression visitFunction(FunctionConstantExpression exp,
1294 BuilderContext<Statement> context) {
1295 return new Identifier(exp.element.name)
1296 ..element = exp.element;
1297 }
1298
1299 @override
1300 Expression visitBinary(BinaryConstantExpression exp,
1301 BuilderContext<Statement> context) {
1302 return handlePrimitiveConstant(exp.value);
1303 }
1304
1305 @override
1306 Expression visitIdentical(IdenticalConstantExpression exp,
1307 BuilderContext<Statement> context) {
1308 return handlePrimitiveConstant(exp.value);
1309 }
1310
1311 @override
1312 Expression visitConditional(ConditionalConstantExpression exp,
1313 BuilderContext<Statement> context) {
1314 if (exp.condition.value.isTrue) {
1315 return exp.trueExp.accept(this);
1316 } else {
1317 return exp.falseExp.accept(this);
1318 }
1319 }
1320
1321 @override
1322 Expression visitUnary(UnaryConstantExpression exp,
1323 BuilderContext<Statement> context) {
1324 return handlePrimitiveConstant(exp.value);
1325 }
1326
1327 @override
1328 Expression visitNamed(NamedArgumentReference exp,
1329 BuilderContext<Statement> context) {
1330 throw new UnsupportedError("ConstantEmitter.visitNamed");
1331 }
1332
1333 @override
1334 Expression visitPositional(PositionalArgumentReference exp,
1335 BuilderContext<Statement> context) {
1336 throw new UnsupportedError("ConstantEmitter.visitPositional");
1337 }
1338
1339 @override
1340 Expression visitBoolFromEnvironment(
1341 BoolFromEnvironmentConstantExpression exp,
1342 BuilderContext<Statement> context) {
1343 return handlePrimitiveConstant(exp.value);
1344 }
1345
1346 @override
1347 Expression visitIntFromEnvironment(
1348 IntFromEnvironmentConstantExpression exp,
1349 BuilderContext<Statement> context) {
1350 return handlePrimitiveConstant(exp.value);
1351 }
1352
1353 @override
1354 Expression visitStringFromEnvironment(
1355 StringFromEnvironmentConstantExpression exp,
1356 BuilderContext<Statement> context) {
1357 return handlePrimitiveConstant(exp.value);
1358 }
1359
1360 @override
1361 Expression visitDeferred(DeferredConstantExpression exp,
1362 BuilderContext<Statement> context) {
1363 return exp.expression.accept(this);
1364 }
1365 }
1366
1367 /// Moves function parameters into a separate variable if one of its uses is
1368 /// shadowed by an inner function parameter.
1369 /// This artifact is necessary because function parameters cannot be renamed.
1370 class UnshadowParameters extends tree.RecursiveVisitor {
1371
1372 /// Maps parameter names to their bindings.
1373 Map<String, tree.Variable> environment = <String, tree.Variable>{};
1374
1375 /// Parameters that are currently shadowed by another parameter.
1376 Set<tree.Variable> shadowedParameters = new Set<tree.Variable>();
1377
1378 /// Parameters that are used in a context where it is shadowed.
1379 Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>();
1380
1381 void unshadow(tree.RootNode definition) {
1382 if (definition.isEmpty) return;
1383 unshadowFunction(definition);
1384 }
1385
1386 void unshadowFunction(tree.RootNode definition) {
1387 var oldShadow = shadowedParameters;
1388 var oldEnvironment = environment;
1389 environment = new Map<String, tree.Variable>.from(environment);
1390 shadowedParameters = new Set<tree.Variable>.from(shadowedParameters);
1391 for (tree.Variable param in definition.parameters) {
1392 tree.Variable oldVariable = environment[param.element.name];
1393 if (oldVariable != null) {
1394 shadowedParameters.add(oldVariable);
1395 }
1396 environment[param.element.name] = param;
1397 }
1398 definition.forEachBody(visitStatement);
1399 environment = oldEnvironment;
1400 shadowedParameters = oldShadow;
1401
1402 for (int i=0; i<definition.parameters.length; i++) {
1403 tree.Variable param = definition.parameters[i];
1404 if (hasShadowedUse.remove(param)) {
1405 tree.Variable newParam = new tree.Variable(definition.element,
1406 param.element);
1407 definition.parameters[i] = newParam;
1408 definition.replaceEachBody((tree.Statement body) {
1409 return tree.Assign.makeStatement(
1410 param,
1411 new tree.VariableUse(newParam),
1412 body);
1413 });
1414 newParam.writeCount = 1; // Being a parameter counts as a write.
1415 param.writeCount--; // Not a parameter anymore.
1416 }
1417 }
1418 }
1419
1420 @override
1421 void visitInnerFunction(tree.FunctionDefinition definition) {
1422 unshadowFunction(definition);
1423 }
1424
1425 @override
1426 visitVariable(tree.Variable variable) {
1427 if (shadowedParameters.contains(variable)) {
1428 hasShadowedUse.add(variable);
1429 }
1430 }
1431
1432 }
1433
1434 // TODO(johnniwinther): Remove this when the dart `backend_ast` does not need
1435 // [Element] for entities.
1436 class _SyntheticLocalVariableElement extends modelx.VariableElementX
1437 implements LocalVariableElement {
1438
1439 _SyntheticLocalVariableElement(String name,
1440 ExecutableElement enclosingElement,
1441 modelx.VariableList variables)
1442 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null);
1443
1444 ExecutableElement get executableContext => enclosingElement;
1445
1446 ExecutableElement get memberContext => executableContext.memberContext;
1447
1448 bool get isLocal => true;
1449
1450 LibraryElement get implementationLibrary => enclosingElement.library;
1451 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698