| // 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 tree_ir_nodes; |
| |
| import '../constants/expressions.dart'; |
| import '../constants/values.dart' as values; |
| import '../dart_types.dart' show DartType, GenericType; |
| import '../elements/elements.dart'; |
| import '../universe/universe.dart'; |
| import '../universe/universe.dart' show Selector; |
| import 'optimization/optimization.dart'; |
| |
| // The Tree language is the target of translation out of the CPS-based IR. |
| // |
| // The translation from CPS to Dart consists of several stages. Among the |
| // stages are translation to direct style, translation out of SSA, eliminating |
| // unnecessary names, recognizing high-level control constructs. Combining |
| // these separate concerns is complicated and the constraints of the CPS-based |
| // language do not permit a multi-stage translation. |
| // |
| // For that reason, CPS is translated to the direct-style language Tree. |
| // Translation out of SSA, unnaming, and control-flow, as well as 'instruction |
| // selection' are performed on the Tree language. |
| // |
| // In contrast to the CPS-based IR, non-primitive expressions can be named and |
| // arguments (to calls, primitives, and blocks) can be arbitrary expressions. |
| // |
| // Additionally, variables are considered in scope within inner functions; |
| // closure variables are thus handled directly instead of using ref cells. |
| |
| /** |
| * The base class of all Tree nodes. |
| */ |
| abstract class Node { |
| } |
| |
| /** |
| * The base class of [Expression]s. |
| */ |
| abstract class Expression extends Node { |
| accept(ExpressionVisitor v); |
| accept1(ExpressionVisitor1 v, arg); |
| |
| /// Temporary variable used by [StatementRewriter]. |
| /// If set to true, this expression has already had enclosing assignments |
| /// propagated into its variables, and should not be processed again. |
| /// It is only set for expressions that are known to be in risk of redundant |
| /// processing. |
| bool processed = false; |
| } |
| |
| abstract class Statement extends Node { |
| Statement get next; |
| void set next(Statement s); |
| accept(StatementVisitor v); |
| accept1(StatementVisitor1 v, arg); |
| } |
| |
| /** |
| * Labels name [LabeledStatement]s. |
| */ |
| class Label { |
| // A counter used to generate names. The counter is reset to 0 for each |
| // function emitted. |
| static int counter = 0; |
| static String _newName() => 'L${counter++}'; |
| |
| String cachedName; |
| |
| String get name { |
| if (cachedName == null) cachedName = _newName(); |
| return cachedName; |
| } |
| |
| /// Number of [Break] or [Continue] statements that target this label. |
| /// The [Break] constructor will increment this automatically, but the |
| /// counter must be decremented by hand when a [Break] becomes orphaned. |
| int useCount = 0; |
| |
| /// The [LabeledStatement] or [WhileTrue] binding this label. |
| JumpTarget binding; |
| } |
| |
| /** |
| * Variables are [Expression]s. |
| */ |
| class Variable extends Expression { |
| /// Function that declares this variable. |
| ExecutableElement host; |
| |
| /// [Entity] used for synthesizing a name for the variable. |
| /// Different variables may have the same entity. May be null. |
| Entity element; |
| |
| int readCount = 0; |
| |
| /// Number of places where this variable occurs as: |
| /// - left-hand of an [Assign] |
| /// - left-hand of a [FunctionDeclaration] |
| /// - parameter in a [FunctionDefinition] |
| int writeCount = 0; |
| |
| Variable(this.host, this.element) { |
| assert(host != null); |
| } |
| |
| accept(ExpressionVisitor visitor) => visitor.visitVariable(this); |
| accept1(ExpressionVisitor1 visitor, arg) => visitor.visitVariable(this, arg); |
| } |
| |
| /** |
| * Common interface for invocations with arguments. |
| */ |
| abstract class Invoke { |
| List<Expression> get arguments; |
| Selector get selector; |
| } |
| |
| /** |
| * A call to a static function or getter/setter to a static field. |
| * |
| * In contrast to the CPS-based IR, the arguments can be arbitrary expressions. |
| */ |
| class InvokeStatic extends Expression implements Invoke { |
| final Entity target; |
| final List<Expression> arguments; |
| final Selector selector; |
| |
| InvokeStatic(this.target, this.selector, this.arguments); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitInvokeStatic(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitInvokeStatic(this, arg); |
| } |
| } |
| |
| /** |
| * A call to a method, operator, getter, setter or index getter/setter. |
| * |
| * In contrast to the CPS-based IR, the receiver and arguments can be |
| * arbitrary expressions. |
| */ |
| class InvokeMethod extends Expression implements Invoke { |
| Expression receiver; |
| final Selector selector; |
| final List<Expression> arguments; |
| |
| InvokeMethod(this.receiver, this.selector, this.arguments) { |
| assert(receiver != null); |
| } |
| |
| accept(ExpressionVisitor visitor) => visitor.visitInvokeMethod(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitInvokeMethod(this, arg); |
| } |
| } |
| |
| /// Invoke [target] on [receiver], bypassing ordinary dispatch semantics. |
| class InvokeMethodDirectly extends Expression implements Invoke { |
| Expression receiver; |
| final Element target; |
| final Selector selector; |
| final List<Expression> arguments; |
| |
| InvokeMethodDirectly(this.receiver, this.target, this.selector, |
| this.arguments); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitInvokeMethodDirectly(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitInvokeMethodDirectly(this, arg); |
| } |
| } |
| |
| /** |
| * Call to a factory or generative constructor. |
| */ |
| class InvokeConstructor extends Expression implements Invoke { |
| final DartType type; |
| final FunctionElement target; |
| final List<Expression> arguments; |
| final Selector selector; |
| /// TODO(karlklose): get rid of this field. Instead use the constant's |
| /// expression to find the constructor to be called in dart2dart. |
| final values.ConstantValue constant; |
| |
| InvokeConstructor(this.type, this.target, this.selector, this.arguments, |
| [this.constant]); |
| |
| ClassElement get targetClass => target.enclosingElement; |
| |
| accept(ExpressionVisitor visitor) => visitor.visitInvokeConstructor(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitInvokeConstructor(this, arg); |
| } |
| } |
| |
| /// Calls [toString] on each argument and concatenates the results. |
| class ConcatenateStrings extends Expression { |
| final List<Expression> arguments; |
| |
| ConcatenateStrings(this.arguments); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitConcatenateStrings(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitConcatenateStrings(this, arg); |
| } |
| } |
| |
| /** |
| * A constant. |
| */ |
| class Constant extends Expression { |
| final ConstantExpression expression; |
| |
| Constant(this.expression); |
| |
| Constant.primitive(values.PrimitiveConstantValue primitiveValue) |
| : expression = new PrimitiveConstantExpression(primitiveValue); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitConstant(this); |
| accept1(ExpressionVisitor1 visitor, arg) => visitor.visitConstant(this, arg); |
| |
| values.ConstantValue get value => expression.value; |
| } |
| |
| class This extends Expression { |
| accept(ExpressionVisitor visitor) => visitor.visitThis(this); |
| accept1(ExpressionVisitor1 visitor, arg) => visitor.visitThis(this, arg); |
| } |
| |
| class ReifyTypeVar extends Expression { |
| TypeVariableElement typeVariable; |
| |
| ReifyTypeVar(this.typeVariable); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitReifyTypeVar(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitReifyTypeVar(this, arg); |
| } |
| } |
| |
| class LiteralList extends Expression { |
| final GenericType type; |
| final List<Expression> values; |
| |
| LiteralList(this.type, this.values); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitLiteralList(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitLiteralList(this, arg); |
| } |
| } |
| |
| class LiteralMapEntry { |
| Expression key; |
| Expression value; |
| |
| LiteralMapEntry(this.key, this.value); |
| } |
| |
| class LiteralMap extends Expression { |
| final GenericType type; |
| final List<LiteralMapEntry> entries; |
| |
| LiteralMap(this.type, this.entries); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitLiteralMap(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitLiteralMap(this, arg); |
| } |
| } |
| |
| class TypeOperator extends Expression { |
| Expression receiver; |
| final DartType type; |
| final bool isTypeTest; |
| |
| TypeOperator(this.receiver, this.type, {bool this.isTypeTest}); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitTypeOperator(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitTypeOperator(this, arg); |
| } |
| |
| String get operator => isTypeTest ? 'is' : 'as'; |
| } |
| |
| /// A conditional expression. |
| class Conditional extends Expression { |
| Expression condition; |
| Expression thenExpression; |
| Expression elseExpression; |
| |
| Conditional(this.condition, this.thenExpression, this.elseExpression); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitConditional(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitConditional(this, arg); |
| } |
| } |
| |
| /// An && or || expression. The operator is internally represented as a boolean |
| /// [isAnd] to simplify rewriting of logical operators. |
| class LogicalOperator extends Expression { |
| Expression left; |
| bool isAnd; |
| Expression right; |
| |
| LogicalOperator(this.left, this.right, this.isAnd); |
| LogicalOperator.and(this.left, this.right) : isAnd = true; |
| LogicalOperator.or(this.left, this.right) : isAnd = false; |
| |
| String get operator => isAnd ? '&&' : '||'; |
| |
| accept(ExpressionVisitor visitor) => visitor.visitLogicalOperator(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitLogicalOperator(this, arg); |
| } |
| } |
| |
| /// Logical negation. |
| class Not extends Expression { |
| Expression operand; |
| |
| Not(this.operand); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitNot(this); |
| accept1(ExpressionVisitor1 visitor, arg) => visitor.visitNot(this, arg); |
| } |
| |
| class FunctionExpression extends Expression { |
| final FunctionDefinition definition; |
| |
| FunctionExpression(this.definition) { |
| assert(definition.element.type.returnType.treatAsDynamic); |
| } |
| |
| accept(ExpressionVisitor visitor) => visitor.visitFunctionExpression(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitFunctionExpression(this, arg); |
| } |
| } |
| |
| /// Declares a local function. |
| /// Used for functions that may not occur in expression context due to |
| /// being recursive or having a return type. |
| /// The [variable] must not occur as the left-hand side of an [Assign] or |
| /// any other [FunctionDeclaration]. |
| class FunctionDeclaration extends Statement { |
| Variable variable; |
| final FunctionDefinition definition; |
| Statement next; |
| |
| FunctionDeclaration(this.variable, this.definition, this.next) { |
| ++variable.writeCount; |
| } |
| |
| accept(StatementVisitor visitor) => visitor.visitFunctionDeclaration(this); |
| accept1(StatementVisitor1 visitor, arg) { |
| return visitor.visitFunctionDeclaration(this, arg); |
| } |
| } |
| |
| /// A [LabeledStatement] or [WhileTrue] or [WhileCondition]. |
| abstract class JumpTarget extends Statement { |
| Label get label; |
| Statement get body; |
| } |
| |
| /** |
| * A labeled statement. Breaks to the label within the labeled statement |
| * target the successor statement. |
| */ |
| class LabeledStatement extends JumpTarget { |
| Statement next; |
| final Label label; |
| Statement body; |
| |
| LabeledStatement(this.label, this.body, this.next) { |
| assert(label.binding == null); |
| label.binding = this; |
| } |
| |
| accept(StatementVisitor visitor) => visitor.visitLabeledStatement(this); |
| accept1(StatementVisitor1 visitor, arg) { |
| return visitor.visitLabeledStatement(this, arg); |
| } |
| } |
| |
| /// A [WhileTrue] or [WhileCondition] loop. |
| abstract class Loop extends JumpTarget { |
| } |
| |
| /** |
| * A labeled while(true) loop. |
| */ |
| class WhileTrue extends Loop { |
| final Label label; |
| Statement body; |
| |
| WhileTrue(this.label, this.body) { |
| assert(label.binding == null); |
| label.binding = this; |
| } |
| |
| Statement get next => null; |
| void set next(Statement s) => throw 'UNREACHABLE'; |
| |
| accept(StatementVisitor visitor) => visitor.visitWhileTrue(this); |
| accept1(StatementVisitor1 visitor, arg) => visitor.visitWhileTrue(this, arg); |
| } |
| |
| /** |
| * A while loop with a condition. If the condition is false, control resumes |
| * at the [next] statement. |
| * |
| * It is NOT valid to target this statement with a [Break]. |
| * The only way to reach [next] is for the condition to evaluate to false. |
| * |
| * [WhileCondition] statements are introduced in the [LoopRewriter] and is |
| * assumed not to occur before then. |
| */ |
| class WhileCondition extends Loop { |
| final Label label; |
| Expression condition; |
| Statement body; |
| Statement next; |
| |
| WhileCondition(this.label, this.condition, this.body, |
| this.next) { |
| assert(label.binding == null); |
| label.binding = this; |
| } |
| |
| accept(StatementVisitor visitor) => visitor.visitWhileCondition(this); |
| accept1(StatementVisitor1 visitor, arg) { |
| return visitor.visitWhileCondition(this, arg); |
| } |
| } |
| |
| /// A [Break] or [Continue] statement. |
| abstract class Jump extends Statement { |
| Label get target; |
| } |
| |
| /** |
| * A break from an enclosing [LabeledStatement]. The break targets the |
| * labeled statement's successor statement. |
| */ |
| class Break extends Jump { |
| final Label target; |
| |
| Statement get next => null; |
| void set next(Statement s) => throw 'UNREACHABLE'; |
| |
| Break(this.target) { |
| ++target.useCount; |
| } |
| |
| accept(StatementVisitor visitor) => visitor.visitBreak(this); |
| accept1(StatementVisitor1 visitor, arg) => visitor.visitBreak(this, arg); |
| } |
| |
| /** |
| * A continue to an enclosing [WhileTrue] or [WhileCondition] loop. |
| * The continue targets the loop's body. |
| */ |
| class Continue extends Jump { |
| final Label target; |
| |
| Statement get next => null; |
| void set next(Statement s) => throw 'UNREACHABLE'; |
| |
| Continue(this.target) { |
| ++target.useCount; |
| } |
| |
| accept(StatementVisitor visitor) => visitor.visitContinue(this); |
| accept1(StatementVisitor1 visitor, arg) => visitor.visitContinue(this, arg); |
| } |
| |
| /** |
| * An assignments of an [Expression] to a [Variable]. |
| * |
| * In contrast to the CPS-based IR, non-primitive expressions can be assigned |
| * to variables. |
| */ |
| class Assign extends Statement { |
| Statement next; |
| Variable variable; |
| Expression definition; |
| |
| /// If true, this assignes to a fresh variable scoped to the [next] |
| /// statement. |
| /// |
| /// Variable declarations themselves are hoisted to function level. |
| bool isDeclaration; |
| |
| Assign(this.variable, this.definition, this.next, |
| { this.isDeclaration: false }) { |
| variable.writeCount++; |
| } |
| |
| bool get hasExactlyOneUse => variable.readCount == 1; |
| |
| accept(StatementVisitor visitor) => visitor.visitAssign(this); |
| accept1(StatementVisitor1 visitor, arg) => visitor.visitAssign(this, arg); |
| } |
| |
| /** |
| * A return exit from the function. |
| * |
| * In contrast to the CPS-based IR, the return value is an arbitrary |
| * expression. |
| */ |
| class Return extends Statement { |
| /// Should not be null. Use [Constant] with [NullConstantValue] for void |
| /// returns. |
| /// Even in constructors this holds true. Take special care when translating |
| /// back to dart, where `return null;` in a constructor is an error. |
| Expression value; |
| |
| Statement get next => null; |
| void set next(Statement s) => throw 'UNREACHABLE'; |
| |
| Return(this.value); |
| |
| accept(StatementVisitor visitor) => visitor.visitReturn(this); |
| accept1(StatementVisitor1 visitor, arg) => visitor.visitReturn(this, arg); |
| } |
| |
| /** |
| * A conditional branch based on the true value of an [Expression]. |
| */ |
| class If extends Statement { |
| Expression condition; |
| Statement thenStatement; |
| Statement elseStatement; |
| |
| Statement get next => null; |
| void set next(Statement s) => throw 'UNREACHABLE'; |
| |
| If(this.condition, this.thenStatement, this.elseStatement); |
| |
| accept(StatementVisitor visitor) => visitor.visitIf(this); |
| accept1(StatementVisitor1 visitor, arg) => visitor.visitIf(this, arg); |
| } |
| |
| class ExpressionStatement extends Statement { |
| Statement next; |
| Expression expression; |
| |
| ExpressionStatement(this.expression, this.next); |
| |
| accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this); |
| accept1(StatementVisitor1 visitor, arg) { |
| return visitor.visitExpressionStatement(this, arg); |
| } |
| } |
| |
| abstract class ExecutableDefinition { |
| ExecutableElement get element; |
| Statement body; |
| |
| applyPass(Pass pass); |
| } |
| |
| class FieldDefinition extends Node implements ExecutableDefinition { |
| final FieldElement element; |
| // The `body` of a field is its initializer. |
| Statement body; |
| |
| FieldDefinition(this.element, this.body); |
| applyPass(Pass pass) => pass.rewriteFieldDefinition(this); |
| |
| /// `true` if this field has no initializer. |
| /// |
| /// If `true` [body] is `null`. |
| /// |
| /// This is different from a initializer that is `null`. Consider this class: |
| /// |
| /// class Class { |
| /// final field; |
| /// Class.a(this.field); |
| /// Class.b() : this.field = null; |
| /// Class.c(); |
| /// } |
| /// |
| /// If `field` had an initializer, possibly `null`, constructors `Class.a` and |
| /// `Class.b` would be invalid, and since `field` has no initializer |
| /// constructor `Class.c` is invalid. We therefore need to distinguish the two |
| /// cases. |
| bool get hasInitializer => body != null; |
| } |
| |
| class FunctionDefinition extends Node implements ExecutableDefinition { |
| final FunctionElement element; |
| final List<Variable> parameters; |
| Statement body; |
| final List<ConstDeclaration> localConstants; |
| final List<ConstantExpression> defaultParameterValues; |
| |
| FunctionDefinition(this.element, this.parameters, this.body, |
| this.localConstants, this.defaultParameterValues); |
| |
| /// Returns `true` if this function is abstract. |
| /// |
| /// If `true` [body] is `null` and [localConstants] is empty. |
| bool get isAbstract => body == null; |
| applyPass(Pass pass) => pass.rewriteFunctionDefinition(this); |
| } |
| |
| abstract class Initializer implements Expression {} |
| |
| class FieldInitializer extends Initializer { |
| final FieldElement element; |
| Statement body; |
| bool processed = false; |
| |
| FieldInitializer(this.element, this.body); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitFieldInitializer(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitFieldInitializer(this, arg); |
| } |
| } |
| |
| class SuperInitializer extends Initializer { |
| final ConstructorElement target; |
| final Selector selector; |
| final List<Statement> arguments; |
| bool processed = false; |
| |
| SuperInitializer(this.target, this.selector, this.arguments); |
| accept(ExpressionVisitor visitor) => visitor.visitSuperInitializer(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitSuperInitializer(this, arg); |
| } |
| } |
| |
| class ConstructorDefinition extends FunctionDefinition { |
| final List<Initializer> initializers; |
| |
| ConstructorDefinition(ConstructorElement element, |
| List<Variable> parameters, |
| Statement body, |
| this.initializers, |
| List<ConstDeclaration> localConstants, |
| List<ConstantExpression> defaultParameterValues) |
| : super(element, parameters, body, localConstants, |
| defaultParameterValues); |
| |
| applyPass(Pass pass) => pass.rewriteConstructorDefinition(this); |
| } |
| |
| abstract class JsSpecificNode implements Node {} |
| |
| class CreateBox extends Expression implements JsSpecificNode { |
| accept(ExpressionVisitor visitor) => visitor.visitCreateBox(this); |
| accept1(ExpressionVisitor1 visitor, arg) => visitor.visitCreateBox(this, arg); |
| } |
| |
| class CreateInstance extends Expression implements JsSpecificNode { |
| ClassElement classElement; |
| List<Expression> arguments; |
| |
| CreateInstance(this.classElement, this.arguments); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitCreateInstance(this); |
| accept1(ExpressionVisitor1 visitor, arg) { |
| return visitor.visitCreateInstance(this, arg); |
| } |
| } |
| |
| class GetField extends Expression implements JsSpecificNode { |
| Expression object; |
| Element field; |
| |
| GetField(this.object, this.field); |
| |
| accept(ExpressionVisitor visitor) => visitor.visitGetField(this); |
| accept1(ExpressionVisitor1 visitor, arg) => visitor.visitGetField(this, arg); |
| } |
| |
| class SetField extends Statement implements JsSpecificNode { |
| Expression object; |
| Element field; |
| Expression value; |
| Statement next; |
| |
| SetField(this.object, this.field, this.value, this.next); |
| |
| accept(StatementVisitor visitor) => visitor.visitSetField(this); |
| accept1(StatementVisitor1 visitor, arg) => visitor.visitSetField(this, arg); |
| } |
| |
| abstract class ExpressionVisitor<E> { |
| E visitExpression(Expression e) => e.accept(this); |
| E visitVariable(Variable node); |
| E visitInvokeStatic(InvokeStatic node); |
| E visitInvokeMethod(InvokeMethod node); |
| E visitInvokeMethodDirectly(InvokeMethodDirectly node); |
| E visitInvokeConstructor(InvokeConstructor node); |
| E visitConcatenateStrings(ConcatenateStrings node); |
| E visitConstant(Constant node); |
| E visitThis(This node); |
| E visitReifyTypeVar(ReifyTypeVar node); |
| E visitConditional(Conditional node); |
| E visitLogicalOperator(LogicalOperator node); |
| E visitNot(Not node); |
| E visitLiteralList(LiteralList node); |
| E visitLiteralMap(LiteralMap node); |
| E visitTypeOperator(TypeOperator node); |
| E visitFunctionExpression(FunctionExpression node); |
| E visitFieldInitializer(FieldInitializer node); |
| E visitSuperInitializer(SuperInitializer node); |
| E visitGetField(GetField node); |
| E visitCreateBox(CreateBox node); |
| E visitCreateInstance(CreateInstance node); |
| } |
| |
| abstract class ExpressionVisitor1<E, A> { |
| E visitExpression(Expression e, A arg) => e.accept1(this, arg); |
| E visitVariable(Variable node, A arg); |
| E visitInvokeStatic(InvokeStatic node, A arg); |
| E visitInvokeMethod(InvokeMethod node, A arg); |
| E visitInvokeMethodDirectly(InvokeMethodDirectly node, A arg); |
| E visitInvokeConstructor(InvokeConstructor node, A arg); |
| E visitConcatenateStrings(ConcatenateStrings node, A arg); |
| E visitConstant(Constant node, A arg); |
| E visitThis(This node, A arg); |
| E visitReifyTypeVar(ReifyTypeVar node, A arg); |
| E visitConditional(Conditional node, A arg); |
| E visitLogicalOperator(LogicalOperator node, A arg); |
| E visitNot(Not node, A arg); |
| E visitLiteralList(LiteralList node, A arg); |
| E visitLiteralMap(LiteralMap node, A arg); |
| E visitTypeOperator(TypeOperator node, A arg); |
| E visitFunctionExpression(FunctionExpression node, A arg); |
| E visitFieldInitializer(FieldInitializer node, A arg); |
| E visitSuperInitializer(SuperInitializer node, A arg); |
| E visitGetField(GetField node, A arg); |
| E visitCreateBox(CreateBox node, A arg); |
| E visitCreateInstance(CreateInstance node, A arg); |
| } |
| |
| abstract class StatementVisitor<S> { |
| S visitStatement(Statement s) => s.accept(this); |
| S visitLabeledStatement(LabeledStatement node); |
| S visitAssign(Assign node); |
| S visitReturn(Return node); |
| S visitBreak(Break node); |
| S visitContinue(Continue node); |
| S visitIf(If node); |
| S visitWhileTrue(WhileTrue node); |
| S visitWhileCondition(WhileCondition node); |
| S visitFunctionDeclaration(FunctionDeclaration node); |
| S visitExpressionStatement(ExpressionStatement node); |
| S visitSetField(SetField node); |
| } |
| |
| abstract class StatementVisitor1<S, A> { |
| S visitStatement(Statement s, A arg) => s.accept1(this, arg); |
| S visitLabeledStatement(LabeledStatement node, A arg); |
| S visitAssign(Assign node, A arg); |
| S visitReturn(Return node, A arg); |
| S visitBreak(Break node, A arg); |
| S visitContinue(Continue node, A arg); |
| S visitIf(If node, A arg); |
| S visitWhileTrue(WhileTrue node, A arg); |
| S visitWhileCondition(WhileCondition node, A arg); |
| S visitFunctionDeclaration(FunctionDeclaration node, A arg); |
| S visitExpressionStatement(ExpressionStatement node, A arg); |
| S visitSetField(SetField node, A arg); |
| } |
| |
| abstract class Visitor<S, E> implements ExpressionVisitor<E>, |
| StatementVisitor<S> { |
| E visitExpression(Expression e) => e.accept(this); |
| S visitStatement(Statement s) => s.accept(this); |
| } |
| |
| abstract class Visitor1<S, E, A> implements ExpressionVisitor1<E, A>, |
| StatementVisitor1<S, A> { |
| E visitExpression(Expression e, A arg) => e.accept1(this, arg); |
| S visitStatement(Statement s, A arg) => s.accept1(this, arg); |
| } |
| |
| class RecursiveVisitor extends Visitor { |
| visitFunctionDefinition(FunctionDefinition node) { |
| visitStatement(node.body); |
| } |
| |
| visitVariable(Variable node) {} |
| |
| visitInvokeStatic(InvokeStatic node) { |
| node.arguments.forEach(visitExpression); |
| } |
| |
| visitInvokeMethod(InvokeMethod node) { |
| visitExpression(node.receiver); |
| node.arguments.forEach(visitExpression); |
| } |
| |
| visitInvokeMethodDirectly(InvokeMethodDirectly node) { |
| visitExpression(node.receiver); |
| node.arguments.forEach(visitExpression); |
| } |
| |
| visitInvokeConstructor(InvokeConstructor node) { |
| node.arguments.forEach(visitExpression); |
| } |
| |
| visitConcatenateStrings(ConcatenateStrings node) { |
| node.arguments.forEach(visitExpression); |
| } |
| |
| visitConstant(Constant node) {} |
| |
| visitThis(This node) {} |
| |
| visitReifyTypeVar(ReifyTypeVar node) {} |
| |
| visitConditional(Conditional node) { |
| visitExpression(node.condition); |
| visitExpression(node.thenExpression); |
| visitExpression(node.elseExpression); |
| } |
| |
| visitLogicalOperator(LogicalOperator node) { |
| visitExpression(node.left); |
| visitExpression(node.right); |
| } |
| |
| visitNot(Not node) { |
| visitExpression(node.operand); |
| } |
| |
| visitLiteralList(LiteralList node) { |
| node.values.forEach(visitExpression); |
| } |
| |
| visitLiteralMap(LiteralMap node) { |
| node.entries.forEach((LiteralMapEntry entry) { |
| visitExpression(entry.key); |
| visitExpression(entry.value); |
| }); |
| } |
| |
| visitTypeOperator(TypeOperator node) { |
| visitExpression(node.receiver); |
| } |
| |
| visitFunctionExpression(FunctionExpression node) { |
| visitFunctionDefinition(node.definition); |
| } |
| |
| visitLabeledStatement(LabeledStatement node) { |
| visitStatement(node.body); |
| visitStatement(node.next); |
| } |
| |
| visitAssign(Assign node) { |
| visitExpression(node.definition); |
| visitVariable(node.variable); |
| visitStatement(node.next); |
| } |
| |
| visitReturn(Return node) { |
| visitExpression(node.value); |
| } |
| |
| visitBreak(Break node) {} |
| |
| visitContinue(Continue node) {} |
| |
| visitIf(If node) { |
| visitExpression(node.condition); |
| visitStatement(node.thenStatement); |
| visitStatement(node.elseStatement); |
| } |
| |
| visitWhileTrue(WhileTrue node) { |
| visitStatement(node.body); |
| } |
| |
| visitWhileCondition(WhileCondition node) { |
| visitExpression(node.condition); |
| visitStatement(node.body); |
| visitStatement(node.next); |
| } |
| |
| visitFunctionDeclaration(FunctionDeclaration node) { |
| visitFunctionDefinition(node.definition); |
| visitStatement(node.next); |
| } |
| |
| visitExpressionStatement(ExpressionStatement node) { |
| visitExpression(node.expression); |
| visitStatement(node.next); |
| } |
| |
| visitFieldInitializer(FieldInitializer node) { |
| visitStatement(node.body); |
| } |
| |
| visitSuperInitializer(SuperInitializer node) { |
| node.arguments.forEach(visitStatement); |
| } |
| |
| visitGetField(GetField node) { |
| visitExpression(node.object); |
| } |
| |
| visitSetField(SetField node) { |
| visitExpression(node.object); |
| visitExpression(node.value); |
| visitStatement(node.next); |
| } |
| |
| visitCreateBox(CreateBox node) { |
| } |
| |
| visitCreateInstance(CreateInstance node) { |
| node.arguments.forEach(visitExpression); |
| } |
| } |