| Index: pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| index 572634132869217746e63c133e89f32139fac834..10b056d8fbc80c9f49698bb362dfc5347e4d837e 100644
|
| --- a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| +++ b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| @@ -4,1024 +4,9 @@
|
|
|
| library backend_ast_emitter;
|
|
|
| -import '../tree_ir/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.
|
| -RootNode emit(tree.RootNode root) {
|
| - return new ASTEmitter().emit(root);
|
| -}
|
| -
|
| -// TODO(johnniwinther): Split into function/block state.
|
| -class BuilderContext<T> {
|
| - /// Builder context for the enclosing function, or null if the current
|
| - /// function is not a local function.
|
| - BuilderContext<T> _parent;
|
| -
|
| - /// Variables to be hoisted at the top of the current function.
|
| - final List<VariableDeclaration> variables = <VariableDeclaration>[];
|
| -
|
| - /// Maps variables to their name.
|
| - final Map<tree.Variable, String> variableNames;
|
| -
|
| - /// Maps local constants to their name.
|
| - final Map<VariableElement, String> constantNames =
|
| - <VariableElement, String>{};
|
| -
|
| - /// Variables that have had their declaration created.
|
| - final Set<tree.Variable> declaredVariables = new Set<tree.Variable>();
|
| -
|
| - /// Variables that are used as catch handler parameters.
|
| - final Set<tree.Variable> handlerVariables = new Set<tree.Variable>();
|
| -
|
| - /// Variable names that have already been used. Used to avoid name clashes.
|
| - final Set<String> usedVariableNames;
|
| -
|
| - /// Statements emitted by the most recent call to [visitStatement].
|
| - List<T> _statementBuffer = <T>[];
|
| -
|
| - /// The element currently being emitted.
|
| - ExecutableElement currentElement;
|
| -
|
| - /// Bookkeeping object needed to synthesize a variable declaration.
|
| - final 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.
|
| - final Set<tree.Label> _usedLabels = new Set<tree.Label>();
|
| -
|
| - final bool inInitializer;
|
| -
|
| - /// The first dart_tree statement that is not converted to a variable
|
| - /// initializer.
|
| - tree.Statement firstStatement;
|
| -
|
| - BuilderContext() : usedVariableNames = new Set<String>(),
|
| - inInitializer = false,
|
| - variableNames = <tree.Variable, String>{};
|
| -
|
| - BuilderContext.inner(BuilderContext<T> parent)
|
| - : this._parent = parent,
|
| - usedVariableNames = parent.usedVariableNames,
|
| - inInitializer = false,
|
| - variableNames = <tree.Variable, String>{};
|
| -
|
| - BuilderContext.initializer(BuilderContext<T> parent)
|
| - : this._parent = parent,
|
| - usedVariableNames = parent.usedVariableNames,
|
| - inInitializer = true,
|
| - variableNames =
|
| - new Map<tree.Variable, String>.from(parent.variableNames);
|
| -
|
| - // TODO(johnniwinther): Fully encapsulate handling of parameter, variable
|
| - // and local function declarations.
|
| - 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);
|
| - }
|
| -
|
| - /// Creates an [Identifier] referring to the given variable.
|
| - Expression makeVariableAccess(tree.Variable variable) {
|
| - return new Identifier(getVariableName(variable))
|
| - ..element = variable.element;
|
| - }
|
| -
|
| - /// 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 (!inInitializer && variable.host != currentElement) {
|
| - 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,
|
| - currentElement,
|
| - variableList);
|
| - }
|
| - return name;
|
| - }
|
| -
|
| - /// Adds declarations for all variables that are still undeclared.
|
| - void declareRemainingVariables() {
|
| - // These variables can be referenced from other variable initializers if
|
| - // they are set by an assignment expression, so we declare variables before
|
| - // those with initializers.
|
| - List<VariableDeclaration> declarations = <VariableDeclaration>[];
|
| - for (tree.Variable variable in variableNames.keys) {
|
| - if (!declaredVariables.contains(variable)) {
|
| - String name = getVariableName(variable);
|
| - VariableDeclaration decl = new VariableDeclaration(name);
|
| - decl.element = variable.element;
|
| - declarations.add(decl);
|
| - declaredVariables.add(variable);
|
| - }
|
| - }
|
| - // Prepend all variables at once to avoid quadratic blowup.
|
| - variables.insertAll(0, declarations);
|
| - }
|
| -
|
| - String getConstantName(VariableElement element) {
|
| - assert(element.kind == ElementKind.VARIABLE);
|
| - if (element.enclosingElement != currentElement) {
|
| - 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;
|
| - }
|
| -
|
| - List<T> inSubcontext(f(BuilderContext<T> subcontext),
|
| - {tree.Statement fallthrough}) {
|
| - List<T> savedBuffer = this._statementBuffer;
|
| - tree.Statement savedFallthrough = this.fallthrough;
|
| - List<T> buffer = this._statementBuffer = <T>[];
|
| - if (fallthrough != null) {
|
| - this.fallthrough = fallthrough;
|
| - }
|
| - f(this);
|
| - this.fallthrough = savedFallthrough;
|
| - this._statementBuffer = savedBuffer;
|
| - return buffer;
|
| - }
|
| -
|
| - /// Removes a trailing "return null" from the current block.
|
| - void removeTrailingReturn(bool isReturnNull(T statement)) {
|
| - if (_statementBuffer.isEmpty) return;
|
| - if (isReturnNull(_statementBuffer.last)) {
|
| - _statementBuffer.removeLast();
|
| - }
|
| - }
|
| -
|
| - /// Register [label] as used.
|
| - void useLabel(tree.Label label) {
|
| - _usedLabels.add(label);
|
| - }
|
| -
|
| - /// Remove [label] and return `true` if it was used.
|
| - bool removeUsedLabel(tree.Label label) {
|
| - return _usedLabels.remove(label);
|
| - }
|
| -
|
| - /// Add [statement] to the current block.
|
| - void addStatement(T statement) {
|
| - _statementBuffer.add(statement);
|
| - }
|
| -
|
| - /// The statements in the current block.
|
| - Iterable<T> get statements => _statementBuffer;
|
| -}
|
| -
|
| -/// 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.StatementVisitor1<dynamic, BuilderContext<Statement>>
|
| - with tree.ExpressionVisitor1<Expression, BuilderContext<Statement>>,
|
| - tree.RootVisitor1<RootNode, BuilderContext<Statement>>,
|
| - tree.InitializerVisitor1<Initializer, BuilderContext<Statement>> {
|
| -
|
| - RootNode emit(tree.RootNode node) {
|
| - return visitRootNode(node, new BuilderContext<Statement>());
|
| - }
|
| -
|
| - @override
|
| - FieldDefinition visitFieldDefinition(tree.FieldDefinition definition,
|
| - BuilderContext<Statement> context) {
|
| - context.currentElement = definition.element;
|
| - Expression initializer;
|
| - if (!definition.isEmpty) {
|
| - visitStatement(definition.body, context);
|
| - List<Statement> bodyParts;
|
| - for (tree.Variable variable in context.variableNames.keys) {
|
| - if (!context.declaredVariables.contains(variable)) {
|
| - context.addDeclaration(variable);
|
| - }
|
| - }
|
| - if (context.variables.length > 0) {
|
| - bodyParts = new List<Statement>();
|
| - bodyParts.add(new VariableDeclarations(context.variables));
|
| - bodyParts.addAll(context.statements);
|
| - } else {
|
| - bodyParts = context.statements;
|
| - }
|
| - initializer = ensureExpression(bodyParts);
|
| - }
|
| -
|
| - return new FieldDefinition(definition.element, initializer);
|
| - }
|
| -
|
| - /// Returns an expression that will evaluate all of [bodyParts].
|
| - /// If [bodyParts] is a single [Return] return its value.
|
| - /// Otherwise wrap the body-parts in an immediately invoked closure.
|
| - Expression ensureExpression(List<Statement> bodyParts) {
|
| - if (bodyParts.length == 1) {
|
| - Statement onlyStatement = bodyParts.single;
|
| - if (onlyStatement is Return) {
|
| - return onlyStatement.expression;
|
| - }
|
| - }
|
| - Statement body = new Block(bodyParts);
|
| - FunctionExpression function =
|
| - new FunctionExpression(new Parameters([]), body);
|
| - function.element = null;
|
| - return new CallFunction(function, []);
|
| - }
|
| -
|
| - bool _recognizeTrailingReturn(Statement statement) {
|
| - if (statement is Return) {
|
| - Expression expr = statement.expression;
|
| - if (expr == null || expr is Literal && expr.value.isNull) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - @override
|
| - FunctionExpression visitConstructorDefinition(
|
| - tree.ConstructorDefinition definition,
|
| - BuilderContext<Statement> context) {
|
| - context.currentElement = definition.element;
|
| -
|
| - Parameters parameters = emitRootParameters(
|
| - definition, definition.defaultParameterValues, context);
|
| -
|
| - // Declare parameters.
|
| - for (tree.Variable param in definition.parameters) {
|
| - context.variableNames[param] = param.element.name;
|
| - context.usedVariableNames.add(param.element.name);
|
| - context.declaredVariables.add(param);
|
| - }
|
| -
|
| - List<Initializer> initializers;
|
| - Statement body;
|
| -
|
| - if (!definition.isEmpty) {
|
| - initializers =
|
| - definition.initializers.map((tree.Initializer initializer) {
|
| - return visitInitializer(initializer, context);
|
| - }).toList();
|
| -
|
| - context.firstStatement = definition.body;
|
| - visitStatement(definition.body, context);
|
| - context.removeTrailingReturn(_recognizeTrailingReturn);
|
| -
|
| - // 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.
|
| - context.declareRemainingVariables();
|
| -
|
| - // Add constant declarations.
|
| - List<VariableDeclaration> constants = <VariableDeclaration>[];
|
| - for (ConstDeclaration constDecl in definition.localConstants) {
|
| - if (!context.constantNames.containsKey(constDecl.element)) {
|
| - continue; // Discard unused constants declarations.
|
| - }
|
| - String name = context.getConstantName(constDecl.element);
|
| - Expression value =
|
| - ConstantEmitter.createExpression(constDecl.expression, context);
|
| - 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 (context.variables.length > 0) {
|
| - bodyParts.add(new VariableDeclarations(context.variables));
|
| - }
|
| - bodyParts.addAll(context.statements);
|
| - body = new Block(bodyParts);
|
| - }
|
| - return new ConstructorDefinition(
|
| - parameters,
|
| - body,
|
| - initializers,
|
| - context.currentElement.name,
|
| - definition.element.isConst)..element = context.currentElement;
|
| - }
|
| -
|
| - @override
|
| - FunctionExpression visitFunctionDefinition(
|
| - tree.FunctionDefinition definition,
|
| - BuilderContext<Statement> context) {
|
| - context.currentElement = definition.element;
|
| -
|
| - Parameters parameters = emitRootParameters(
|
| - definition, definition.defaultParameterValues, context);
|
| -
|
| - // Declare parameters.
|
| - for (tree.Variable param in definition.parameters) {
|
| - context.variableNames[param] = param.element.name;
|
| - context.usedVariableNames.add(param.element.name);
|
| - context.declaredVariables.add(param);
|
| - }
|
| -
|
| - Statement body;
|
| - if (definition.isEmpty) {
|
| - body = new EmptyStatement();
|
| - } else {
|
| - context.firstStatement = definition.body;
|
| - visitStatement(definition.body, context);
|
| - context.removeTrailingReturn(_recognizeTrailingReturn);
|
| -
|
| - // 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.
|
| - context.declareRemainingVariables();
|
| -
|
| - // Add constant declarations.
|
| - List<VariableDeclaration> constants = <VariableDeclaration>[];
|
| - for (ConstDeclaration constDecl in definition.localConstants) {
|
| - if (!context.constantNames.containsKey(constDecl.element)) {
|
| - continue; // Discard unused constants declarations.
|
| - }
|
| - String name = context.getConstantName(constDecl.element);
|
| - Expression value =
|
| - ConstantEmitter.createExpression(constDecl.expression, context);
|
| - 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 (context.variables.length > 0) {
|
| - bodyParts.add(new VariableDeclarations(context.variables));
|
| - }
|
| - bodyParts.addAll(context.statements);
|
| -
|
| - body = new Block(bodyParts);
|
| - }
|
| - FunctionType functionType = context.currentElement.type;
|
| -
|
| - return new FunctionExpression(
|
| - parameters,
|
| - body,
|
| - name: context.currentElement.name,
|
| - returnType: TypeGenerator.createOptionalType(functionType.returnType),
|
| - isGetter: context.currentElement.isGetter,
|
| - isSetter: context.currentElement.isSetter)
|
| - ..element = context.currentElement;
|
| - }
|
| -
|
| - /// Emits parameters that are not nested inside other parameters.
|
| - /// Root parameters can have default values, while inner parameters cannot.
|
| - Parameters emitRootParameters(tree.RootNode function,
|
| - List<ConstantExpression> defaults,
|
| - BuilderContext<Statement> context) {
|
| - FunctionType functionType = function.element.type;
|
| - List<Parameter> required = TypeGenerator.createParameters(
|
| - functionType.parameterTypes,
|
| - context: context,
|
| - elements: function.parameters.map((p) => p.element));
|
| - bool optionalParametersAreNamed = !functionType.namedParameters.isEmpty;
|
| - List<Parameter> optional = TypeGenerator.createParameters(
|
| - optionalParametersAreNamed
|
| - ? functionType.namedParameterTypes
|
| - : functionType.optionalParameterTypes,
|
| - context: context,
|
| - defaultValues: defaults,
|
| - 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)) {
|
| - Receiver 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);
|
| - }
|
| -
|
| - Block visitInSubContext(tree.Statement statement,
|
| - BuilderContext<Statement> context,
|
| - {tree.Statement fallthrough}) {
|
| - return new Block(context.inSubcontext(
|
| - (BuilderContext<Statement> subcontext) {
|
| - visitStatement(statement, subcontext);
|
| - }, fallthrough: fallthrough));
|
| - }
|
| -
|
| - void addLabeledStatement(tree.Label label,
|
| - Statement statement,
|
| - BuilderContext<Statement> context) {
|
| - if (context.removeUsedLabel(label)) {
|
| - context.addStatement(new LabeledStatement(label.name, statement));
|
| - } else {
|
| - context.addStatement(statement);
|
| - }
|
| - }
|
| -
|
| - @override
|
| - void visitExpressionStatement(tree.ExpressionStatement stmt,
|
| - BuilderContext<Statement> context) {
|
| - if (stmt.expression is tree.Assign) {
|
| - emitAssignStatement(stmt.expression, stmt, context);
|
| - return;
|
| - }
|
| - Expression e = visitExpression(stmt.expression, context);
|
| - context.addStatement(new ExpressionStatement(e));
|
| - visitStatement(stmt.next, context);
|
| - }
|
| -
|
| - @override
|
| - void visitVariableDeclaration(tree.VariableDeclaration node,
|
| - BuilderContext<Statement> context) {
|
| - Expression value = visitExpression(node.value, context);
|
| - String name = context.getVariableName(node.variable);
|
| - VariableDeclaration decl = new VariableDeclaration(name, value)
|
| - ..element = node.variable.element;
|
| - context.declaredVariables.add(node.variable);
|
| - context.addStatement(new VariableDeclarations([decl]));
|
| - visitStatement(node.next, context);
|
| - }
|
| -
|
| - @override
|
| - void visitLabeledStatement(tree.LabeledStatement stmt,
|
| - BuilderContext<Statement> context) {
|
| - Block block = visitInSubContext(stmt.body, context, fallthrough: stmt.next);
|
| - addLabeledStatement(stmt.label, block, context);
|
| -
|
| - visitStatement(stmt.next, context);
|
| - }
|
| -
|
| - bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull;
|
| -
|
| - void emitAssignStatement(tree.Assign assign,
|
| - tree.Statement statement,
|
| - BuilderContext<Statement> context) {
|
| - // 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 (assign.variable.element is FunctionElement &&
|
| - assign.value is tree.FunctionExpression &&
|
| - !context.declaredVariables.contains(assign.variable) &&
|
| - assign.variable.writeCount == 1) {
|
| - tree.FunctionExpression functionExp = assign.value;
|
| - FunctionExpression function =
|
| - makeSubFunction(functionExp.definition, context);
|
| - FunctionDeclaration decl = new FunctionDeclaration(function);
|
| - context.addStatement(decl);
|
| - context.declaredVariables.add(assign.variable);
|
| -
|
| - visitStatement(statement.next, context);
|
| - return;
|
| - }
|
| -
|
| - Expression definition = visitExpression(assign.value, context);
|
| - bool isFirstOccurrence = (context.variableNames[assign.variable] == null);
|
| - bool isDeclaredHere = assign.variable.host == context.currentElement;
|
| - bool isFirstStatement = context.firstStatement == statement;
|
| -
|
| - // Try to pull into initializer.
|
| - if (isFirstStatement && isFirstOccurrence && isDeclaredHere) {
|
| - if (isNullLiteral(definition)) definition = null;
|
| - context.addDeclaration(assign.variable, definition);
|
| - context.firstStatement = statement.next;
|
| - visitStatement(statement.next, context);
|
| - return;
|
| - }
|
| -
|
| - context.addStatement(new ExpressionStatement(makeAssignment(
|
| - context.makeVariableAccess(assign.variable),
|
| - definition)));
|
| - visitStatement(statement.next, context);
|
| - }
|
| -
|
| - @override
|
| - void visitReturn(tree.Return stmt, BuilderContext<Statement> context) {
|
| - if (context.currentElement.isGenerativeConstructor &&
|
| - !context.inInitializer) {
|
| - assert(() {
|
| - tree.Expression value = stmt.value;
|
| - return value is tree.Constant && value.value.isNull;
|
| - });
|
| - context.addStatement(new Return(null));
|
| - } else {
|
| - Expression inner = visitExpression(stmt.value, context);
|
| - context.addStatement(new Return(inner));
|
| - }
|
| - }
|
| -
|
| - @override
|
| - void visitThrow(tree.Throw stmt, BuilderContext<Statement> context) {
|
| - Expression value = visitExpression(stmt.value, context);
|
| - context.addStatement(new ExpressionStatement(new Throw(value)));
|
| - }
|
| -
|
| - @override
|
| - void visitRethrow(tree.Rethrow stmt, BuilderContext<Statement> context) {
|
| - context.addStatement(new Rethrow());
|
| - }
|
| -
|
| - @override
|
| - void visitBreak(tree.Break stmt, BuilderContext<Statement> context) {
|
| - tree.Statement fall = context.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 {
|
| - context.useLabel(stmt.target);
|
| - context.addStatement(new Break(stmt.target.name));
|
| - }
|
| - }
|
| -
|
| - @override
|
| - void visitContinue(tree.Continue stmt,
|
| - BuilderContext<Statement> context) {
|
| - tree.Statement fall = context.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 {
|
| - context.useLabel(stmt.target);
|
| - context.addStatement(new Continue(stmt.target.name));
|
| - }
|
| - }
|
| -
|
| - @override
|
| - void visitIf(tree.If stmt,
|
| - BuilderContext<Statement> context) {
|
| - Expression condition = visitExpression(stmt.condition, context);
|
| - Block thenBlock = visitInSubContext(stmt.thenStatement, context);
|
| - Block elseBlock= visitInSubContext(stmt.elseStatement, context);
|
| - context.addStatement(new If(condition, thenBlock, elseBlock));
|
| - }
|
| -
|
| - @override
|
| - void visitWhileTrue(tree.WhileTrue stmt,
|
| - BuilderContext<Statement> context) {
|
| - Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
|
| - Statement statement =
|
| - new While(new Literal(new TrueConstantValue()), body);
|
| - addLabeledStatement(stmt.label, statement, context);
|
| - }
|
| -
|
| - @override
|
| - void visitWhileCondition(tree.WhileCondition stmt,
|
| - BuilderContext<Statement> context) {
|
| - Expression condition = visitExpression(stmt.condition, context);
|
| - Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
|
| - Statement statement = new While(condition, body);
|
| - addLabeledStatement(stmt.label, statement, context);
|
| -
|
| - visitStatement(stmt.next, context);
|
| - }
|
| -
|
| - @override
|
| - void visitTry(tree.Try stmt,
|
| - BuilderContext<Statement> context) {
|
| - Block tryBody = visitInSubContext(stmt.tryBody, context);
|
| - Block catchBody = visitInSubContext(stmt.catchBody, context);
|
| - CatchBlock catchBlock;
|
| - tree.Variable exceptionVariable = stmt.catchParameters[0];
|
| - context.handlerVariables.add(exceptionVariable);
|
| - VariableDeclaration exceptionParameter =
|
| - new VariableDeclaration(context.getVariableName(exceptionVariable));
|
| - exceptionParameter.element = exceptionVariable.element;
|
| - stmt.catchParameters.forEach(context.declaredVariables.add);
|
| - if (stmt.catchParameters.length == 2) {
|
| - tree.Variable stackTraceVariable = stmt.catchParameters[1];
|
| - context.handlerVariables.add(stackTraceVariable);
|
| - VariableDeclaration stackTraceParameter =
|
| - new VariableDeclaration(context.getVariableName(stackTraceVariable));
|
| - stackTraceParameter.element = stackTraceVariable.element;
|
| - catchBlock = new CatchBlock(catchBody,
|
| - exceptionVar: exceptionParameter,
|
| - stackVar: stackTraceParameter);
|
| - } else {
|
| - assert(stmt.catchParameters.length == 1);
|
| - catchBlock = new CatchBlock(catchBody,
|
| - exceptionVar: exceptionParameter);
|
| - }
|
| - context.addStatement(new Try(tryBody, <CatchBlock>[catchBlock], null));
|
| - }
|
| -
|
| - @override
|
| - Expression visitConstant(tree.Constant exp,
|
| - BuilderContext<Statement> context) {
|
| - return ConstantEmitter.createExpression(exp.expression, context);
|
| - }
|
| -
|
| - @override
|
| - Expression visitThis(tree.This exp,
|
| - BuilderContext<Statement> context) {
|
| - return new This();
|
| - }
|
| -
|
| - @override
|
| - Expression visitReifyTypeVar(tree.ReifyTypeVar exp,
|
| - BuilderContext<Statement> context) {
|
| - return new ReifyTypeVar(exp.typeVariable.name)
|
| - ..element = exp.typeVariable;
|
| - }
|
| -
|
| - List<Expression> visitExpressions(List<tree.Expression> expressions,
|
| - BuilderContext<Statement> context) {
|
| - return expressions.map((expression) => visitExpression(expression, context))
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - @override
|
| - Expression visitLiteralList(tree.LiteralList exp,
|
| - BuilderContext<Statement> context) {
|
| - return new LiteralList(visitExpressions(exp.values, context),
|
| - typeArgument:
|
| - TypeGenerator.createOptionalType(exp.type.typeArguments.single));
|
| - }
|
| -
|
| - @override
|
| - Expression visitLiteralMap(tree.LiteralMap exp,
|
| - BuilderContext<Statement> context) {
|
| - List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
|
| - exp.entries.length,
|
| - (i) => new LiteralMapEntry(
|
| - visitExpression(exp.entries[i].key, context),
|
| - visitExpression(exp.entries[i].value, context)));
|
| - List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
|
| - ? null
|
| - : exp.type.typeArguments.map(TypeGenerator.createType)
|
| - .toList(growable: false);
|
| - return new LiteralMap(entries, typeArguments: typeArguments);
|
| - }
|
| -
|
| - @override
|
| - Expression visitTypeOperator(tree.TypeOperator exp,
|
| - BuilderContext<Statement> context) {
|
| - return new TypeOperator(visitExpression(exp.value, context),
|
| - exp.operator,
|
| - TypeGenerator.createType(exp.type));
|
| - }
|
| -
|
| - List<Argument> emitArguments(List<Expression> arguments,
|
| - Selector selector) {
|
| - int positionalArgumentCount = selector.positionalArgumentCount;
|
| - List<Argument> result = new List<Argument>.generate(positionalArgumentCount,
|
| - (i) => arguments[i]);
|
| - for (int i = 0; i < selector.namedArgumentCount; ++i) {
|
| - result.add(new NamedArgument(selector.namedArguments[i],
|
| - arguments[positionalArgumentCount + i]));
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - List<Expression> visitArgumentList(List<tree.Expression> arguments,
|
| - BuilderContext context) {
|
| - return arguments
|
| - .map((tree.Expression argument) => visitExpression(argument, context))
|
| - .toList();
|
| - }
|
| -
|
| - @override
|
| - Expression visitInvokeStatic(tree.InvokeStatic exp,
|
| - BuilderContext<Statement> context) {
|
| - 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], context));
|
| -
|
| - case SelectorKind.CALL:
|
| - return new CallStatic(
|
| - null, exp.target.name,
|
| - emitArguments(visitArgumentList(exp.arguments, context),
|
| - exp.selector))
|
| - ..element = exp.target;
|
| -
|
| - default:
|
| - throw "Unexpected selector kind: ${exp.selector.kind}";
|
| - }
|
| - }
|
| -
|
| - Expression emitMethodCall(tree.Invoke exp, Receiver receiver,
|
| - BuilderContext<Statement> context) {
|
| - List<Argument> args =
|
| - emitArguments(visitArgumentList(exp.arguments, context), exp.selector);
|
| - 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}";
|
| - }
|
| - }
|
| -
|
| - @override
|
| - Expression visitInvokeMethod(tree.InvokeMethod exp,
|
| - BuilderContext<Statement> context) {
|
| - Expression receiver = visitExpression(exp.receiver, context);
|
| - return emitMethodCall(exp, receiver, context);
|
| - }
|
| -
|
| - @override
|
| - Expression visitInvokeMethodDirectly(tree.InvokeMethodDirectly exp,
|
| - BuilderContext<Statement> context) {
|
| - // When targeting Dart, InvokeMethodDirectly is only used for super calls.
|
| - // The receiver is known to be `this`, and the target method is a method
|
| - // on the super class. So we just translate it as a method call with the
|
| - // super receiver.
|
| - return emitMethodCall(exp, new SuperReceiver(), context);
|
| - }
|
| -
|
| - @override
|
| - Expression visitInvokeConstructor(tree.InvokeConstructor exp,
|
| - BuilderContext<Statement> context) {
|
| - List<Argument> args =
|
| - emitArguments(visitArgumentList(exp.arguments, context), exp.selector);
|
| - FunctionElement constructor = exp.target;
|
| - String name = constructor.name.isEmpty ? null : constructor.name;
|
| - return new CallNew(TypeGenerator.createType(exp.type),
|
| - args,
|
| - constructorName: name,
|
| - isConst: exp.constant != null)
|
| - ..constructor = constructor
|
| - ..dartType = exp.type;
|
| - }
|
| -
|
| - @override
|
| - Expression visitConcatenateStrings(tree.ConcatenateStrings exp,
|
| - BuilderContext<Statement> context) {
|
| - return new StringConcat(visitExpressions(exp.arguments, context));
|
| - }
|
| -
|
| - @override
|
| - Expression visitConditional(tree.Conditional exp,
|
| - BuilderContext<Statement> context) {
|
| - return new Conditional(
|
| - visitExpression(exp.condition, context),
|
| - visitExpression(exp.thenExpression, context),
|
| - visitExpression(exp.elseExpression, context));
|
| - }
|
| -
|
| - @override
|
| - Expression visitLogicalOperator(tree.LogicalOperator exp,
|
| - BuilderContext<Statement> context) {
|
| - return new BinaryOperator(visitExpression(exp.left, context),
|
| - exp.operator,
|
| - visitExpression(exp.right, context));
|
| - }
|
| -
|
| - @override
|
| - Expression visitNot(tree.Not exp,
|
| - BuilderContext<Statement> context) {
|
| - return new UnaryOperator('!', visitExpression(exp.operand, context));
|
| - }
|
| -
|
| - @override
|
| - Expression visitVariableUse(tree.VariableUse exp,
|
| - BuilderContext<Statement> context) {
|
| - return context.makeVariableAccess(exp.variable);
|
| - }
|
| -
|
| - @override
|
| - Expression visitAssign(tree.Assign node, BuilderContext<Statement> context) {
|
| - // This is called only when an assignment occurs in expression context.
|
| - return makeAssignment(
|
| - context.makeVariableAccess(node.variable),
|
| - visitExpression(node.value, context));
|
| - }
|
| -
|
| - FunctionExpression makeSubFunction(tree.FunctionDefinition function,
|
| - BuilderContext<Statement> context) {
|
| - return visitFunctionDefinition(function,
|
| - new BuilderContext<Statement>.inner(context));
|
| - }
|
| -
|
| - @override
|
| - Expression visitFunctionExpression(tree.FunctionExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return makeSubFunction(exp.definition, context)..name = null;
|
| - }
|
| -
|
| - @override
|
| - void visitFunctionDeclaration(tree.FunctionDeclaration node,
|
| - BuilderContext<Statement> context) {
|
| - assert(context.variableNames[node.variable] == null);
|
| - String name = context.getVariableName(node.variable);
|
| - FunctionExpression inner = makeSubFunction(node.definition, context);
|
| - inner.name = name;
|
| - FunctionDeclaration decl = new FunctionDeclaration(inner);
|
| - context.declaredVariables.add(node.variable);
|
| - context.addStatement(decl);
|
| - visitStatement(node.next, context);
|
| - }
|
| -
|
| - List<Statement> buildInInitializerContext(tree.Statement root,
|
| - BuilderContext context) {
|
| - BuilderContext inner = new BuilderContext<Statement>.initializer(context);
|
| - inner.currentElement = context.currentElement;
|
| - inner.firstStatement = root;
|
| - visitStatement(root, inner);
|
| - List<Statement> bodyParts;
|
| - for (tree.Variable variable in inner.variableNames.keys) {
|
| - if (!context.declaredVariables.contains(variable) &&
|
| - !inner.declaredVariables.contains(variable)) {
|
| - inner.addDeclaration(variable);
|
| - }
|
| - }
|
| - if (inner.variables.length > 0) {
|
| - bodyParts = new List<Statement>();
|
| - bodyParts.add(new VariableDeclarations(inner.variables));
|
| - bodyParts.addAll(inner.statements);
|
| - } else {
|
| - bodyParts = inner.statements;
|
| - }
|
| - return bodyParts;
|
| - }
|
| -
|
| - @override
|
| - Initializer visitFieldInitializer(tree.FieldInitializer node,
|
| - BuilderContext<Statement> context) {
|
| - return new FieldInitializer(node.element,
|
| - ensureExpression(buildInInitializerContext(node.body, context)));
|
| - }
|
| -
|
| - @override
|
| - Initializer visitSuperInitializer(tree.SuperInitializer node,
|
| - BuilderContext<Statement> context) {
|
| - List<Argument> arguments = node.arguments.map((tree.Statement argument) {
|
| - return ensureExpression(buildInInitializerContext(argument, context));
|
| - }).toList();
|
| - return new SuperInitializer(node.target,
|
| - emitArguments(arguments, node.selector));
|
| - }
|
| -
|
| - @override
|
| - Expression visitGetStatic(tree.GetStatic node,
|
| - BuilderContext<Statement> context) {
|
| - return new Identifier(node.element.name)..element = node.element;
|
| - }
|
| -
|
| - @override
|
| - Expression visitSetStatic(tree.SetStatic node,
|
| - BuilderContext<Statement> context) {
|
| - Expression target =
|
| - new Identifier(node.element.name)..element = node.element;
|
| - Expression value = visitExpression(node.value, context);
|
| - return makeAssignment(target, value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitTypeExpression(tree.TypeExpression node, arg) {
|
| - throw '$node not supported by dart backend';
|
| - }
|
| -
|
| - @override
|
| - visitGetField(tree.GetField node, arg) => errorUnsupportedNode(node);
|
| -
|
| - @override
|
| - visitSetField(tree.SetField node, arg) => errorUnsupportedNode(node);
|
| -
|
| - @override
|
| - visitCreateBox(tree.CreateBox node, arg) => errorUnsupportedNode(node);
|
| -
|
| - @override
|
| - visitCreateInstance(tree.CreateInstance node, arg) {
|
| - return errorUnsupportedNode(node);
|
| - }
|
| -
|
| - @override
|
| - visitCreateInvocationMirror(tree.CreateInvocationMirror node, arg) {
|
| - return errorUnsupportedNode(node);
|
| - }
|
| -
|
| - @override
|
| - Expression visitReadTypeVariable(tree.ReadTypeVariable node, arg) {
|
| - return errorUnsupportedNode(node);
|
| - }
|
| -
|
| - @override
|
| - Expression visitReifyRuntimeType(tree.ReifyRuntimeType node, arg) {
|
| - return errorUnsupportedNode(node);
|
| - }
|
| -
|
| - errorUnsupportedNode(tree.JsSpecificNode node) {
|
| - throw '$node not supported by dart backend';
|
| - }
|
| -
|
| -}
|
|
|
| class TypeGenerator {
|
|
|
| @@ -1029,10 +14,8 @@ class TypeGenerator {
|
| static int pseudoNameCounter = 0;
|
|
|
| static Parameter emitParameter(DartType type,
|
| - BuilderContext<Statement> context,
|
| {String name,
|
| - Element element,
|
| - ConstantExpression defaultValue}) {
|
| + Element element}) {
|
| if (name == null && element != null) {
|
| name = element.name;
|
| }
|
| @@ -1051,10 +34,6 @@ class TypeGenerator {
|
| parameter = new Parameter(name, type: typeAnnotation);
|
| }
|
| parameter.element = element;
|
| - if (defaultValue != null && !defaultValue.value.isNull) {
|
| - parameter.defaultValue =
|
| - ConstantEmitter.createExpression(defaultValue, context);
|
| - }
|
| return parameter;
|
| }
|
|
|
| @@ -1076,20 +55,15 @@ class TypeGenerator {
|
|
|
| static List<Parameter> createParameters(
|
| Iterable<DartType> parameterTypes,
|
| - {BuilderContext<Statement> context,
|
| - Iterable<String> names: const <String>[],
|
| - Iterable<ConstantExpression> defaultValues: const <ConstantExpression>[],
|
| + {Iterable<String> names: const <String>[],
|
| 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, context,
|
| + return emitParameter(type,
|
| name: name.current,
|
| - defaultValue: defaultValue.current,
|
| element: element.current);
|
| }).toList();
|
| }
|
| @@ -1129,323 +103,4 @@ class TypeGenerator {
|
| throw "Unsupported type annotation: $type";
|
| }
|
| }
|
| -
|
| -}
|
| -
|
| -
|
| -class ConstantEmitter
|
| - extends ConstantExpressionVisitor<Expression, BuilderContext<Statement>> {
|
| - const ConstantEmitter();
|
| -
|
| - /// Creates the [Expression] for the constant [exp].
|
| - static Expression createExpression(ConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return const ConstantEmitter().visit(exp, context);
|
| - }
|
| -
|
| - 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);
|
| - }
|
| -
|
| - List<Expression> visitExpressions(List<ConstantExpression> expressions,
|
| - BuilderContext<Statement> context) {
|
| - return expressions.map((expression) => visit(expression, context))
|
| - .toList(growable: false);
|
| - }
|
| -
|
| - @override
|
| - Expression visitBool(BoolConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitInt(IntConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitDouble(DoubleConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitString(StringConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitNull(NullConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - 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,
|
| - BuilderContext<Statement> context) {
|
| - return new LiteralList(
|
| - visitExpressions(exp.values, context),
|
| - isConst: true,
|
| - typeArgument:
|
| - TypeGenerator.createOptionalType(exp.type.typeArguments.single));
|
| - }
|
| -
|
| - @override
|
| - Expression visitMap(MapConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
|
| - exp.values.length,
|
| - (i) => new LiteralMapEntry(visit(exp.keys[i], context),
|
| - visit(exp.values[i], context)));
|
| - List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
|
| - ? null
|
| - : exp.type.typeArguments.map(TypeGenerator.createType).toList();
|
| - return new LiteralMap(entries, isConst: true, typeArguments: typeArguments);
|
| - }
|
| -
|
| - @override
|
| - Expression visitConstructed(ConstructedConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - int positionalArgumentCount = exp.callStructure.positionalArgumentCount;
|
| - List<Argument> args = new List<Argument>.generate(
|
| - positionalArgumentCount,
|
| - (i) => visit(exp.arguments[i], context));
|
| - for (int i = 0; i < exp.callStructure.namedArgumentCount; ++i) {
|
| - args.add(new NamedArgument(exp.callStructure.namedArguments[i],
|
| - visit(exp.arguments[positionalArgumentCount + i], context)));
|
| - }
|
| -
|
| - FunctionElement constructor = exp.target;
|
| - String name = constructor.name.isEmpty ? null : constructor.name;
|
| - return new CallNew(TypeGenerator.createType(exp.type),
|
| - args,
|
| - constructorName: name,
|
| - isConst: true)
|
| - ..constructor = constructor
|
| - ..dartType = exp.type;
|
| - }
|
| -
|
| - @override
|
| - Expression visitConcatenate(ConcatenateConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| -
|
| - return new StringConcat(visitExpressions(exp.expressions, context));
|
| - }
|
| -
|
| - @override
|
| - Expression visitSymbol(SymbolConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return new LiteralSymbol(exp.name);
|
| - }
|
| -
|
| - @override
|
| - Expression visitType(TypeConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - DartType type = exp.type;
|
| - return new LiteralType(type.name)
|
| - ..type = type;
|
| - }
|
| -
|
| - @override
|
| - Expression visitVariable(VariableConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - Element element = exp.element;
|
| - if (element.kind != ElementKind.VARIABLE) {
|
| - return new Identifier(element.name)..element = element;
|
| - }
|
| - String name = context.getConstantName(element);
|
| - return new Identifier(name)
|
| - ..element = element;
|
| - }
|
| -
|
| - @override
|
| - Expression visitFunction(FunctionConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return new Identifier(exp.element.name)
|
| - ..element = exp.element;
|
| - }
|
| -
|
| - @override
|
| - Expression visitBinary(BinaryConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitIdentical(IdenticalConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitConditional(ConditionalConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - if (exp.condition.value.isTrue) {
|
| - return exp.trueExp.accept(this);
|
| - } else {
|
| - return exp.falseExp.accept(this);
|
| - }
|
| - }
|
| -
|
| - @override
|
| - Expression visitUnary(UnaryConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitNamed(NamedArgumentReference exp,
|
| - BuilderContext<Statement> context) {
|
| - throw new UnsupportedError("ConstantEmitter.visitNamed");
|
| - }
|
| -
|
| - @override
|
| - Expression visitPositional(PositionalArgumentReference exp,
|
| - BuilderContext<Statement> context) {
|
| - throw new UnsupportedError("ConstantEmitter.visitPositional");
|
| - }
|
| -
|
| - @override
|
| - Expression visitBoolFromEnvironment(
|
| - BoolFromEnvironmentConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitIntFromEnvironment(
|
| - IntFromEnvironmentConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitStringFromEnvironment(
|
| - StringFromEnvironmentConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return handlePrimitiveConstant(exp.value);
|
| - }
|
| -
|
| - @override
|
| - Expression visitDeferred(DeferredConstantExpression exp,
|
| - BuilderContext<Statement> context) {
|
| - return exp.expression.accept(this);
|
| - }
|
| -}
|
| -
|
| -/// 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.RootNode definition) {
|
| - if (definition.isEmpty) return;
|
| - unshadowFunction(definition);
|
| - }
|
| -
|
| - void unshadowFunction(tree.RootNode 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;
|
| - }
|
| - definition.forEachBody(visitStatement);
|
| - 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.element,
|
| - param.element);
|
| - definition.parameters[i] = newParam;
|
| - definition.replaceEachBody((tree.Statement body) {
|
| - return tree.Assign.makeStatement(
|
| - param,
|
| - new tree.VariableUse(newParam),
|
| - body);
|
| - });
|
| - newParam.writeCount = 1; // Being a parameter counts as a write.
|
| - param.writeCount--; // Not a parameter anymore.
|
| - }
|
| - }
|
| - }
|
| -
|
| - @override
|
| - void visitInnerFunction(tree.FunctionDefinition definition) {
|
| - unshadowFunction(definition);
|
| - }
|
| -
|
| - @override
|
| - 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;
|
| }
|
|
|