diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-10-06 16:24:37 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-10-06 16:24:37 +0100 |
| commit | e6f463257720bee91a1b4954d97684dbb3398cbf (patch) | |
| tree | c8d1f04dfe8928d33361108aefee7e7572dae1c7 /src/main/java/org/zwobble/couscous/ast | |
| parent | 9685c8fb7fa14d5b75d828f8443dd948715ac4af (diff) | |
Add support for constructors and fields
Diffstat (limited to 'src/main/java/org/zwobble/couscous/ast')
17 files changed, 276 insertions, 27 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/AssignableExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/AssignableExpressionNode.java new file mode 100644 index 0000000..eba641f --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/AssignableExpressionNode.java @@ -0,0 +1,7 @@ +package org.zwobble.couscous.ast; + +import org.zwobble.couscous.ast.visitors.AssignableExpressionNodeVisitor; + +public interface AssignableExpressionNode extends ExpressionNode { + void accept(AssignableExpressionNodeVisitor mapper); +} diff --git a/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java b/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java index d7ea09f..483d4c2 100644 --- a/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java +++ b/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java @@ -8,11 +8,23 @@ import lombok.Value; @Value public class AssignmentNode implements ExpressionNode { + public static StatementNode assignStatement(AssignableExpressionNode target, ExpressionNode value) { + return new ExpressionStatementNode(assign(target, value)); + } + + public static AssignmentNode assign(AssignableExpressionNode target, ExpressionNode value) { + return new AssignmentNode(target, value); + } + + public static StatementNode assignStatement(VariableNode target, ExpressionNode value) { + return new ExpressionStatementNode(assign(target, value)); + } + public static AssignmentNode assign(VariableNode target, ExpressionNode value) { return new AssignmentNode(reference(target), value); } - VariableReferenceNode target; + AssignableExpressionNode target; ExpressionNode value; @Override diff --git a/src/main/java/org/zwobble/couscous/ast/CallableNode.java b/src/main/java/org/zwobble/couscous/ast/CallableNode.java new file mode 100644 index 0000000..79d2e84 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/CallableNode.java @@ -0,0 +1,9 @@ +package org.zwobble.couscous.ast; + +import java.util.List; + +public interface CallableNode extends Node { + List<FormalArgumentNode> getArguments(); + List<StatementNode> getBody(); + +} diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java index 5f08d38..280b772 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java @@ -4,37 +4,17 @@ import java.util.List; import org.zwobble.couscous.ast.visitors.NodeVisitor; -import com.google.common.collect.ImmutableList; - import lombok.Singular; import lombok.Value; @Value public class ClassNode implements Node { - public static ClassNode.Builder builder(String name) { - return new Builder(name); - } - - public static class Builder { - private final String name; - private final ImmutableList.Builder<MethodNode> methods; - - public Builder(String name) { - this.name = name; - this.methods = ImmutableList.builder(); - } - - public Builder method(MethodNode method) { - this.methods.add(method); - return this; - } - - public ClassNode build() { - return new ClassNode(TypeName.of(name), methods.build()); - } + public static ClassNodeBuilder builder(String name) { + return new ClassNodeBuilder(name); } TypeName name; + ConstructorNode constructor; @Singular List<MethodNode> methods; diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java new file mode 100644 index 0000000..cd324b9 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java @@ -0,0 +1,103 @@ +package org.zwobble.couscous.ast; + +import java.util.Optional; +import java.util.function.Function; + +import com.google.common.collect.ImmutableList; + +public class ClassNodeBuilder { + private final TypeName name; + private final ImmutableList.Builder<FieldDeclarationNode> fields; + private Optional<ConstructorNode> constructor; + private final ImmutableList.Builder<MethodNode> methods; + + public ClassNodeBuilder(String name) { + this.name = TypeName.of(name); + this.fields = ImmutableList.builder(); + this.constructor = Optional.empty(); + this.methods = ImmutableList.builder(); + } + + public ClassNodeBuilder field(String name, TypeName type) { + this.fields.add(FieldDeclarationNode.field(name, type)); + return this; + } + + public ClassNodeBuilder constructor(Function<ConstructorBuilder, ConstructorBuilder> build) { + this.constructor = Optional.of(build.apply(new ConstructorBuilder()).build()); + return this; + } + + public ClassNodeBuilder method(MethodNode method) { + this.methods.add(method); + return this; + } + + public ClassNodeBuilder method(String name, Function<MethodBuilder, MethodBuilder> build) { + this.methods.add(build.apply(new MethodBuilder(name)).build()); + return this; + } + + public ClassNode build() { + return new ClassNode( + name, + constructor.orElse(new ConstructorBuilder().build()), + methods.build()); + } + + public class ConstructorBuilder { + private final ImmutableList.Builder<FormalArgumentNode> arguments; + private final ImmutableList.Builder<StatementNode> statements; + + public ConstructorBuilder() { + this.arguments = ImmutableList.builder(); + this.statements = ImmutableList.builder(); + } + + public ThisReferenceNode thisReference() { + return ThisReferenceNode.thisReference(name); + } + + public ConstructorBuilder argument(FormalArgumentNode argument) { + arguments.add(argument); + return this; + } + + public ConstructorBuilder statement(StatementNode statement) { + statements.add(statement); + return this; + } + + public ConstructorNode build() { + return ConstructorNode.constructor( + arguments.build(), + statements.build()); + } + } + + public class MethodBuilder { + private final String methodName; + private final ImmutableList.Builder<StatementNode> statements; + + public MethodBuilder(String name) { + this.methodName = name; + this.statements = ImmutableList.builder(); + } + + public ThisReferenceNode thisReference() { + return ThisReferenceNode.thisReference(name); + } + + public MethodBuilder statement(StatementNode statement) { + statements.add(statement); + return this; + } + + public MethodNode build() { + return MethodNode.builder() + .name(methodName) + .body(statements.build()) + .build(); + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java new file mode 100644 index 0000000..468ef9e --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java @@ -0,0 +1,18 @@ +package org.zwobble.couscous.ast; + +import java.util.List; + +import org.zwobble.couscous.ast.visitors.NodeVisitor; + +import lombok.Value; + +@Value(staticConstructor="constructor") +public class ConstructorNode implements CallableNode { + List<FormalArgumentNode> arguments; + List<StatementNode> body; + + @Override + public void accept(NodeVisitor visitor) { + visitor.visit(this); + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java index 2e1cded..8210ae1 100644 --- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java @@ -23,6 +23,12 @@ public interface ExpressionNode extends Node { } @Override + public Void visit(ThisReferenceNode reference) { + visitor.visit(reference); + return null; + } + + @Override public Void visit(AssignmentNode assignment) { visitor.visit(assignment); return null; @@ -51,6 +57,12 @@ public interface ExpressionNode extends Node { visitor.visit(call); return null; } + + @Override + public Void visit(FieldAccessNode fieldAccess) { + visitor.visit(fieldAccess); + return null; + } }); } } diff --git a/src/main/java/org/zwobble/couscous/ast/FieldAccessNode.java b/src/main/java/org/zwobble/couscous/ast/FieldAccessNode.java new file mode 100644 index 0000000..8de1323 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/FieldAccessNode.java @@ -0,0 +1,23 @@ +package org.zwobble.couscous.ast; + +import org.zwobble.couscous.ast.visitors.AssignableExpressionNodeVisitor; +import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; + +import lombok.Value; + +@Value(staticConstructor="fieldAccess") +public class FieldAccessNode implements AssignableExpressionNode { + ExpressionNode left; + String fieldName; + TypeName type; + + @Override + public <T> T accept(ExpressionNodeMapper<T> visitor) { + return visitor.visit(this); + } + + @Override + public void accept(AssignableExpressionNodeVisitor mapper) { + mapper.visit(this); + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java b/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java new file mode 100644 index 0000000..49a45d3 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java @@ -0,0 +1,9 @@ +package org.zwobble.couscous.ast; + +import lombok.Value; + +@Value(staticConstructor="field") +public class FieldDeclarationNode { + String name; + TypeName type; +} diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java index b547c92..700e9ec 100644 --- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java +++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java @@ -10,7 +10,7 @@ import lombok.Value; @Builder @Value -public class MethodNode implements Node { +public class MethodNode implements CallableNode { public static MethodNodeBuilder staticMethod(String name) { return builder().isStatic(true).name(name); } diff --git a/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java b/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java new file mode 100644 index 0000000..c8fa54a --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java @@ -0,0 +1,15 @@ +package org.zwobble.couscous.ast; + +import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; + +import lombok.Value; + +@Value(staticConstructor="thisReference") +public class ThisReferenceNode implements ExpressionNode { + TypeName type; + + @Override + public <T> T accept(ExpressionNodeMapper<T> visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java b/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java index a07006e..ebe79b0 100644 --- a/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java +++ b/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java @@ -1,11 +1,12 @@ package org.zwobble.couscous.ast; +import org.zwobble.couscous.ast.visitors.AssignableExpressionNodeVisitor; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; import lombok.Value; @Value -public class VariableReferenceNode implements ExpressionNode { +public class VariableReferenceNode implements AssignableExpressionNode { public static VariableReferenceNode reference(VariableNode variable) { return new VariableReferenceNode(variable.getDeclaration()); } @@ -25,4 +26,9 @@ public class VariableReferenceNode implements ExpressionNode { public TypeName getType() { return referent.getType(); } + + @Override + public void accept(AssignableExpressionNodeVisitor mapper) { + mapper.visit(this); + } } diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/AssignableExpressionNodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/AssignableExpressionNodeVisitor.java new file mode 100644 index 0000000..57cb105 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/visitors/AssignableExpressionNodeVisitor.java @@ -0,0 +1,9 @@ +package org.zwobble.couscous.ast.visitors; + +import org.zwobble.couscous.ast.FieldAccessNode; +import org.zwobble.couscous.ast.VariableReferenceNode; + +public interface AssignableExpressionNodeVisitor { + void visit(VariableReferenceNode reference); + void visit(FieldAccessNode fieldAccess); +} diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java index f924797..c1c3e88 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java @@ -2,18 +2,22 @@ package org.zwobble.couscous.ast.visitors; import org.zwobble.couscous.ast.AssignmentNode; import org.zwobble.couscous.ast.ConstructorCallNode; +import org.zwobble.couscous.ast.FieldAccessNode; import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.ast.MethodCallNode; import org.zwobble.couscous.ast.StaticMethodCallNode; import org.zwobble.couscous.ast.TernaryConditionalNode; +import org.zwobble.couscous.ast.ThisReferenceNode; import org.zwobble.couscous.ast.VariableReferenceNode; public interface ExpressionNodeMapper<T> { T visit(LiteralNode literal); T visit(VariableReferenceNode variableReference); + T visit(ThisReferenceNode reference); T visit(AssignmentNode assignment); T visit(TernaryConditionalNode ternaryConditional); T visit(MethodCallNode methodCall); T visit(StaticMethodCallNode staticMethodCall); T visit(ConstructorCallNode call); + T visit(FieldAccessNode fieldAccess); } diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java index 7377986..8a88052 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java @@ -3,7 +3,9 @@ package org.zwobble.couscous.ast.visitors; import org.zwobble.couscous.ast.AssignmentNode; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ConstructorCallNode; +import org.zwobble.couscous.ast.ConstructorNode; import org.zwobble.couscous.ast.ExpressionStatementNode; +import org.zwobble.couscous.ast.FieldAccessNode; import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.ast.LocalVariableDeclarationNode; import org.zwobble.couscous.ast.MethodCallNode; @@ -11,16 +13,19 @@ import org.zwobble.couscous.ast.MethodNode; import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.StaticMethodCallNode; import org.zwobble.couscous.ast.TernaryConditionalNode; +import org.zwobble.couscous.ast.ThisReferenceNode; import org.zwobble.couscous.ast.VariableReferenceNode; public interface NodeVisitor { void visit(LiteralNode literal); void visit(VariableReferenceNode variableReference); + void visit(ThisReferenceNode reference); void visit(AssignmentNode assignment); void visit(TernaryConditionalNode ternaryConditional); void visit(MethodCallNode methodCall); void visit(StaticMethodCallNode staticMethodCall); void visit(ConstructorCallNode call); + void visit(FieldAccessNode fieldAccess); void visit(ReturnNode returnNode); void visit(ExpressionStatementNode expressionStatement); @@ -28,4 +33,5 @@ public interface NodeVisitor { void visit(ClassNode classNode); void visit(MethodNode methodNode); + void visit(ConstructorNode constructorNode); } diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java index ac3786b..8408b7a 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java @@ -3,7 +3,9 @@ package org.zwobble.couscous.ast.visitors; import org.zwobble.couscous.ast.AssignmentNode; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ConstructorCallNode; +import org.zwobble.couscous.ast.ConstructorNode; import org.zwobble.couscous.ast.ExpressionStatementNode; +import org.zwobble.couscous.ast.FieldAccessNode; import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.ast.LocalVariableDeclarationNode; import org.zwobble.couscous.ast.MethodCallNode; @@ -11,6 +13,7 @@ import org.zwobble.couscous.ast.MethodNode; import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.StaticMethodCallNode; import org.zwobble.couscous.ast.TernaryConditionalNode; +import org.zwobble.couscous.ast.ThisReferenceNode; import org.zwobble.couscous.ast.VariableReferenceNode; public interface NodeVisitorWithEmptyDefaults extends NodeVisitor { @@ -23,6 +26,10 @@ public interface NodeVisitorWithEmptyDefaults extends NodeVisitor { } @Override + default void visit(ThisReferenceNode reference) { + } + + @Override default void visit(AssignmentNode assignment) { } @@ -41,6 +48,10 @@ public interface NodeVisitorWithEmptyDefaults extends NodeVisitor { @Override default void visit(ConstructorCallNode call) { } + + @Override + default void visit(FieldAccessNode fieldAccess) { + } @Override default void visit(ReturnNode returnNode) { @@ -61,4 +72,8 @@ public interface NodeVisitorWithEmptyDefaults extends NodeVisitor { @Override default void visit(MethodNode methodNode) { } + + @Override + default void visit(ConstructorNode constructorNode) { + } } diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java index 835d96f..bb5b054 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java @@ -3,7 +3,9 @@ package org.zwobble.couscous.ast.visitors; import org.zwobble.couscous.ast.AssignmentNode; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ConstructorCallNode; +import org.zwobble.couscous.ast.ConstructorNode; import org.zwobble.couscous.ast.ExpressionStatementNode; +import org.zwobble.couscous.ast.FieldAccessNode; import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.ast.LocalVariableDeclarationNode; import org.zwobble.couscous.ast.MethodCallNode; @@ -12,6 +14,7 @@ import org.zwobble.couscous.ast.Node; import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.StaticMethodCallNode; import org.zwobble.couscous.ast.TernaryConditionalNode; +import org.zwobble.couscous.ast.ThisReferenceNode; import org.zwobble.couscous.ast.VariableReferenceNode; import lombok.val; @@ -28,12 +31,17 @@ public class NodeVisitors { public void visit(VariableReferenceNode variableReference) { visitor.visit(variableReference); } + + @Override + public void visit(ThisReferenceNode reference) { + visitor.visit(reference); + } @Override public void visit(AssignmentNode assignment) { visitor.visit(assignment); assignment.getValue().accept(this); - visit(assignment.getTarget()); + assignment.getTarget().accept(this); } @Override @@ -68,6 +76,11 @@ public class NodeVisitors { argument.accept(this); } } + + @Override + public void visit(FieldAccessNode fieldAccess) { + visitor.visit(fieldAccess); + } @Override public void visit(ReturnNode returnNode) { @@ -90,6 +103,7 @@ public class NodeVisitors { @Override public void visit(ClassNode classNode) { visitor.visit(classNode); + classNode.getConstructor().accept(this); for (val method : classNode.getMethods()) { method.accept(this); } @@ -101,6 +115,13 @@ public class NodeVisitors { statement.accept(this); } } + + @Override + public void visit(ConstructorNode constructorNode) { + for (val statement : constructorNode.getBody()) { + statement.accept(this); + } + } }); } } |
