Index: sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart |
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart |
deleted file mode 100644 |
index 7ceefa66b585b348a223d7065953f67102d0efb0..0000000000000000000000000000000000000000 |
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart |
+++ /dev/null |
@@ -1,919 +0,0 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library backend_ast_emitter; |
- |
-import 'tree_ir_nodes.dart' as tree; |
-import 'backend_ast_nodes.dart'; |
-import '../constants/expressions.dart'; |
-import '../constants/values.dart'; |
-import '../dart_types.dart'; |
-import '../elements/elements.dart'; |
-import '../elements/modelx.dart' as modelx; |
-import '../universe/universe.dart'; |
-import '../tree/tree.dart' as tree show Modifiers; |
- |
-/// Translates the dart_tree IR to Dart backend AST. |
-Expression emit(tree.FunctionDefinition definition) { |
- return new ASTEmitter().emit(definition); |
-} |
- |
-/// Translates the dart_tree IR to Dart backend AST. |
-/// An instance of this class should only be used once; a fresh emitter |
-/// must be created for each function to be emitted. |
-class ASTEmitter extends tree.Visitor<dynamic, Expression> { |
- /// Variables to be hoisted at the top of the current function. |
- List<VariableDeclaration> variables = <VariableDeclaration>[]; |
- |
- /// Maps variables to their name. |
- Map<tree.Variable, String> variableNames = <tree.Variable, String>{}; |
- |
- /// Maps local constants to their name. |
- Map<VariableElement, String> constantNames = <VariableElement, String>{}; |
- |
- /// Variables that have had their declaration created. |
- Set<tree.Variable> declaredVariables = new Set<tree.Variable>(); |
- |
- /// Variable names that have already been used. Used to avoid name clashes. |
- Set<String> usedVariableNames; |
- |
- /// Statements emitted by the most recent call to [visitStatement]. |
- List<Statement> statementBuffer = <Statement>[]; |
- |
- /// The function currently being emitted. |
- FunctionElement functionElement; |
- |
- /// Bookkeeping object needed to synthesize a variable declaration. |
- modelx.VariableList variableList |
- = new modelx.VariableList(tree.Modifiers.EMPTY); |
- |
- /// Input to [visitStatement]. Denotes the statement that will execute next |
- /// if the statements produced by [visitStatement] complete normally. |
- /// Set to null if control will fall over the end of the method. |
- tree.Statement fallthrough = null; |
- |
- /// Labels that could not be eliminated using fallthrough. |
- Set<tree.Label> usedLabels = new Set<tree.Label>(); |
- |
- /// The first dart_tree statement that is not converted to a variable |
- /// initializer. |
- tree.Statement firstStatement; |
- |
- /// Emitter for the enclosing function, or null if the current function is |
- /// not a local function. |
- ASTEmitter parent; |
- |
- ASTEmitter() : usedVariableNames = new Set<String>(); |
- |
- ASTEmitter.inner(ASTEmitter parent) |
- : this.parent = parent, |
- usedVariableNames = parent.usedVariableNames; |
- |
- FunctionExpression emit(tree.FunctionDefinition definition) { |
- functionElement = definition.element; |
- |
- Parameters parameters = emitRootParameters(definition); |
- |
- // Declare parameters. |
- for (tree.Variable param in definition.parameters) { |
- variableNames[param] = param.element.name; |
- usedVariableNames.add(param.element.name); |
- declaredVariables.add(param); |
- } |
- |
- Statement body; |
- if (definition.isAbstract) { |
- body = new EmptyStatement(); |
- } else { |
- firstStatement = definition.body; |
- visitStatement(definition.body); |
- removeTrailingReturn(); |
- |
- // Some of the variable declarations have already been added |
- // if their first assignment could be pulled into the initializer. |
- // Add the remaining variable declarations now. |
- for (tree.Variable variable in variableNames.keys) { |
- if (!declaredVariables.contains(variable)) { |
- addDeclaration(variable); |
- } |
- } |
- |
- // Add constant declarations. |
- List<VariableDeclaration> constants = <VariableDeclaration>[]; |
- for (ConstDeclaration constDecl in definition.localConstants) { |
- if (!constantNames.containsKey(constDecl.element)) |
- continue; // Discard unused constants declarations. |
- String name = getConstantName(constDecl.element); |
- Expression value = emitConstant(constDecl.expression); |
- VariableDeclaration decl = new VariableDeclaration(name, value); |
- decl.element = constDecl.element; |
- constants.add(decl); |
- } |
- |
- List<Statement> bodyParts = []; |
- if (constants.length > 0) { |
- bodyParts.add(new VariableDeclarations(constants, isConst: true)); |
- } |
- if (variables.length > 0) { |
- bodyParts.add(new VariableDeclarations(variables)); |
- } |
- bodyParts.addAll(statementBuffer); |
- |
- body = new Block(bodyParts); |
- } |
- FunctionType functionType = functionElement.type; |
- |
- return new FunctionExpression( |
- parameters, |
- body, |
- name: functionElement.name, |
- returnType: emitOptionalType(functionType.returnType), |
- isGetter: functionElement.isGetter, |
- isSetter: functionElement.isSetter) |
- ..element = functionElement; |
- } |
- |
- void addDeclaration(tree.Variable variable, [Expression initializer]) { |
- assert(!declaredVariables.contains(variable)); |
- String name = getVariableName(variable); |
- VariableDeclaration decl = new VariableDeclaration(name, initializer); |
- decl.element = variable.element; |
- declaredVariables.add(variable); |
- variables.add(decl); |
- } |
- |
- /// Removes a trailing "return null" from [statementBuffer]. |
- void removeTrailingReturn() { |
- if (statementBuffer.isEmpty) return; |
- if (statementBuffer.last is! Return) return; |
- Return ret = statementBuffer.last; |
- Expression expr = ret.expression; |
- if (expr is Literal && expr.value.isNull) { |
- statementBuffer.removeLast(); |
- } |
- } |
- |
- /// TODO(johnniwinther): Remove this when issue 21283 has been resolved. |
- int pseudoNameCounter = 0; |
- |
- Parameter emitParameter(DartType type, |
- {String name, |
- Element element, |
- ConstantExpression defaultValue}) { |
- if (name == null && element != null) { |
- name = element.name; |
- } |
- if (name == null) { |
- name = '_${pseudoNameCounter++}'; |
- } |
- Parameter parameter; |
- if (type.isFunctionType) { |
- FunctionType functionType = type; |
- TypeAnnotation returnType = emitOptionalType(functionType.returnType); |
- Parameters innerParameters = emitParametersFromType(functionType); |
- parameter = new Parameter.function(name, returnType, innerParameters); |
- } else { |
- TypeAnnotation typeAnnotation = emitOptionalType(type); |
- parameter = new Parameter(name, type: typeAnnotation); |
- } |
- parameter.element = element; |
- if (defaultValue != null && !defaultValue.value.isNull) { |
- parameter.defaultValue = emitConstant(defaultValue); |
- } |
- return parameter; |
- } |
- |
- Parameters emitParametersFromType(FunctionType functionType) { |
- if (functionType.namedParameters.isEmpty) { |
- return new Parameters( |
- emitParameters(functionType.parameterTypes), |
- emitParameters(functionType.optionalParameterTypes), |
- false); |
- } else { |
- return new Parameters( |
- emitParameters(functionType.parameterTypes), |
- emitParameters(functionType.namedParameterTypes, |
- names: functionType.namedParameters), |
- true); |
- } |
- } |
- |
- List<Parameter> emitParameters( |
- Iterable<DartType> parameterTypes, |
- {Iterable<String> names: const <String>[], |
- Iterable<ConstantExpression> defaultValues: const <ConstantExpression>[], |
- Iterable<Element> elements: const <Element>[]}) { |
- Iterator<String> name = names.iterator; |
- Iterator<ConstantExpression> defaultValue = defaultValues.iterator; |
- Iterator<Element> element = elements.iterator; |
- return parameterTypes.map((DartType type) { |
- name.moveNext(); |
- defaultValue.moveNext(); |
- element.moveNext(); |
- return emitParameter(type, |
- name: name.current, |
- defaultValue: defaultValue.current, |
- element: element.current); |
- }).toList(); |
- } |
- |
- /// Emits parameters that are not nested inside other parameters. |
- /// Root parameters can have default values, while inner parameters cannot. |
- Parameters emitRootParameters(tree.FunctionDefinition function) { |
- FunctionType functionType = function.element.type; |
- List<Parameter> required = emitParameters( |
- functionType.parameterTypes, |
- elements: function.parameters.map((p) => p.element)); |
- bool optionalParametersAreNamed = !functionType.namedParameters.isEmpty; |
- List<Parameter> optional = emitParameters( |
- optionalParametersAreNamed |
- ? functionType.namedParameterTypes |
- : functionType.optionalParameterTypes, |
- defaultValues: function.defaultParameterValues, |
- elements: function.parameters.skip(required.length) |
- .map((p) => p.element)); |
- return new Parameters(required, optional, optionalParametersAreNamed); |
- } |
- |
- /// True if the two expressions are a reference to the same variable. |
- bool isSameVariable(Receiver e1, Receiver e2) { |
- return e1 is Identifier && |
- e2 is Identifier && |
- e1.element is VariableElement && |
- e1.element == e2.element; |
- } |
- |
- Expression makeAssignment(Expression target, Expression value) { |
- // Try to print as compound assignment or increment |
- if (value is BinaryOperator && isCompoundableOperator(value.operator)) { |
- Expression leftOperand = value.left; |
- Expression rightOperand = value.right; |
- bool valid = false; |
- if (isSameVariable(target, leftOperand)) { |
- valid = true; |
- } else if (target is FieldExpression && |
- leftOperand is FieldExpression && |
- isSameVariable(target.object, leftOperand.object) && |
- target.fieldName == leftOperand.fieldName) { |
- valid = true; |
- } else if (target is IndexExpression && |
- leftOperand is IndexExpression && |
- isSameVariable(target.object, leftOperand.object) && |
- isSameVariable(target.index, leftOperand.index)) { |
- valid = true; |
- } |
- if (valid) { |
- if (rightOperand is Literal && rightOperand.value.isOne && |
- (value.operator == '+' || value.operator == '-')) { |
- return new Increment.prefix(target, value.operator + value.operator); |
- } else { |
- return new Assignment(target, value.operator + '=', rightOperand); |
- } |
- } |
- } |
- // Fall back to regular assignment |
- return new Assignment(target, '=', value); |
- } |
- |
- void visitExpressionStatement(tree.ExpressionStatement stmt) { |
- Expression e = visitExpression(stmt.expression); |
- statementBuffer.add(new ExpressionStatement(e)); |
- visitStatement(stmt.next); |
- } |
- |
- void visitLabeledStatement(tree.LabeledStatement stmt) { |
- List<Statement> savedBuffer = statementBuffer; |
- tree.Statement savedFallthrough = fallthrough; |
- statementBuffer = <Statement>[]; |
- fallthrough = stmt.next; |
- visitStatement(stmt.body); |
- if (usedLabels.remove(stmt.label)) { |
- savedBuffer.add(new LabeledStatement(stmt.label.name, |
- new Block(statementBuffer))); |
- } else { |
- savedBuffer.add(new Block(statementBuffer)); |
- } |
- fallthrough = savedFallthrough; |
- statementBuffer = savedBuffer; |
- visitStatement(stmt.next); |
- } |
- |
- /// Generates a name for the given variable and synthesizes an element for it, |
- /// if necessary. |
- String getVariableName(tree.Variable variable) { |
- // If the variable belongs to an enclosing function, ask the parent emitter |
- // for the variable name. |
- if (variable.host.element != functionElement) { |
- return parent.getVariableName(variable); |
- } |
- |
- // Get the name if we already have one. |
- String name = variableNames[variable]; |
- if (name != null) { |
- return name; |
- } |
- |
- // Synthesize a variable name that isn't used elsewhere. |
- // The [usedVariableNames] set is shared between nested emitters, |
- // so this also prevents clash with variables in an enclosing/inner scope. |
- // The renaming phase after codegen will further prefix local variables |
- // so they cannot clash with top-level variables or fields. |
- String prefix = variable.element == null ? 'v' : variable.element.name; |
- int counter = 0; |
- name = variable.element == null ? '$prefix$counter' : variable.element.name; |
- while (!usedVariableNames.add(name)) { |
- ++counter; |
- name = '$prefix$counter'; |
- } |
- variableNames[variable] = name; |
- |
- // Synthesize an element for the variable |
- if (variable.element == null || name != variable.element.name) { |
- // TODO(johnniwinther): Replace by synthetic [Entity]. |
- variable.element = new _SyntheticLocalVariableElement( |
- name, |
- functionElement, |
- variableList); |
- } |
- return name; |
- } |
- |
- String getConstantName(VariableElement element) { |
- assert(element.kind == ElementKind.VARIABLE); |
- if (element.enclosingElement != functionElement) { |
- return parent.getConstantName(element); |
- } |
- String name = constantNames[element]; |
- if (name != null) { |
- return name; |
- } |
- String prefix = element.name; |
- int counter = 0; |
- name = element.name; |
- while (!usedVariableNames.add(name)) { |
- ++counter; |
- name = '$prefix$counter'; |
- } |
- constantNames[element] = name; |
- return name; |
- } |
- |
- bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull; |
- |
- void visitAssign(tree.Assign stmt) { |
- // Try to emit a local function declaration. This is useful for functions |
- // that may occur in expression context, but could not be inlined anywhere. |
- if (stmt.variable.element is FunctionElement && |
- stmt.definition is tree.FunctionExpression && |
- !declaredVariables.contains(stmt.variable)) { |
- tree.FunctionExpression functionExp = stmt.definition; |
- FunctionExpression function = makeSubFunction(functionExp.definition); |
- FunctionDeclaration decl = new FunctionDeclaration(function); |
- statementBuffer.add(decl); |
- declaredVariables.add(stmt.variable); |
- visitStatement(stmt.next); |
- return; |
- } |
- |
- bool isFirstOccurrence = (variableNames[stmt.variable] == null); |
- bool isDeclaredHere = stmt.variable.host.element == functionElement; |
- String name = getVariableName(stmt.variable); |
- Expression definition = visitExpression(stmt.definition); |
- |
- // Try to pull into initializer. |
- if (firstStatement == stmt && isFirstOccurrence && isDeclaredHere) { |
- if (isNullLiteral(definition)) definition = null; |
- addDeclaration(stmt.variable, definition); |
- firstStatement = stmt.next; |
- visitStatement(stmt.next); |
- return; |
- } |
- |
- // Emit a variable declaration if we are required to do so. |
- // This is to ensure that a fresh closure variable is created. |
- if (stmt.isDeclaration) { |
- assert(isFirstOccurrence); |
- assert(isDeclaredHere); |
- if (isNullLiteral(definition)) definition = null; |
- VariableDeclaration decl = new VariableDeclaration(name, definition) |
- ..element = stmt.variable.element; |
- declaredVariables.add(stmt.variable); |
- statementBuffer.add(new VariableDeclarations([decl])); |
- visitStatement(stmt.next); |
- return; |
- } |
- |
- statementBuffer.add(new ExpressionStatement(makeAssignment( |
- visitVariable(stmt.variable), |
- definition))); |
- visitStatement(stmt.next); |
- } |
- |
- void visitReturn(tree.Return stmt) { |
- Expression inner = visitExpression(stmt.value); |
- statementBuffer.add(new Return(inner)); |
- } |
- |
- void visitBreak(tree.Break stmt) { |
- tree.Statement fall = fallthrough; |
- if (stmt.target.binding.next == fall) { |
- // Fall through to break target |
- } else if (fall is tree.Break && fall.target == stmt.target) { |
- // Fall through to equivalent break |
- } else { |
- usedLabels.add(stmt.target); |
- statementBuffer.add(new Break(stmt.target.name)); |
- } |
- } |
- |
- void visitContinue(tree.Continue stmt) { |
- tree.Statement fall = fallthrough; |
- if (stmt.target.binding == fall) { |
- // Fall through to continue target |
- } else if (fall is tree.Continue && fall.target == stmt.target) { |
- // Fall through to equivalent continue |
- } else { |
- usedLabels.add(stmt.target); |
- statementBuffer.add(new Continue(stmt.target.name)); |
- } |
- } |
- |
- void visitIf(tree.If stmt) { |
- Expression condition = visitExpression(stmt.condition); |
- List<Statement> savedBuffer = statementBuffer; |
- List<Statement> thenBuffer = statementBuffer = <Statement>[]; |
- visitStatement(stmt.thenStatement); |
- List<Statement> elseBuffer = statementBuffer = <Statement>[]; |
- visitStatement(stmt.elseStatement); |
- savedBuffer.add( |
- new If(condition, new Block(thenBuffer), new Block(elseBuffer))); |
- statementBuffer = savedBuffer; |
- } |
- |
- void visitWhileTrue(tree.WhileTrue stmt) { |
- List<Statement> savedBuffer = statementBuffer; |
- tree.Statement savedFallthrough = fallthrough; |
- statementBuffer = <Statement>[]; |
- fallthrough = stmt; |
- |
- visitStatement(stmt.body); |
- Statement body = new Block(statementBuffer); |
- Statement statement = new While(new Literal(new TrueConstantValue()), |
- body); |
- if (usedLabels.remove(stmt.label)) { |
- statement = new LabeledStatement(stmt.label.name, statement); |
- } |
- savedBuffer.add(statement); |
- |
- statementBuffer = savedBuffer; |
- fallthrough = savedFallthrough; |
- } |
- |
- void visitWhileCondition(tree.WhileCondition stmt) { |
- Expression condition = visitExpression(stmt.condition); |
- |
- List<Statement> savedBuffer = statementBuffer; |
- tree.Statement savedFallthrough = fallthrough; |
- statementBuffer = <Statement>[]; |
- fallthrough = stmt; |
- |
- visitStatement(stmt.body); |
- Statement body = new Block(statementBuffer); |
- Statement statement; |
- statement = new While(condition, body); |
- if (usedLabels.remove(stmt.label)) { |
- statement = new LabeledStatement(stmt.label.name, statement); |
- } |
- savedBuffer.add(statement); |
- |
- statementBuffer = savedBuffer; |
- fallthrough = savedFallthrough; |
- |
- visitStatement(stmt.next); |
- } |
- |
- Expression visitConstant(tree.Constant exp) { |
- return emitConstant(exp.expression); |
- } |
- |
- Expression visitThis(tree.This exp) { |
- return new This(); |
- } |
- |
- Expression visitReifyTypeVar(tree.ReifyTypeVar exp) { |
- return new ReifyTypeVar(exp.typeVariable.name) |
- ..element = exp.typeVariable; |
- } |
- |
- Expression visitLiteralList(tree.LiteralList exp) { |
- return new LiteralList( |
- exp.values.map(visitExpression).toList(growable: false), |
- typeArgument: emitOptionalType(exp.type.typeArguments.single)); |
- } |
- |
- Expression visitLiteralMap(tree.LiteralMap exp) { |
- List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate( |
- exp.entries.length, |
- (i) => new LiteralMapEntry(visitExpression(exp.entries[i].key), |
- visitExpression(exp.entries[i].value))); |
- List<TypeAnnotation> typeArguments = exp.type.treatAsRaw |
- ? null |
- : exp.type.typeArguments.map(createTypeAnnotation) |
- .toList(growable: false); |
- return new LiteralMap(entries, typeArguments: typeArguments); |
- } |
- |
- Expression visitTypeOperator(tree.TypeOperator exp) { |
- return new TypeOperator(visitExpression(exp.receiver), |
- exp.operator, |
- createTypeAnnotation(exp.type)); |
- } |
- |
- List<Argument> emitArguments(tree.Invoke exp) { |
- List<tree.Expression> args = exp.arguments; |
- int positionalArgumentCount = exp.selector.positionalArgumentCount; |
- List<Argument> result = new List<Argument>.generate(positionalArgumentCount, |
- (i) => visitExpression(exp.arguments[i])); |
- for (int i = 0; i < exp.selector.namedArgumentCount; ++i) { |
- result.add(new NamedArgument(exp.selector.namedArguments[i], |
- visitExpression(exp.arguments[positionalArgumentCount + i]))); |
- } |
- return result; |
- } |
- |
- Expression visitInvokeStatic(tree.InvokeStatic exp) { |
- switch (exp.selector.kind) { |
- case SelectorKind.GETTER: |
- return new Identifier(exp.target.name)..element = exp.target; |
- |
- case SelectorKind.SETTER: |
- return new Assignment( |
- new Identifier(exp.target.name)..element = exp.target, |
- '=', |
- visitExpression(exp.arguments[0])); |
- |
- case SelectorKind.CALL: |
- return new CallStatic(null, exp.target.name, emitArguments(exp)) |
- ..element = exp.target; |
- |
- default: |
- throw "Unexpected selector kind: ${exp.selector.kind}"; |
- } |
- } |
- |
- Expression emitMethodCall(tree.Invoke exp, Receiver receiver) { |
- List<Argument> args = emitArguments(exp); |
- switch (exp.selector.kind) { |
- case SelectorKind.CALL: |
- if (exp.selector.name == "call") { |
- return new CallFunction(receiver, args); |
- } |
- return new CallMethod(receiver, exp.selector.name, args); |
- |
- case SelectorKind.OPERATOR: |
- if (args.length == 0) { |
- String name = exp.selector.name; |
- if (name == 'unary-') { |
- name = '-'; |
- } |
- return new UnaryOperator(name, receiver); |
- } |
- return new BinaryOperator(receiver, exp.selector.name, args[0]); |
- |
- case SelectorKind.GETTER: |
- return new FieldExpression(receiver, exp.selector.name); |
- |
- case SelectorKind.SETTER: |
- return makeAssignment( |
- new FieldExpression(receiver, exp.selector.name), |
- args[0]); |
- |
- case SelectorKind.INDEX: |
- Expression e = new IndexExpression(receiver, args[0]); |
- if (args.length == 2) { |
- e = makeAssignment(e, args[1]); |
- } |
- return e; |
- |
- default: |
- throw "Unexpected selector in InvokeMethod: ${exp.selector.kind}"; |
- } |
- } |
- |
- Expression visitInvokeMethod(tree.InvokeMethod exp) { |
- Expression receiver = visitExpression(exp.receiver); |
- return emitMethodCall(exp, receiver); |
- } |
- |
- Expression visitInvokeSuperMethod(tree.InvokeSuperMethod exp) { |
- return emitMethodCall(exp, new SuperReceiver()); |
- } |
- |
- Expression visitInvokeConstructor(tree.InvokeConstructor exp) { |
- List args = emitArguments(exp); |
- FunctionElement constructor = exp.target; |
- String name = constructor.name.isEmpty ? null : constructor.name; |
- return new CallNew(createTypeAnnotation(exp.type), |
- args, |
- constructorName: name, |
- isConst: exp.constant != null) |
- ..constructor = constructor |
- ..dartType = exp.type; |
- } |
- |
- Expression visitConcatenateStrings(tree.ConcatenateStrings exp) { |
- List args = exp.arguments.map(visitExpression).toList(growable:false); |
- return new StringConcat(args); |
- } |
- |
- Expression visitConditional(tree.Conditional exp) { |
- return new Conditional( |
- visitExpression(exp.condition), |
- visitExpression(exp.thenExpression), |
- visitExpression(exp.elseExpression)); |
- } |
- |
- Expression visitLogicalOperator(tree.LogicalOperator exp) { |
- return new BinaryOperator(visitExpression(exp.left), |
- exp.operator, |
- visitExpression(exp.right)); |
- } |
- |
- Expression visitNot(tree.Not exp) { |
- return new UnaryOperator('!', visitExpression(exp.operand)); |
- } |
- |
- Expression visitVariable(tree.Variable exp) { |
- return new Identifier(getVariableName(exp)) |
- ..element = exp.element; |
- } |
- |
- FunctionExpression makeSubFunction(tree.FunctionDefinition function) { |
- return new ASTEmitter.inner(this).emit(function); |
- } |
- |
- Expression visitFunctionExpression(tree.FunctionExpression exp) { |
- return makeSubFunction(exp.definition)..name = null; |
- } |
- |
- void visitFunctionDeclaration(tree.FunctionDeclaration node) { |
- assert(variableNames[node.variable] == null); |
- String name = getVariableName(node.variable); |
- FunctionExpression inner = makeSubFunction(node.definition); |
- inner.name = name; |
- FunctionDeclaration decl = new FunctionDeclaration(inner); |
- declaredVariables.add(node.variable); |
- statementBuffer.add(decl); |
- visitStatement(node.next); |
- } |
- |
- /// Like [createTypeAnnotation] except the dynamic type is converted to null. |
- TypeAnnotation emitOptionalType(DartType type) { |
- if (type.treatAsDynamic) { |
- return null; |
- } else { |
- return createTypeAnnotation(type); |
- } |
- } |
- |
- Expression emitConstant(ConstantExpression exp) { |
- return new ConstantEmitter(this).visit(exp); |
- } |
-} |
- |
-TypeAnnotation createTypeAnnotation(DartType type) { |
- if (type is GenericType) { |
- if (type.treatAsRaw) { |
- return new TypeAnnotation(type.element.name)..dartType = type; |
- } |
- return new TypeAnnotation( |
- type.element.name, |
- type.typeArguments.map(createTypeAnnotation).toList(growable:false)) |
- ..dartType = type; |
- } else if (type is VoidType) { |
- return new TypeAnnotation('void') |
- ..dartType = type; |
- } else if (type is TypeVariableType) { |
- return new TypeAnnotation(type.name) |
- ..dartType = type; |
- } else if (type is DynamicType) { |
- return new TypeAnnotation("dynamic") |
- ..dartType = type; |
- } else if (type is MalformedType) { |
- return new TypeAnnotation(type.name) |
- ..dartType = type; |
- } else { |
- throw "Unsupported type annotation: $type"; |
- } |
-} |
- |
-class ConstantEmitter extends ConstantExpressionVisitor<Expression> { |
- ASTEmitter parent; |
- ConstantEmitter(this.parent); |
- |
- Expression handlePrimitiveConstant(PrimitiveConstantValue value) { |
- // Num constants may be negative, while literals must be non-negative: |
- // Literals are non-negative in the specification, and a negated literal |
- // parses as a call to unary `-`. The AST unparser assumes literals are |
- // non-negative and relies on this to avoid incorrectly generating `--`, |
- // the predecrement operator. |
- // Translate such constants into their positive value wrapped by |
- // the unary minus operator. |
- if (value.isNum) { |
- NumConstantValue numConstant = value; |
- if (numConstant.primitiveValue.isNegative) { |
- return negatedLiteral(numConstant); |
- } |
- } |
- return new Literal(value); |
- } |
- |
- @override |
- Expression visitPrimitive(PrimitiveConstantExpression exp) { |
- return handlePrimitiveConstant(exp.value); |
- } |
- |
- /// Given a negative num constant, returns the corresponding positive |
- /// literal wrapped by a unary minus operator. |
- Expression negatedLiteral(NumConstantValue constant) { |
- assert(constant.primitiveValue.isNegative); |
- NumConstantValue positiveConstant; |
- if (constant.isInt) { |
- positiveConstant = new IntConstantValue(-constant.primitiveValue); |
- } else if (constant.isDouble) { |
- positiveConstant = new DoubleConstantValue(-constant.primitiveValue); |
- } else { |
- throw "Unexpected type of NumConstant: $constant"; |
- } |
- return new UnaryOperator('-', new Literal(positiveConstant)); |
- } |
- |
- @override |
- Expression visitList(ListConstantExpression exp) { |
- return new LiteralList( |
- exp.values.map(visit).toList(growable: false), |
- isConst: true, |
- typeArgument: parent.emitOptionalType(exp.type.typeArguments.single)); |
- } |
- |
- @override |
- Expression visitMap(MapConstantExpression exp) { |
- List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate( |
- exp.values.length, |
- (i) => new LiteralMapEntry(visit(exp.keys[i]), |
- visit(exp.values[i]))); |
- List<TypeAnnotation> typeArguments = exp.type.treatAsRaw |
- ? null |
- : exp.type.typeArguments.map(createTypeAnnotation).toList(); |
- return new LiteralMap(entries, isConst: true, typeArguments: typeArguments); |
- } |
- |
- @override |
- Expression visitConstructor(ConstructedConstantExpresssion exp) { |
- int positionalArgumentCount = exp.selector.positionalArgumentCount; |
- List<Argument> args = new List<Argument>.generate( |
- positionalArgumentCount, |
- (i) => visit(exp.arguments[i])); |
- for (int i = 0; i < exp.selector.namedArgumentCount; ++i) { |
- args.add(new NamedArgument(exp.selector.namedArguments[i], |
- visit(exp.arguments[positionalArgumentCount + i]))); |
- } |
- |
- FunctionElement constructor = exp.target; |
- String name = constructor.name.isEmpty ? null : constructor.name; |
- return new CallNew(createTypeAnnotation(exp.type), |
- args, |
- constructorName: name, |
- isConst: true) |
- ..constructor = constructor |
- ..dartType = exp.type; |
- } |
- |
- @override |
- Expression visitConcatenate(ConcatenateConstantExpression exp) { |
- return new StringConcat(exp.arguments.map(visit).toList(growable: false)); |
- } |
- |
- @override |
- Expression visitSymbol(SymbolConstantExpression exp) { |
- return new LiteralSymbol(exp.name); |
- } |
- |
- @override |
- Expression visitType(TypeConstantExpression exp) { |
- DartType type = exp.type; |
- return new LiteralType(type.name) |
- ..type = type; |
- } |
- |
- @override |
- Expression visitVariable(VariableConstantExpression exp) { |
- Element element = exp.element; |
- if (element.kind != ElementKind.VARIABLE) { |
- return new Identifier(element.name)..element = element; |
- } |
- String name = parent.getConstantName(element); |
- return new Identifier(name) |
- ..element = element; |
- } |
- |
- @override |
- Expression visitFunction(FunctionConstantExpression exp) { |
- return new Identifier(exp.element.name) |
- ..element = exp.element; |
- } |
- |
- @override |
- Expression visitBinary(BinaryConstantExpression exp) { |
- return handlePrimitiveConstant(exp.value); |
- } |
- |
- @override |
- Expression visitConditional(ConditionalConstantExpression exp) { |
- if (exp.condition.value.isTrue) { |
- return exp.trueExp.accept(this); |
- } else { |
- return exp.falseExp.accept(this); |
- } |
- } |
- |
- @override |
- Expression visitUnary(UnaryConstantExpression exp) { |
- return handlePrimitiveConstant(exp.value); |
- } |
-} |
- |
-/// Moves function parameters into a separate variable if one of its uses is |
-/// shadowed by an inner function parameter. |
-/// This artifact is necessary because function parameters cannot be renamed. |
-class UnshadowParameters extends tree.RecursiveVisitor { |
- |
- /// Maps parameter names to their bindings. |
- Map<String, tree.Variable> environment = <String, tree.Variable>{}; |
- |
- /// Parameters that are currently shadowed by another parameter. |
- Set<tree.Variable> shadowedParameters = new Set<tree.Variable>(); |
- |
- /// Parameters that are used in a context where it is shadowed. |
- Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>(); |
- |
- void unshadow(tree.FunctionDefinition definition) { |
- if (definition.isAbstract) return; |
- |
- visitFunctionDefinition(definition); |
- } |
- |
- visitFunctionDefinition(tree.FunctionDefinition definition) { |
- var oldShadow = shadowedParameters; |
- var oldEnvironment = environment; |
- environment = new Map<String, tree.Variable>.from(environment); |
- shadowedParameters = new Set<tree.Variable>.from(shadowedParameters); |
- for (tree.Variable param in definition.parameters) { |
- tree.Variable oldVariable = environment[param.element.name]; |
- if (oldVariable != null) { |
- shadowedParameters.add(oldVariable); |
- } |
- environment[param.element.name] = param; |
- } |
- visitStatement(definition.body); |
- environment = oldEnvironment; |
- shadowedParameters = oldShadow; |
- |
- for (int i=0; i<definition.parameters.length; i++) { |
- tree.Variable param = definition.parameters[i]; |
- if (hasShadowedUse.remove(param)) { |
- tree.Variable newParam = new tree.Variable(definition, param.element); |
- definition.parameters[i] = newParam; |
- definition.body = new tree.Assign(param, newParam, definition.body); |
- newParam.writeCount = 1; // Being a parameter counts as a write. |
- } |
- } |
- } |
- |
- visitVariable(tree.Variable variable) { |
- if (shadowedParameters.contains(variable)) { |
- hasShadowedUse.add(variable); |
- } |
- } |
- |
-} |
- |
-// TODO(johnniwinther): Remove this when the dart `backend_ast` does not need |
-// [Element] for entities. |
-class _SyntheticLocalVariableElement extends modelx.VariableElementX |
- implements LocalVariableElement { |
- |
- _SyntheticLocalVariableElement(String name, |
- ExecutableElement enclosingElement, |
- modelx.VariableList variables) |
- : super(name, ElementKind.VARIABLE, enclosingElement, variables, null); |
- |
- ExecutableElement get executableContext => enclosingElement; |
- |
- ExecutableElement get memberContext => executableContext.memberContext; |
- |
- bool get isLocal => true; |
- |
- LibraryElement get implementationLibrary => enclosingElement.library; |
-} |