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

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

Issue 692513002: Remove old dart2js code. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library backend_ast_emitter;
6
7 import 'tree_ir_nodes.dart' as tree;
8 import 'backend_ast_nodes.dart';
9 import '../constants/expressions.dart';
10 import '../constants/values.dart';
11 import '../dart_types.dart';
12 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 Expression emit(tree.FunctionDefinition definition) {
19 return new ASTEmitter().emit(definition);
20 }
21
22 /// Translates the dart_tree IR to Dart backend AST.
23 /// An instance of this class should only be used once; a fresh emitter
24 /// must be created for each function to be emitted.
25 class ASTEmitter extends tree.Visitor<dynamic, Expression> {
26 /// Variables to be hoisted at the top of the current function.
27 List<VariableDeclaration> variables = <VariableDeclaration>[];
28
29 /// Maps variables to their name.
30 Map<tree.Variable, String> variableNames = <tree.Variable, String>{};
31
32 /// Maps local constants to their name.
33 Map<VariableElement, String> constantNames = <VariableElement, String>{};
34
35 /// Variables that have had their declaration created.
36 Set<tree.Variable> declaredVariables = new Set<tree.Variable>();
37
38 /// Variable names that have already been used. Used to avoid name clashes.
39 Set<String> usedVariableNames;
40
41 /// Statements emitted by the most recent call to [visitStatement].
42 List<Statement> statementBuffer = <Statement>[];
43
44 /// The function currently being emitted.
45 FunctionElement functionElement;
46
47 /// Bookkeeping object needed to synthesize a variable declaration.
48 modelx.VariableList variableList
49 = new modelx.VariableList(tree.Modifiers.EMPTY);
50
51 /// Input to [visitStatement]. Denotes the statement that will execute next
52 /// if the statements produced by [visitStatement] complete normally.
53 /// Set to null if control will fall over the end of the method.
54 tree.Statement fallthrough = null;
55
56 /// Labels that could not be eliminated using fallthrough.
57 Set<tree.Label> usedLabels = new Set<tree.Label>();
58
59 /// The first dart_tree statement that is not converted to a variable
60 /// initializer.
61 tree.Statement firstStatement;
62
63 /// Emitter for the enclosing function, or null if the current function is
64 /// not a local function.
65 ASTEmitter parent;
66
67 ASTEmitter() : usedVariableNames = new Set<String>();
68
69 ASTEmitter.inner(ASTEmitter parent)
70 : this.parent = parent,
71 usedVariableNames = parent.usedVariableNames;
72
73 FunctionExpression emit(tree.FunctionDefinition definition) {
74 functionElement = definition.element;
75
76 Parameters parameters = emitRootParameters(definition);
77
78 // Declare parameters.
79 for (tree.Variable param in definition.parameters) {
80 variableNames[param] = param.element.name;
81 usedVariableNames.add(param.element.name);
82 declaredVariables.add(param);
83 }
84
85 Statement body;
86 if (definition.isAbstract) {
87 body = new EmptyStatement();
88 } else {
89 firstStatement = definition.body;
90 visitStatement(definition.body);
91 removeTrailingReturn();
92
93 // Some of the variable declarations have already been added
94 // if their first assignment could be pulled into the initializer.
95 // Add the remaining variable declarations now.
96 for (tree.Variable variable in variableNames.keys) {
97 if (!declaredVariables.contains(variable)) {
98 addDeclaration(variable);
99 }
100 }
101
102 // Add constant declarations.
103 List<VariableDeclaration> constants = <VariableDeclaration>[];
104 for (ConstDeclaration constDecl in definition.localConstants) {
105 if (!constantNames.containsKey(constDecl.element))
106 continue; // Discard unused constants declarations.
107 String name = getConstantName(constDecl.element);
108 Expression value = emitConstant(constDecl.expression);
109 VariableDeclaration decl = new VariableDeclaration(name, value);
110 decl.element = constDecl.element;
111 constants.add(decl);
112 }
113
114 List<Statement> bodyParts = [];
115 if (constants.length > 0) {
116 bodyParts.add(new VariableDeclarations(constants, isConst: true));
117 }
118 if (variables.length > 0) {
119 bodyParts.add(new VariableDeclarations(variables));
120 }
121 bodyParts.addAll(statementBuffer);
122
123 body = new Block(bodyParts);
124 }
125 FunctionType functionType = functionElement.type;
126
127 return new FunctionExpression(
128 parameters,
129 body,
130 name: functionElement.name,
131 returnType: emitOptionalType(functionType.returnType),
132 isGetter: functionElement.isGetter,
133 isSetter: functionElement.isSetter)
134 ..element = functionElement;
135 }
136
137 void addDeclaration(tree.Variable variable, [Expression initializer]) {
138 assert(!declaredVariables.contains(variable));
139 String name = getVariableName(variable);
140 VariableDeclaration decl = new VariableDeclaration(name, initializer);
141 decl.element = variable.element;
142 declaredVariables.add(variable);
143 variables.add(decl);
144 }
145
146 /// Removes a trailing "return null" from [statementBuffer].
147 void removeTrailingReturn() {
148 if (statementBuffer.isEmpty) return;
149 if (statementBuffer.last is! Return) return;
150 Return ret = statementBuffer.last;
151 Expression expr = ret.expression;
152 if (expr is Literal && expr.value.isNull) {
153 statementBuffer.removeLast();
154 }
155 }
156
157 /// TODO(johnniwinther): Remove this when issue 21283 has been resolved.
158 int pseudoNameCounter = 0;
159
160 Parameter emitParameter(DartType type,
161 {String name,
162 Element element,
163 ConstantExpression defaultValue}) {
164 if (name == null && element != null) {
165 name = element.name;
166 }
167 if (name == null) {
168 name = '_${pseudoNameCounter++}';
169 }
170 Parameter parameter;
171 if (type.isFunctionType) {
172 FunctionType functionType = type;
173 TypeAnnotation returnType = emitOptionalType(functionType.returnType);
174 Parameters innerParameters = emitParametersFromType(functionType);
175 parameter = new Parameter.function(name, returnType, innerParameters);
176 } else {
177 TypeAnnotation typeAnnotation = emitOptionalType(type);
178 parameter = new Parameter(name, type: typeAnnotation);
179 }
180 parameter.element = element;
181 if (defaultValue != null && !defaultValue.value.isNull) {
182 parameter.defaultValue = emitConstant(defaultValue);
183 }
184 return parameter;
185 }
186
187 Parameters emitParametersFromType(FunctionType functionType) {
188 if (functionType.namedParameters.isEmpty) {
189 return new Parameters(
190 emitParameters(functionType.parameterTypes),
191 emitParameters(functionType.optionalParameterTypes),
192 false);
193 } else {
194 return new Parameters(
195 emitParameters(functionType.parameterTypes),
196 emitParameters(functionType.namedParameterTypes,
197 names: functionType.namedParameters),
198 true);
199 }
200 }
201
202 List<Parameter> emitParameters(
203 Iterable<DartType> parameterTypes,
204 {Iterable<String> names: const <String>[],
205 Iterable<ConstantExpression> defaultValues: const <ConstantExpression>[],
206 Iterable<Element> elements: const <Element>[]}) {
207 Iterator<String> name = names.iterator;
208 Iterator<ConstantExpression> defaultValue = defaultValues.iterator;
209 Iterator<Element> element = elements.iterator;
210 return parameterTypes.map((DartType type) {
211 name.moveNext();
212 defaultValue.moveNext();
213 element.moveNext();
214 return emitParameter(type,
215 name: name.current,
216 defaultValue: defaultValue.current,
217 element: element.current);
218 }).toList();
219 }
220
221 /// Emits parameters that are not nested inside other parameters.
222 /// Root parameters can have default values, while inner parameters cannot.
223 Parameters emitRootParameters(tree.FunctionDefinition function) {
224 FunctionType functionType = function.element.type;
225 List<Parameter> required = emitParameters(
226 functionType.parameterTypes,
227 elements: function.parameters.map((p) => p.element));
228 bool optionalParametersAreNamed = !functionType.namedParameters.isEmpty;
229 List<Parameter> optional = emitParameters(
230 optionalParametersAreNamed
231 ? functionType.namedParameterTypes
232 : functionType.optionalParameterTypes,
233 defaultValues: function.defaultParameterValues,
234 elements: function.parameters.skip(required.length)
235 .map((p) => p.element));
236 return new Parameters(required, optional, optionalParametersAreNamed);
237 }
238
239 /// True if the two expressions are a reference to the same variable.
240 bool isSameVariable(Receiver e1, Receiver e2) {
241 return e1 is Identifier &&
242 e2 is Identifier &&
243 e1.element is VariableElement &&
244 e1.element == e2.element;
245 }
246
247 Expression makeAssignment(Expression target, Expression value) {
248 // Try to print as compound assignment or increment
249 if (value is BinaryOperator && isCompoundableOperator(value.operator)) {
250 Expression leftOperand = value.left;
251 Expression rightOperand = value.right;
252 bool valid = false;
253 if (isSameVariable(target, leftOperand)) {
254 valid = true;
255 } else if (target is FieldExpression &&
256 leftOperand is FieldExpression &&
257 isSameVariable(target.object, leftOperand.object) &&
258 target.fieldName == leftOperand.fieldName) {
259 valid = true;
260 } else if (target is IndexExpression &&
261 leftOperand is IndexExpression &&
262 isSameVariable(target.object, leftOperand.object) &&
263 isSameVariable(target.index, leftOperand.index)) {
264 valid = true;
265 }
266 if (valid) {
267 if (rightOperand is Literal && rightOperand.value.isOne &&
268 (value.operator == '+' || value.operator == '-')) {
269 return new Increment.prefix(target, value.operator + value.operator);
270 } else {
271 return new Assignment(target, value.operator + '=', rightOperand);
272 }
273 }
274 }
275 // Fall back to regular assignment
276 return new Assignment(target, '=', value);
277 }
278
279 void visitExpressionStatement(tree.ExpressionStatement stmt) {
280 Expression e = visitExpression(stmt.expression);
281 statementBuffer.add(new ExpressionStatement(e));
282 visitStatement(stmt.next);
283 }
284
285 void visitLabeledStatement(tree.LabeledStatement stmt) {
286 List<Statement> savedBuffer = statementBuffer;
287 tree.Statement savedFallthrough = fallthrough;
288 statementBuffer = <Statement>[];
289 fallthrough = stmt.next;
290 visitStatement(stmt.body);
291 if (usedLabels.remove(stmt.label)) {
292 savedBuffer.add(new LabeledStatement(stmt.label.name,
293 new Block(statementBuffer)));
294 } else {
295 savedBuffer.add(new Block(statementBuffer));
296 }
297 fallthrough = savedFallthrough;
298 statementBuffer = savedBuffer;
299 visitStatement(stmt.next);
300 }
301
302 /// Generates a name for the given variable and synthesizes an element for it,
303 /// if necessary.
304 String getVariableName(tree.Variable variable) {
305 // If the variable belongs to an enclosing function, ask the parent emitter
306 // for the variable name.
307 if (variable.host.element != functionElement) {
308 return parent.getVariableName(variable);
309 }
310
311 // Get the name if we already have one.
312 String name = variableNames[variable];
313 if (name != null) {
314 return name;
315 }
316
317 // Synthesize a variable name that isn't used elsewhere.
318 // The [usedVariableNames] set is shared between nested emitters,
319 // so this also prevents clash with variables in an enclosing/inner scope.
320 // The renaming phase after codegen will further prefix local variables
321 // so they cannot clash with top-level variables or fields.
322 String prefix = variable.element == null ? 'v' : variable.element.name;
323 int counter = 0;
324 name = variable.element == null ? '$prefix$counter' : variable.element.name;
325 while (!usedVariableNames.add(name)) {
326 ++counter;
327 name = '$prefix$counter';
328 }
329 variableNames[variable] = name;
330
331 // Synthesize an element for the variable
332 if (variable.element == null || name != variable.element.name) {
333 // TODO(johnniwinther): Replace by synthetic [Entity].
334 variable.element = new modelx.LocalVariableElementX.synthetic(
335 name,
336 functionElement,
337 variableList);
338 }
339 return name;
340 }
341
342 String getConstantName(VariableElement element) {
343 assert(element.kind == ElementKind.VARIABLE);
344 if (element.enclosingElement != functionElement) {
345 return parent.getConstantName(element);
346 }
347 String name = constantNames[element];
348 if (name != null) {
349 return name;
350 }
351 String prefix = element.name;
352 int counter = 0;
353 name = element.name;
354 while (!usedVariableNames.add(name)) {
355 ++counter;
356 name = '$prefix$counter';
357 }
358 constantNames[element] = name;
359 return name;
360 }
361
362 bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull;
363
364 void visitAssign(tree.Assign stmt) {
365 // Try to emit a local function declaration. This is useful for functions
366 // that may occur in expression context, but could not be inlined anywhere.
367 if (stmt.variable.element is FunctionElement &&
368 stmt.definition is tree.FunctionExpression &&
369 !declaredVariables.contains(stmt.variable)) {
370 tree.FunctionExpression functionExp = stmt.definition;
371 FunctionExpression function = makeSubFunction(functionExp.definition);
372 FunctionDeclaration decl = new FunctionDeclaration(function);
373 statementBuffer.add(decl);
374 declaredVariables.add(stmt.variable);
375 visitStatement(stmt.next);
376 return;
377 }
378
379 bool isFirstOccurrence = (variableNames[stmt.variable] == null);
380 bool isDeclaredHere = stmt.variable.host.element == functionElement;
381 String name = getVariableName(stmt.variable);
382 Expression definition = visitExpression(stmt.definition);
383
384 // Try to pull into initializer.
385 if (firstStatement == stmt && isFirstOccurrence && isDeclaredHere) {
386 if (isNullLiteral(definition)) definition = null;
387 addDeclaration(stmt.variable, definition);
388 firstStatement = stmt.next;
389 visitStatement(stmt.next);
390 return;
391 }
392
393 // Emit a variable declaration if we are required to do so.
394 // This is to ensure that a fresh closure variable is created.
395 if (stmt.isDeclaration) {
396 assert(isFirstOccurrence);
397 assert(isDeclaredHere);
398 if (isNullLiteral(definition)) definition = null;
399 VariableDeclaration decl = new VariableDeclaration(name, definition)
400 ..element = stmt.variable.element;
401 declaredVariables.add(stmt.variable);
402 statementBuffer.add(new VariableDeclarations([decl]));
403 visitStatement(stmt.next);
404 return;
405 }
406
407 statementBuffer.add(new ExpressionStatement(makeAssignment(
408 visitVariable(stmt.variable),
409 definition)));
410 visitStatement(stmt.next);
411 }
412
413 void visitReturn(tree.Return stmt) {
414 Expression inner = visitExpression(stmt.value);
415 statementBuffer.add(new Return(inner));
416 }
417
418 void visitBreak(tree.Break stmt) {
419 tree.Statement fall = fallthrough;
420 if (stmt.target.binding.next == fall) {
421 // Fall through to break target
422 } else if (fall is tree.Break && fall.target == stmt.target) {
423 // Fall through to equivalent break
424 } else {
425 usedLabels.add(stmt.target);
426 statementBuffer.add(new Break(stmt.target.name));
427 }
428 }
429
430 void visitContinue(tree.Continue stmt) {
431 tree.Statement fall = fallthrough;
432 if (stmt.target.binding == fall) {
433 // Fall through to continue target
434 } else if (fall is tree.Continue && fall.target == stmt.target) {
435 // Fall through to equivalent continue
436 } else {
437 usedLabels.add(stmt.target);
438 statementBuffer.add(new Continue(stmt.target.name));
439 }
440 }
441
442 void visitIf(tree.If stmt) {
443 Expression condition = visitExpression(stmt.condition);
444 List<Statement> savedBuffer = statementBuffer;
445 List<Statement> thenBuffer = statementBuffer = <Statement>[];
446 visitStatement(stmt.thenStatement);
447 List<Statement> elseBuffer = statementBuffer = <Statement>[];
448 visitStatement(stmt.elseStatement);
449 savedBuffer.add(
450 new If(condition, new Block(thenBuffer), new Block(elseBuffer)));
451 statementBuffer = savedBuffer;
452 }
453
454 void visitWhileTrue(tree.WhileTrue stmt) {
455 List<Statement> savedBuffer = statementBuffer;
456 tree.Statement savedFallthrough = fallthrough;
457 statementBuffer = <Statement>[];
458 fallthrough = stmt;
459
460 visitStatement(stmt.body);
461 Statement body = new Block(statementBuffer);
462 Statement statement = new While(new Literal(new TrueConstantValue()),
463 body);
464 if (usedLabels.remove(stmt.label)) {
465 statement = new LabeledStatement(stmt.label.name, statement);
466 }
467 savedBuffer.add(statement);
468
469 statementBuffer = savedBuffer;
470 fallthrough = savedFallthrough;
471 }
472
473 void visitWhileCondition(tree.WhileCondition stmt) {
474 Expression condition = visitExpression(stmt.condition);
475
476 List<Statement> savedBuffer = statementBuffer;
477 tree.Statement savedFallthrough = fallthrough;
478 statementBuffer = <Statement>[];
479 fallthrough = stmt;
480
481 visitStatement(stmt.body);
482 Statement body = new Block(statementBuffer);
483 Statement statement;
484 statement = new While(condition, body);
485 if (usedLabels.remove(stmt.label)) {
486 statement = new LabeledStatement(stmt.label.name, statement);
487 }
488 savedBuffer.add(statement);
489
490 statementBuffer = savedBuffer;
491 fallthrough = savedFallthrough;
492
493 visitStatement(stmt.next);
494 }
495
496 Expression visitConstant(tree.Constant exp) {
497 return emitConstant(exp.expression);
498 }
499
500 Expression visitThis(tree.This exp) {
501 return new This();
502 }
503
504 Expression visitReifyTypeVar(tree.ReifyTypeVar exp) {
505 return new ReifyTypeVar(exp.typeVariable.name)
506 ..element = exp.typeVariable;
507 }
508
509 Expression visitLiteralList(tree.LiteralList exp) {
510 return new LiteralList(
511 exp.values.map(visitExpression).toList(growable: false),
512 typeArgument: emitOptionalType(exp.type.typeArguments.single));
513 }
514
515 Expression visitLiteralMap(tree.LiteralMap exp) {
516 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
517 exp.values.length,
518 (i) => new LiteralMapEntry(visitExpression(exp.keys[i]),
519 visitExpression(exp.values[i])));
520 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
521 ? null
522 : exp.type.typeArguments.map(createTypeAnnotation).toList(growable: fals e);
523 return new LiteralMap(entries, typeArguments: typeArguments);
524 }
525
526 Expression visitTypeOperator(tree.TypeOperator exp) {
527 return new TypeOperator(visitExpression(exp.receiver),
528 exp.operator,
529 createTypeAnnotation(exp.type));
530 }
531
532 List<Argument> emitArguments(tree.Invoke exp) {
533 List<tree.Expression> args = exp.arguments;
534 int positionalArgumentCount = exp.selector.positionalArgumentCount;
535 List<Argument> result = new List<Argument>.generate(positionalArgumentCount,
536 (i) => visitExpression(exp.arguments[i]));
537 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
538 result.add(new NamedArgument(exp.selector.namedArguments[i],
539 visitExpression(exp.arguments[positionalArgumentCount + i])));
540 }
541 return result;
542 }
543
544 Expression visitInvokeStatic(tree.InvokeStatic exp) {
545 switch (exp.selector.kind) {
546 case SelectorKind.GETTER:
547 return new Identifier(exp.target.name)..element = exp.target;
548
549 case SelectorKind.SETTER:
550 return new Assignment(
551 new Identifier(exp.target.name)..element = exp.target,
552 '=',
553 visitExpression(exp.arguments[0]));
554
555 case SelectorKind.CALL:
556 return new CallStatic(null, exp.target.name, emitArguments(exp))
557 ..element = exp.target;
558
559 default:
560 throw "Unexpected selector kind: ${exp.selector.kind}";
561 }
562 }
563
564 Expression emitMethodCall(tree.Invoke exp, Receiver receiver) {
565 List<Argument> args = emitArguments(exp);
566 switch (exp.selector.kind) {
567 case SelectorKind.CALL:
568 if (exp.selector.name == "call") {
569 return new CallFunction(receiver, args);
570 }
571 return new CallMethod(receiver, exp.selector.name, args);
572
573 case SelectorKind.OPERATOR:
574 if (args.length == 0) {
575 String name = exp.selector.name;
576 if (name == 'unary-') {
577 name = '-';
578 }
579 return new UnaryOperator(name, receiver);
580 }
581 return new BinaryOperator(receiver, exp.selector.name, args[0]);
582
583 case SelectorKind.GETTER:
584 return new FieldExpression(receiver, exp.selector.name);
585
586 case SelectorKind.SETTER:
587 return makeAssignment(
588 new FieldExpression(receiver, exp.selector.name),
589 args[0]);
590
591 case SelectorKind.INDEX:
592 Expression e = new IndexExpression(receiver, args[0]);
593 if (args.length == 2) {
594 e = makeAssignment(e, args[1]);
595 }
596 return e;
597
598 default:
599 throw "Unexpected selector in InvokeMethod: ${exp.selector.kind}";
600 }
601 }
602
603 Expression visitInvokeMethod(tree.InvokeMethod exp) {
604 Expression receiver = visitExpression(exp.receiver);
605 return emitMethodCall(exp, receiver);
606 }
607
608 Expression visitInvokeSuperMethod(tree.InvokeSuperMethod exp) {
609 return emitMethodCall(exp, new SuperReceiver());
610 }
611
612 Expression visitInvokeConstructor(tree.InvokeConstructor exp) {
613 List args = emitArguments(exp);
614 FunctionElement constructor = exp.target;
615 String name = constructor.name.isEmpty ? null : constructor.name;
616 return new CallNew(createTypeAnnotation(exp.type),
617 args,
618 constructorName: name,
619 isConst: exp.constant != null)
620 ..constructor = constructor
621 ..dartType = exp.type;
622 }
623
624 Expression visitConcatenateStrings(tree.ConcatenateStrings exp) {
625 List args = exp.arguments.map(visitExpression).toList(growable:false);
626 return new StringConcat(args);
627 }
628
629 Expression visitConditional(tree.Conditional exp) {
630 return new Conditional(
631 visitExpression(exp.condition),
632 visitExpression(exp.thenExpression),
633 visitExpression(exp.elseExpression));
634 }
635
636 Expression visitLogicalOperator(tree.LogicalOperator exp) {
637 return new BinaryOperator(visitExpression(exp.left),
638 exp.operator,
639 visitExpression(exp.right));
640 }
641
642 Expression visitNot(tree.Not exp) {
643 return new UnaryOperator('!', visitExpression(exp.operand));
644 }
645
646 Expression visitVariable(tree.Variable exp) {
647 return new Identifier(getVariableName(exp))
648 ..element = exp.element;
649 }
650
651 FunctionExpression makeSubFunction(tree.FunctionDefinition function) {
652 return new ASTEmitter.inner(this).emit(function);
653 }
654
655 Expression visitFunctionExpression(tree.FunctionExpression exp) {
656 return makeSubFunction(exp.definition)..name = null;
657 }
658
659 void visitFunctionDeclaration(tree.FunctionDeclaration node) {
660 assert(variableNames[node.variable] == null);
661 String name = getVariableName(node.variable);
662 FunctionExpression inner = makeSubFunction(node.definition);
663 inner.name = name;
664 FunctionDeclaration decl = new FunctionDeclaration(inner);
665 declaredVariables.add(node.variable);
666 statementBuffer.add(decl);
667 visitStatement(node.next);
668 }
669
670 /// Like [createTypeAnnotation] except the dynamic type is converted to null.
671 TypeAnnotation emitOptionalType(DartType type) {
672 if (type.treatAsDynamic) {
673 return null;
674 } else {
675 return createTypeAnnotation(type);
676 }
677 }
678
679 Expression emitConstant(ConstantExpression exp) {
680 return new ConstantEmitter(this).visit(exp);
681 }
682 }
683
684 TypeAnnotation createTypeAnnotation(DartType type) {
685 if (type is GenericType) {
686 if (type.treatAsRaw) {
687 return new TypeAnnotation(type.element.name)..dartType = type;
688 }
689 return new TypeAnnotation(
690 type.element.name,
691 type.typeArguments.map(createTypeAnnotation).toList(growable:false))
692 ..dartType = type;
693 } else if (type is VoidType) {
694 return new TypeAnnotation('void')
695 ..dartType = type;
696 } else if (type is TypeVariableType) {
697 return new TypeAnnotation(type.name)
698 ..dartType = type;
699 } else if (type is DynamicType) {
700 return new TypeAnnotation("dynamic")
701 ..dartType = type;
702 } else if (type is MalformedType) {
703 return new TypeAnnotation(type.name)
704 ..dartType = type;
705 } else {
706 throw "Unsupported type annotation: $type";
707 }
708 }
709
710 class ConstantEmitter extends ConstantExpressionVisitor<Expression> {
711 ASTEmitter parent;
712 ConstantEmitter(this.parent);
713
714 Expression handlePrimitiveConstant(PrimitiveConstantValue value) {
715 // Num constants may be negative, while literals must be non-negative:
716 // Literals are non-negative in the specification, and a negated literal
717 // parses as a call to unary `-`. The AST unparser assumes literals are
718 // non-negative and relies on this to avoid incorrectly generating `--`,
719 // the predecrement operator.
720 // Translate such constants into their positive value wrapped by
721 // the unary minus operator.
722 if (value.isNum) {
723 NumConstantValue numConstant = value;
724 if (numConstant.primitiveValue.isNegative) {
725 return negatedLiteral(numConstant);
726 }
727 }
728 return new Literal(value);
729 }
730
731 @override
732 Expression visitPrimitive(PrimitiveConstantExpression exp) {
733 return handlePrimitiveConstant(exp.value);
734 }
735
736 /// Given a negative num constant, returns the corresponding positive
737 /// literal wrapped by a unary minus operator.
738 Expression negatedLiteral(NumConstantValue constant) {
739 assert(constant.primitiveValue.isNegative);
740 NumConstantValue positiveConstant;
741 if (constant.isInt) {
742 positiveConstant = new IntConstantValue(-constant.primitiveValue);
743 } else if (constant.isDouble) {
744 positiveConstant = new DoubleConstantValue(-constant.primitiveValue);
745 } else {
746 throw "Unexpected type of NumConstant: $constant";
747 }
748 return new UnaryOperator('-', new Literal(positiveConstant));
749 }
750
751 @override
752 Expression visitList(ListConstantExpression exp) {
753 return new LiteralList(
754 exp.values.map(visit).toList(growable: false),
755 isConst: true,
756 typeArgument: parent.emitOptionalType(exp.type.typeArguments.single));
757 }
758
759 @override
760 Expression visitMap(MapConstantExpression exp) {
761 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
762 exp.values.length,
763 (i) => new LiteralMapEntry(visit(exp.keys[i]),
764 visit(exp.values[i])));
765 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
766 ? null
767 : exp.type.typeArguments.map(createTypeAnnotation).toList();
768 return new LiteralMap(entries, isConst: true, typeArguments: typeArguments);
769 }
770
771 @override
772 Expression visitConstructor(ConstructedConstantExpresssion exp) {
773 int positionalArgumentCount = exp.selector.positionalArgumentCount;
774 List<Argument> args = new List<Argument>.generate(
775 positionalArgumentCount,
776 (i) => visit(exp.arguments[i]));
777 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
778 args.add(new NamedArgument(exp.selector.namedArguments[i],
779 visit(exp.arguments[positionalArgumentCount + i])));
780 }
781
782 FunctionElement constructor = exp.target;
783 String name = constructor.name.isEmpty ? null : constructor.name;
784 return new CallNew(createTypeAnnotation(exp.type),
785 args,
786 constructorName: name,
787 isConst: true)
788 ..constructor = constructor
789 ..dartType = exp.type;
790 }
791
792 @override
793 Expression visitConcatenate(ConcatenateConstantExpression exp) {
794 return new StringConcat(exp.arguments.map(visit).toList(growable: false));
795 }
796
797 @override
798 Expression visitSymbol(SymbolConstantExpression exp) {
799 return new LiteralSymbol(exp.name);
800 }
801
802 @override
803 Expression visitType(TypeConstantExpression exp) {
804 DartType type = exp.type;
805 return new LiteralType(type.name)
806 ..type = type;
807 }
808
809 @override
810 Expression visitVariable(VariableConstantExpression exp) {
811 Element element = exp.element;
812 if (element.kind != ElementKind.VARIABLE) {
813 return new Identifier(element.name)..element = element;
814 }
815 String name = parent.getConstantName(element);
816 return new Identifier(name)
817 ..element = element;
818 }
819
820 @override
821 Expression visitFunction(FunctionConstantExpression exp) {
822 return new Identifier(exp.element.name)
823 ..element = exp.element;
824 }
825
826 @override
827 Expression visitBinary(BinaryConstantExpression exp) {
828 return handlePrimitiveConstant(exp.value);
829 }
830
831 @override
832 Expression visitConditional(ConditionalConstantExpression exp) {
833 if (exp.condition.value.isTrue) {
834 return exp.trueExp.accept(this);
835 } else {
836 return exp.falseExp.accept(this);
837 }
838 }
839
840 @override
841 Expression visitUnary(UnaryConstantExpression exp) {
842 return handlePrimitiveConstant(exp.value);
843 }
844 }
845
846 /// Moves function parameters into a separate variable if one of its uses is
847 /// shadowed by an inner function parameter.
848 /// This artifact is necessary because function parameters cannot be renamed.
849 class UnshadowParameters extends tree.RecursiveVisitor {
850
851 /// Maps parameter names to their bindings.
852 Map<String, tree.Variable> environment = <String, tree.Variable>{};
853
854 /// Parameters that are currently shadowed by another parameter.
855 Set<tree.Variable> shadowedParameters = new Set<tree.Variable>();
856
857 /// Parameters that are used in a context where it is shadowed.
858 Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>();
859
860 void unshadow(tree.FunctionDefinition definition) {
861 if (definition.isAbstract) return;
862
863 visitFunctionDefinition(definition);
864 }
865
866 visitFunctionDefinition(tree.FunctionDefinition definition) {
867 var oldShadow = shadowedParameters;
868 var oldEnvironment = environment;
869 environment = new Map<String, tree.Variable>.from(environment);
870 shadowedParameters = new Set<tree.Variable>.from(shadowedParameters);
871 for (tree.Variable param in definition.parameters) {
872 tree.Variable oldVariable = environment[param.element.name];
873 if (oldVariable != null) {
874 shadowedParameters.add(oldVariable);
875 }
876 environment[param.element.name] = param;
877 }
878 visitStatement(definition.body);
879 environment = oldEnvironment;
880 shadowedParameters = oldShadow;
881
882 for (int i=0; i<definition.parameters.length; i++) {
883 tree.Variable param = definition.parameters[i];
884 if (hasShadowedUse.remove(param)) {
885 tree.Variable newParam = new tree.Variable(definition, param.element);
886 definition.parameters[i] = newParam;
887 definition.body = new tree.Assign(param, newParam, definition.body);
888 newParam.writeCount = 1; // Being a parameter counts as a write.
889 }
890 }
891 }
892
893 visitVariable(tree.Variable variable) {
894 if (shadowedParameters.contains(variable)) {
895 hasShadowedUse.add(variable);
896 }
897 }
898
899 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698