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