OLD | NEW |
| (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 } | |
OLD | NEW |