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

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

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (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 _SyntheticLocalVariableElement(
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.entries.length,
518 (i) => new LiteralMapEntry(visitExpression(exp.entries[i].key),
519 visitExpression(exp.entries[i].value)));
520 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
521 ? null
522 : exp.type.typeArguments.map(createTypeAnnotation)
523 .toList(growable: false);
524 return new LiteralMap(entries, typeArguments: typeArguments);
525 }
526
527 Expression visitTypeOperator(tree.TypeOperator exp) {
528 return new TypeOperator(visitExpression(exp.receiver),
529 exp.operator,
530 createTypeAnnotation(exp.type));
531 }
532
533 List<Argument> emitArguments(tree.Invoke exp) {
534 List<tree.Expression> args = exp.arguments;
535 int positionalArgumentCount = exp.selector.positionalArgumentCount;
536 List<Argument> result = new List<Argument>.generate(positionalArgumentCount,
537 (i) => visitExpression(exp.arguments[i]));
538 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
539 result.add(new NamedArgument(exp.selector.namedArguments[i],
540 visitExpression(exp.arguments[positionalArgumentCount + i])));
541 }
542 return result;
543 }
544
545 Expression visitInvokeStatic(tree.InvokeStatic exp) {
546 switch (exp.selector.kind) {
547 case SelectorKind.GETTER:
548 return new Identifier(exp.target.name)..element = exp.target;
549
550 case SelectorKind.SETTER:
551 return new Assignment(
552 new Identifier(exp.target.name)..element = exp.target,
553 '=',
554 visitExpression(exp.arguments[0]));
555
556 case SelectorKind.CALL:
557 return new CallStatic(null, exp.target.name, emitArguments(exp))
558 ..element = exp.target;
559
560 default:
561 throw "Unexpected selector kind: ${exp.selector.kind}";
562 }
563 }
564
565 Expression emitMethodCall(tree.Invoke exp, Receiver receiver) {
566 List<Argument> args = emitArguments(exp);
567 switch (exp.selector.kind) {
568 case SelectorKind.CALL:
569 if (exp.selector.name == "call") {
570 return new CallFunction(receiver, args);
571 }
572 return new CallMethod(receiver, exp.selector.name, args);
573
574 case SelectorKind.OPERATOR:
575 if (args.length == 0) {
576 String name = exp.selector.name;
577 if (name == 'unary-') {
578 name = '-';
579 }
580 return new UnaryOperator(name, receiver);
581 }
582 return new BinaryOperator(receiver, exp.selector.name, args[0]);
583
584 case SelectorKind.GETTER:
585 return new FieldExpression(receiver, exp.selector.name);
586
587 case SelectorKind.SETTER:
588 return makeAssignment(
589 new FieldExpression(receiver, exp.selector.name),
590 args[0]);
591
592 case SelectorKind.INDEX:
593 Expression e = new IndexExpression(receiver, args[0]);
594 if (args.length == 2) {
595 e = makeAssignment(e, args[1]);
596 }
597 return e;
598
599 default:
600 throw "Unexpected selector in InvokeMethod: ${exp.selector.kind}";
601 }
602 }
603
604 Expression visitInvokeMethod(tree.InvokeMethod exp) {
605 Expression receiver = visitExpression(exp.receiver);
606 return emitMethodCall(exp, receiver);
607 }
608
609 Expression visitInvokeSuperMethod(tree.InvokeSuperMethod exp) {
610 return emitMethodCall(exp, new SuperReceiver());
611 }
612
613 Expression visitInvokeConstructor(tree.InvokeConstructor exp) {
614 List args = emitArguments(exp);
615 FunctionElement constructor = exp.target;
616 String name = constructor.name.isEmpty ? null : constructor.name;
617 return new CallNew(createTypeAnnotation(exp.type),
618 args,
619 constructorName: name,
620 isConst: exp.constant != null)
621 ..constructor = constructor
622 ..dartType = exp.type;
623 }
624
625 Expression visitConcatenateStrings(tree.ConcatenateStrings exp) {
626 List args = exp.arguments.map(visitExpression).toList(growable:false);
627 return new StringConcat(args);
628 }
629
630 Expression visitConditional(tree.Conditional exp) {
631 return new Conditional(
632 visitExpression(exp.condition),
633 visitExpression(exp.thenExpression),
634 visitExpression(exp.elseExpression));
635 }
636
637 Expression visitLogicalOperator(tree.LogicalOperator exp) {
638 return new BinaryOperator(visitExpression(exp.left),
639 exp.operator,
640 visitExpression(exp.right));
641 }
642
643 Expression visitNot(tree.Not exp) {
644 return new UnaryOperator('!', visitExpression(exp.operand));
645 }
646
647 Expression visitVariable(tree.Variable exp) {
648 return new Identifier(getVariableName(exp))
649 ..element = exp.element;
650 }
651
652 FunctionExpression makeSubFunction(tree.FunctionDefinition function) {
653 return new ASTEmitter.inner(this).emit(function);
654 }
655
656 Expression visitFunctionExpression(tree.FunctionExpression exp) {
657 return makeSubFunction(exp.definition)..name = null;
658 }
659
660 void visitFunctionDeclaration(tree.FunctionDeclaration node) {
661 assert(variableNames[node.variable] == null);
662 String name = getVariableName(node.variable);
663 FunctionExpression inner = makeSubFunction(node.definition);
664 inner.name = name;
665 FunctionDeclaration decl = new FunctionDeclaration(inner);
666 declaredVariables.add(node.variable);
667 statementBuffer.add(decl);
668 visitStatement(node.next);
669 }
670
671 /// Like [createTypeAnnotation] except the dynamic type is converted to null.
672 TypeAnnotation emitOptionalType(DartType type) {
673 if (type.treatAsDynamic) {
674 return null;
675 } else {
676 return createTypeAnnotation(type);
677 }
678 }
679
680 Expression emitConstant(ConstantExpression exp) {
681 return new ConstantEmitter(this).visit(exp);
682 }
683 }
684
685 TypeAnnotation createTypeAnnotation(DartType type) {
686 if (type is GenericType) {
687 if (type.treatAsRaw) {
688 return new TypeAnnotation(type.element.name)..dartType = type;
689 }
690 return new TypeAnnotation(
691 type.element.name,
692 type.typeArguments.map(createTypeAnnotation).toList(growable:false))
693 ..dartType = type;
694 } else if (type is VoidType) {
695 return new TypeAnnotation('void')
696 ..dartType = type;
697 } else if (type is TypeVariableType) {
698 return new TypeAnnotation(type.name)
699 ..dartType = type;
700 } else if (type is DynamicType) {
701 return new TypeAnnotation("dynamic")
702 ..dartType = type;
703 } else if (type is MalformedType) {
704 return new TypeAnnotation(type.name)
705 ..dartType = type;
706 } else {
707 throw "Unsupported type annotation: $type";
708 }
709 }
710
711 class ConstantEmitter extends ConstantExpressionVisitor<Expression> {
712 ASTEmitter parent;
713 ConstantEmitter(this.parent);
714
715 Expression handlePrimitiveConstant(PrimitiveConstantValue value) {
716 // Num constants may be negative, while literals must be non-negative:
717 // Literals are non-negative in the specification, and a negated literal
718 // parses as a call to unary `-`. The AST unparser assumes literals are
719 // non-negative and relies on this to avoid incorrectly generating `--`,
720 // the predecrement operator.
721 // Translate such constants into their positive value wrapped by
722 // the unary minus operator.
723 if (value.isNum) {
724 NumConstantValue numConstant = value;
725 if (numConstant.primitiveValue.isNegative) {
726 return negatedLiteral(numConstant);
727 }
728 }
729 return new Literal(value);
730 }
731
732 @override
733 Expression visitPrimitive(PrimitiveConstantExpression exp) {
734 return handlePrimitiveConstant(exp.value);
735 }
736
737 /// Given a negative num constant, returns the corresponding positive
738 /// literal wrapped by a unary minus operator.
739 Expression negatedLiteral(NumConstantValue constant) {
740 assert(constant.primitiveValue.isNegative);
741 NumConstantValue positiveConstant;
742 if (constant.isInt) {
743 positiveConstant = new IntConstantValue(-constant.primitiveValue);
744 } else if (constant.isDouble) {
745 positiveConstant = new DoubleConstantValue(-constant.primitiveValue);
746 } else {
747 throw "Unexpected type of NumConstant: $constant";
748 }
749 return new UnaryOperator('-', new Literal(positiveConstant));
750 }
751
752 @override
753 Expression visitList(ListConstantExpression exp) {
754 return new LiteralList(
755 exp.values.map(visit).toList(growable: false),
756 isConst: true,
757 typeArgument: parent.emitOptionalType(exp.type.typeArguments.single));
758 }
759
760 @override
761 Expression visitMap(MapConstantExpression exp) {
762 List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
763 exp.values.length,
764 (i) => new LiteralMapEntry(visit(exp.keys[i]),
765 visit(exp.values[i])));
766 List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
767 ? null
768 : exp.type.typeArguments.map(createTypeAnnotation).toList();
769 return new LiteralMap(entries, isConst: true, typeArguments: typeArguments);
770 }
771
772 @override
773 Expression visitConstructor(ConstructedConstantExpresssion exp) {
774 int positionalArgumentCount = exp.selector.positionalArgumentCount;
775 List<Argument> args = new List<Argument>.generate(
776 positionalArgumentCount,
777 (i) => visit(exp.arguments[i]));
778 for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
779 args.add(new NamedArgument(exp.selector.namedArguments[i],
780 visit(exp.arguments[positionalArgumentCount + i])));
781 }
782
783 FunctionElement constructor = exp.target;
784 String name = constructor.name.isEmpty ? null : constructor.name;
785 return new CallNew(createTypeAnnotation(exp.type),
786 args,
787 constructorName: name,
788 isConst: true)
789 ..constructor = constructor
790 ..dartType = exp.type;
791 }
792
793 @override
794 Expression visitConcatenate(ConcatenateConstantExpression exp) {
795 return new StringConcat(exp.arguments.map(visit).toList(growable: false));
796 }
797
798 @override
799 Expression visitSymbol(SymbolConstantExpression exp) {
800 return new LiteralSymbol(exp.name);
801 }
802
803 @override
804 Expression visitType(TypeConstantExpression exp) {
805 DartType type = exp.type;
806 return new LiteralType(type.name)
807 ..type = type;
808 }
809
810 @override
811 Expression visitVariable(VariableConstantExpression exp) {
812 Element element = exp.element;
813 if (element.kind != ElementKind.VARIABLE) {
814 return new Identifier(element.name)..element = element;
815 }
816 String name = parent.getConstantName(element);
817 return new Identifier(name)
818 ..element = element;
819 }
820
821 @override
822 Expression visitFunction(FunctionConstantExpression exp) {
823 return new Identifier(exp.element.name)
824 ..element = exp.element;
825 }
826
827 @override
828 Expression visitBinary(BinaryConstantExpression exp) {
829 return handlePrimitiveConstant(exp.value);
830 }
831
832 @override
833 Expression visitConditional(ConditionalConstantExpression exp) {
834 if (exp.condition.value.isTrue) {
835 return exp.trueExp.accept(this);
836 } else {
837 return exp.falseExp.accept(this);
838 }
839 }
840
841 @override
842 Expression visitUnary(UnaryConstantExpression exp) {
843 return handlePrimitiveConstant(exp.value);
844 }
845 }
846
847 /// Moves function parameters into a separate variable if one of its uses is
848 /// shadowed by an inner function parameter.
849 /// This artifact is necessary because function parameters cannot be renamed.
850 class UnshadowParameters extends tree.RecursiveVisitor {
851
852 /// Maps parameter names to their bindings.
853 Map<String, tree.Variable> environment = <String, tree.Variable>{};
854
855 /// Parameters that are currently shadowed by another parameter.
856 Set<tree.Variable> shadowedParameters = new Set<tree.Variable>();
857
858 /// Parameters that are used in a context where it is shadowed.
859 Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>();
860
861 void unshadow(tree.FunctionDefinition definition) {
862 if (definition.isAbstract) return;
863
864 visitFunctionDefinition(definition);
865 }
866
867 visitFunctionDefinition(tree.FunctionDefinition definition) {
868 var oldShadow = shadowedParameters;
869 var oldEnvironment = environment;
870 environment = new Map<String, tree.Variable>.from(environment);
871 shadowedParameters = new Set<tree.Variable>.from(shadowedParameters);
872 for (tree.Variable param in definition.parameters) {
873 tree.Variable oldVariable = environment[param.element.name];
874 if (oldVariable != null) {
875 shadowedParameters.add(oldVariable);
876 }
877 environment[param.element.name] = param;
878 }
879 visitStatement(definition.body);
880 environment = oldEnvironment;
881 shadowedParameters = oldShadow;
882
883 for (int i=0; i<definition.parameters.length; i++) {
884 tree.Variable param = definition.parameters[i];
885 if (hasShadowedUse.remove(param)) {
886 tree.Variable newParam = new tree.Variable(definition, param.element);
887 definition.parameters[i] = newParam;
888 definition.body = new tree.Assign(param, newParam, definition.body);
889 newParam.writeCount = 1; // Being a parameter counts as a write.
890 }
891 }
892 }
893
894 visitVariable(tree.Variable variable) {
895 if (shadowedParameters.contains(variable)) {
896 hasShadowedUse.add(variable);
897 }
898 }
899
900 }
901
902 // TODO(johnniwinther): Remove this when the dart `backend_ast` does not need
903 // [Element] for entities.
904 class _SyntheticLocalVariableElement extends modelx.VariableElementX
905 implements LocalVariableElement {
906
907 _SyntheticLocalVariableElement(String name,
908 ExecutableElement enclosingElement,
909 modelx.VariableList variables)
910 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null);
911
912 ExecutableElement get executableContext => enclosingElement;
913
914 ExecutableElement get memberContext => executableContext.memberContext;
915
916 bool get isLocal => true;
917
918 LibraryElement get implementationLibrary => enclosingElement.library;
919 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698