diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-01-17 18:02:27 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-01-17 18:02:27 +0000 |
| commit | cd244418efb005c27b1018458767c57dfa09e046 (patch) | |
| tree | 9a536359b38446a6271659337cc6803aab1529b9 /src/main/java | |
| parent | 013265afb2432181de05a109fd8fe7823d8f3d69 (diff) | |
Add transformation pass to C# backend
Diffstat (limited to 'src/main/java')
27 files changed, 440 insertions, 69 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java b/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java index 0d135ba..e102af7 100644 --- a/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java +++ b/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; public class AnnotationNode implements Node { public static AnnotationNode annotation(TypeName type) { @@ -22,6 +23,10 @@ public class AnnotationNode implements Node { return visitor.visit(this); } + public AnnotationNode transform(NodeTransformer transformer) { + return new AnnotationNode(transformer.transform(type)); + } + @Override public String toString() { return "AnnotationNode(type=" + type + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java b/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java index 15ecf8f..dd1a9f3 100644 --- a/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java +++ b/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -52,6 +53,12 @@ public class AssignmentNode implements ExpressionNode { replace.apply(value)); } + public ExpressionNode transform(NodeTransformer transformer) { + return new AssignmentNode( + (AssignableExpressionNode) transformer.visit(target), + transformer.visit(value)); + } + @Override public TypeName getType() { return value.getType(); diff --git a/src/main/java/org/zwobble/couscous/ast/CastNode.java b/src/main/java/org/zwobble/couscous/ast/CastNode.java index e81cd94..1f61941 100644 --- a/src/main/java/org/zwobble/couscous/ast/CastNode.java +++ b/src/main/java/org/zwobble/couscous/ast/CastNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -36,6 +37,10 @@ public class CastNode implements ExpressionNode { return new CastNode(replace.apply(expression), type); } + public ExpressionNode transform(NodeTransformer transformer) { + return new CastNode(transformer.visit(expression), transformer.transform(type)); + } + @Override public String toString() { return "CastNode(" + diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java index 3545084..8b54be6 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.List; import java.util.Set; @@ -66,6 +67,15 @@ public class ClassNode implements Node { return visitor.visit(this); } + public ClassNode transform(NodeTransformer transformer) { + return new ClassNode( + transformer.transform(name), + transformer.transformTypes(superTypes), + transformer.transformFields(fields), + transformer.visit(constructor), + transformer.transformMethods(methods)); + } + @Override public String toString() { return "ClassNode(" + diff --git a/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java b/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java index cad359d..ecbdc00 100644 --- a/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ConstructorCallNode.java @@ -1,10 +1,11 @@ package org.zwobble.couscous.ast; +import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; + import java.util.List; import java.util.function.Function; -import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; - import static org.zwobble.couscous.util.ExtraLists.eagerMap; public class ConstructorCallNode implements ExpressionNode { @@ -43,6 +44,12 @@ public class ConstructorCallNode implements ExpressionNode { return new ConstructorCallNode(type, eagerMap(arguments, replace::apply)); } + public ExpressionNode transform(NodeTransformer transformer) { + return new ConstructorCallNode( + transformer.transform(type), + transformer.transformExpressions(arguments)); + } + @Override public String toString() { return "ConstructorCallNode(type=" + type + ", arguments=" + arguments diff --git a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java index 0d4bad8..fab931b 100644 --- a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.Collections; import java.util.List; @@ -17,7 +18,7 @@ public class ConstructorNode implements CallableNode { private final List<FormalArgumentNode> arguments; private final List<StatementNode> body; - public ConstructorNode( + private ConstructorNode( List<FormalArgumentNode> arguments, List<StatementNode> body) { this.arguments = arguments; @@ -37,6 +38,12 @@ public class ConstructorNode implements CallableNode { return visitor.visit(this); } + public ConstructorNode transform(NodeTransformer transformer) { + return new ConstructorNode( + transformer.transformFormalArguments(arguments), + transformer.transformStatements(body)); + } + @Override public String toString() { return "ConstructorNode(arguments=" + arguments + ", body=" + body diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java index 0ac7381..68acedb 100644 --- a/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java @@ -1,5 +1,6 @@ package org.zwobble.couscous.ast; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import java.util.function.Function; @@ -29,6 +30,10 @@ public class ExpressionStatementNode implements StatementNode { return new ExpressionStatementNode(replace.apply(expression)); } + public StatementNode transform(NodeTransformer transformer) { + return new ExpressionStatementNode(transformer.visit(expression)); + } + @Override public String toString() { return "ExpressionStatementNode(expression=" + expression + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/FieldAccessNode.java b/src/main/java/org/zwobble/couscous/ast/FieldAccessNode.java index 9f881b4..3224b5d 100644 --- a/src/main/java/org/zwobble/couscous/ast/FieldAccessNode.java +++ b/src/main/java/org/zwobble/couscous/ast/FieldAccessNode.java @@ -2,6 +2,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.AssignableExpressionNodeVisitor; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -48,6 +49,13 @@ public class FieldAccessNode implements AssignableExpressionNode { return new FieldAccessNode(replace.apply(left), fieldName, type); } + public ExpressionNode transform(NodeTransformer transformer) { + return new FieldAccessNode( + transformer.visit(left), + fieldName, + transformer.transform(type)); + } + @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 index 7fea43c..3b27b9e 100644 --- a/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java +++ b/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java @@ -1,7 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; -import org.zwobble.couscous.ast.visitors.NodeVisitor; +import org.zwobble.couscous.ast.visitors.NodeTransformer; public class FieldDeclarationNode implements Node { public static FieldDeclarationNode field(String name, TypeName type) { @@ -29,6 +29,12 @@ public class FieldDeclarationNode implements Node { return visitor.visit(this); } + public FieldDeclarationNode transform(NodeTransformer transformer) { + return new FieldDeclarationNode( + name, + transformer.transform(type)); + } + @Override public String toString() { return "FieldDeclarationNode(name=" + name + ", type=" + type + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java index 41fb982..f7d7f42 100644 --- a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java +++ b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; public class FormalArgumentNode implements VariableNode, Node { public static FormalArgumentNode formalArg(VariableDeclaration declaration) { @@ -30,6 +31,10 @@ public class FormalArgumentNode implements VariableNode, Node { return visitor.visit(this); } + public FormalArgumentNode transform(NodeTransformer transformer) { + return new FormalArgumentNode(transformer.transform(declaration)); + } + @Override public String toString() { return "FormalArgumentNode(declaration=" + declaration + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/IfStatementNode.java b/src/main/java/org/zwobble/couscous/ast/IfStatementNode.java index 8b4709a..972f0a4 100644 --- a/src/main/java/org/zwobble/couscous/ast/IfStatementNode.java +++ b/src/main/java/org/zwobble/couscous/ast/IfStatementNode.java @@ -1,5 +1,6 @@ package org.zwobble.couscous.ast; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import java.util.List; @@ -53,6 +54,13 @@ public class IfStatementNode implements StatementNode { eagerMap(falseBranch, statement -> statement.replaceExpressions(replace))); } + public StatementNode transform(NodeTransformer transformer) { + return new IfStatementNode( + transformer.visit(condition), + transformer.transformStatements(trueBranch), + transformer.transformStatements(falseBranch)); + } + @Override public String toString() { return "IfStatementNode(condition=" + condition + ", trueBranch=" diff --git a/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java index 926af5d..ed32dc4 100644 --- a/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java +++ b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -29,6 +30,10 @@ public class InstanceReceiver implements Receiver { return visitor.visit(expression); } + public Receiver transform(NodeTransformer transformer) { + return new InstanceReceiver(transformer.visit(expression)); + } + @Override public <T> T accept(NodeMapper<T> visitor) { return visitor.visit(this); diff --git a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java index ed2aaf0..5753650 100644 --- a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java +++ b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.values.*; import java.util.function.Function; @@ -58,6 +59,18 @@ public class LiteralNode implements ExpressionNode { return this; } + public ExpressionNode transform(NodeTransformer transformer) { + return new LiteralNode(transformValue(transformer), transformer.transform(type)); + } + + private PrimitiveValue transformValue(NodeTransformer transformer) { + if (value instanceof TypeValue) { + return new TypeValue(transformer.transform(((TypeValue)value).getValue())); + } else { + return value; + } + } + @Override public String toString() { return "LiteralNode(value=" + value + ", type=" + type + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java b/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java index a165070..4ee0e97 100644 --- a/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java +++ b/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.identifiers.Identifier; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import java.util.function.Function; @@ -58,6 +59,12 @@ public class LocalVariableDeclarationNode implements VariableNode, StatementNode return new LocalVariableDeclarationNode(declaration, replace.apply(initialValue)); } + public StatementNode transform(NodeTransformer transformer) { + return new LocalVariableDeclarationNode( + transformer.transform(declaration), + transformer.visit(initialValue)); + } + @Override public String toString() { return "LocalVariableDeclarationNode(declaration=" + declaration diff --git a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java index b50250d..5a67bc2 100644 --- a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java +++ b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.List; import java.util.function.Function; @@ -95,6 +96,14 @@ public class MethodCallNode implements ExpressionNode { type); } + public ExpressionNode transform(NodeTransformer transformer) { + return new MethodCallNode( + transformer.visit(receiver), + methodName, + transformer.transformExpressions(arguments), + transformer.transform(type)); + } + @Override public String toString() { return "MethodCallNode(receiver=" + receiver + ", methodName=" diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java index 5ee3a7d..b5dfd39 100644 --- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java +++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java @@ -2,6 +2,7 @@ package org.zwobble.couscous.ast; import com.google.common.collect.ImmutableList; import org.zwobble.couscous.ast.visitors.NodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.values.UnitValue; import java.util.List; @@ -151,6 +152,16 @@ public class MethodNode implements CallableNode { return visitor.visit(this); } + public MethodNode transform(NodeTransformer transformer) { + return new MethodNode( + transformer.transformAnnotations(annotations), + isStatic, + name, + transformer.transformFormalArguments(arguments), + transformer.transform(returnType), + transformer.transformStatements(body)); + } + @Override public String toString() { return "MethodNode(" + diff --git a/src/main/java/org/zwobble/couscous/ast/ReturnNode.java b/src/main/java/org/zwobble/couscous/ast/ReturnNode.java index 68330af..5bd5987 100644 --- a/src/main/java/org/zwobble/couscous/ast/ReturnNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ReturnNode.java @@ -1,5 +1,6 @@ package org.zwobble.couscous.ast; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import java.util.function.Function; @@ -29,6 +30,12 @@ public class ReturnNode implements StatementNode { return new ReturnNode(replace.apply(value)); } + public StatementNode transform(NodeTransformer transformer) { + // TODO: remove duplication with replaceExpressions + // (can probably implement replaceExpressions with transform) + return new ReturnNode(transformer.visit(value)); + } + @Override public String toString() { return "ReturnNode(value=" + value + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java index 4d35376..7814108 100644 --- a/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java +++ b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.NodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -34,6 +35,10 @@ public class StaticReceiver implements Receiver { return visitor.visit(this); } + public Receiver transform(NodeTransformer transformer) { + return new StaticReceiver(transformer.transform(type)); + } + @Override public String toString() { return "StaticReceiver(" + diff --git a/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java b/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java index f370b0a..c49bbc5 100644 --- a/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java +++ b/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -50,6 +51,13 @@ public class TernaryConditionalNode implements ExpressionNode { replace.apply(ifFalse)); } + public ExpressionNode transform(NodeTransformer transformer) { + return new TernaryConditionalNode( + transformer.visit(condition), + transformer.visit(ifTrue), + transformer.visit(ifFalse)); + } + @Override public TypeName getType() { return ifTrue.getType(); diff --git a/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java b/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java index a4851c8..6056abd 100644 --- a/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ThisReferenceNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -34,6 +35,10 @@ public class ThisReferenceNode implements ExpressionNode, ReferenceNode { return visitor.visit(this); } + public ExpressionNode transform(NodeTransformer transformer) { + return new ThisReferenceNode(transformer.transform(type)); + } + @Override public String toString() { return "ThisReferenceNode(type=" + type + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java b/src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java index 1ffdd95..04ba7d1 100644 --- a/src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java +++ b/src/main/java/org/zwobble/couscous/ast/TypeCoercionNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -36,6 +37,12 @@ public class TypeCoercionNode implements ExpressionNode { return new TypeCoercionNode(replace.apply(expression), type); } + public ExpressionNode transform(NodeTransformer transformer) { + return new TypeCoercionNode( + transformer.visit(expression), + transformer.transform(type)); + } + @Override public String toString() { return "TypeCoercionNode(" + diff --git a/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java b/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java index c1b022a..b907c6d 100644 --- a/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java +++ b/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java @@ -3,6 +3,7 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.identifiers.Identifier; import org.zwobble.couscous.ast.visitors.AssignableExpressionNodeVisitor; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.function.Function; @@ -54,6 +55,10 @@ public class VariableReferenceNode implements AssignableExpressionNode, Referenc return visitor.visit(this); } + public ExpressionNode transform(NodeTransformer transformer) { + return new VariableReferenceNode(transformer.transform(referent)); + } + @Override public String toString() { return "VariableReferenceNode(referent=" + referent + ")"; diff --git a/src/main/java/org/zwobble/couscous/ast/WhileNode.java b/src/main/java/org/zwobble/couscous/ast/WhileNode.java index 6462821..34d1883 100644 --- a/src/main/java/org/zwobble/couscous/ast/WhileNode.java +++ b/src/main/java/org/zwobble/couscous/ast/WhileNode.java @@ -1,6 +1,7 @@ package org.zwobble.couscous.ast; import com.google.common.base.Objects; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import java.util.List; @@ -41,6 +42,12 @@ public class WhileNode implements StatementNode { eagerMap(body, statement -> statement.replaceExpressions(replace))); } + public StatementNode transform(NodeTransformer transformer) { + return new WhileNode( + transformer.visit(condition), + transformer.transformStatements(body)); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java new file mode 100644 index 0000000..539acd0 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java @@ -0,0 +1,185 @@ +package org.zwobble.couscous.ast.visitors; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import org.zwobble.couscous.ast.*; + +import java.util.List; +import java.util.Set; + +public class NodeTransformer implements ExpressionNodeMapper<ExpressionNode>, StatementNodeMapper<StatementNode>, NodeMapper<Node> { + // TODO: tidy up transform vs visit + public TypeName transform(TypeName type) { + return type; + } + + public ExpressionNode visit(ExpressionNode value) { + return value.accept((ExpressionNodeMapper<ExpressionNode>)this); + } + + @Override + public ExpressionNode visit(LiteralNode literal) { + return literal.transform(this); + } + + @Override + public ExpressionNode visit(VariableReferenceNode variableReference) { + return variableReference.transform(this); + } + + @Override + public ExpressionNode visit(ThisReferenceNode reference) { + return reference.transform(this); + } + + @Override + public ExpressionNode visit(AssignmentNode assignment) { + return assignment.transform(this); + } + + @Override + public ExpressionNode visit(TernaryConditionalNode ternaryConditional) { + return ternaryConditional.transform(this); + } + + @Override + public ExpressionNode visit(MethodCallNode methodCall) { + return methodCall.transform(this); + } + + @Override + public ExpressionNode visit(ConstructorCallNode call) { + return call.transform(this); + } + + @Override + public ExpressionNode visit(FieldAccessNode fieldAccess) { + return fieldAccess.transform(this); + } + + @Override + public ExpressionNode visit(TypeCoercionNode typeCoercion) { + return typeCoercion.transform(this); + } + + @Override + public ExpressionNode visit(CastNode cast) { + return cast.transform(this); + } + + public Receiver visit(Receiver receiver) { + // TODO: remove cast + return (Receiver) receiver.accept(this); + } + + @Override + public Node visit(InstanceReceiver receiver) { + return receiver.transform(this); + } + + @Override + public Node visit(StaticReceiver receiver) { + return receiver.transform(this); + } + + public VariableDeclaration transform(VariableDeclaration declaration) { + return VariableDeclaration.var(declaration.getId(), declaration.getName(), transform(declaration.getType())); + } + + public StatementNode visit(StatementNode statement) { + return statement.accept((StatementNodeMapper<StatementNode>)this); + } + + @Override + public StatementNode visit(ReturnNode returnNode) { + return returnNode.transform(this); + } + + @Override + public StatementNode visit(ExpressionStatementNode expressionStatement) { + return expressionStatement.transform(this); + } + + @Override + public StatementNode visit(LocalVariableDeclarationNode localVariableDeclaration) { + return localVariableDeclaration.transform(this); + } + + @Override + public StatementNode visit(IfStatementNode ifStatement) { + return ifStatement.transform(this); + } + + @Override + public StatementNode visit(WhileNode whileLoop) { + return whileLoop.transform(this); + } + + @Override + public FormalArgumentNode visit(FormalArgumentNode formalArgumentNode) { + return formalArgumentNode.transform(this); + } + + @Override + public AnnotationNode visit(AnnotationNode annotation) { + return annotation.transform(this); + } + + @Override + public MethodNode visit(MethodNode method) { + return method.transform(this); + } + + @Override + public ConstructorNode visit(ConstructorNode constructor) { + return constructor.transform(this); + } + + @Override + public FieldDeclarationNode visit(FieldDeclarationNode field) { + return field.transform(this); + } + + @Override + public ClassNode visit(ClassNode classNode) { + return classNode.transform(this); + } + + public List<AnnotationNode> transformAnnotations(List<AnnotationNode> annotations) { + return transformList(annotations, this::visit); + } + + public Set<TypeName> transformTypes(Set<TypeName> superTypes) { + return transformSet(superTypes, this::transform); + } + + public List<FieldDeclarationNode> transformFields(List<FieldDeclarationNode> fields) { + return transformList(fields, this::visit); + } + + public List<MethodNode> transformMethods(List<MethodNode> methods) { + return transformList(methods, this::visit); + } + + public List<StatementNode> transformStatements(List<StatementNode> body) { + return transformList(body, this::visit); + } + + public List<ExpressionNode> transformExpressions(List<? extends ExpressionNode> expressions) { + return transformList(expressions, this::visit); + } + + public List<FormalArgumentNode> transformFormalArguments(List<FormalArgumentNode> arguments) { + return transformList(arguments, this::visit); + } + + private <T> Set<T> transformSet(Set<T> values, Function<T, T> function) { + return ImmutableSet.copyOf(Iterables.transform(values, function)); + } + + private <T> List<T> transformList(List<? extends T> values, Function<T, T> function) { + return ImmutableList.copyOf(Iterables.transform(values, function)); + } +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java new file mode 100644 index 0000000..9e48e9a --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java @@ -0,0 +1,68 @@ +package org.zwobble.couscous.backends.csharp; + +import com.google.common.collect.ImmutableMap; +import org.zwobble.couscous.ast.*; +import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.values.*; + +import java.util.Map; +import java.util.Optional; + +public class CsharpCodeGenerator extends NodeTransformer { + private final static Map<TypeName, TypeName> PRIMITIVES = ImmutableMap.<TypeName, TypeName>builder() + .put(IntegerValue.REF, TypeName.of("int")) + .put(StringValue.REF, TypeName.of("string")) + .put(BooleanValue.REF, TypeName.of("bool")) + .put(ObjectValues.OBJECT, TypeName.of("object")) + .put(ObjectValues.CLASS, TypeName.of("System.Type")) + .put(UnitValue.REF, TypeName.of("void")) + .build(); + + private final String namespace; + + public static Node generateCode(Node node, String namespace) { + return new CsharpCodeGenerator(namespace).generateCode(node); + } + + private CsharpCodeGenerator(String namespace) { + this.namespace = namespace; + } + + private Node generateCode(Node node) { + return node.accept(this); + } + + @Override + public TypeName transform(TypeName type) { + if (PRIMITIVES.containsKey(type)) { + return PRIMITIVES.get(type); + } else { + return addPrefix(type, namespace); + } + } + + @Override + public ExpressionNode visit(MethodCallNode call) { + return toPrimitiveMethod(call).orElseGet(() -> super.visit(call)); + } + + private Optional<ExpressionNode> toPrimitiveMethod(MethodCallNode call) { + return call.getReceiver().accept(new Receiver.Mapper<Optional<ExpressionNode>>() { + @Override + public Optional<ExpressionNode> visit(ExpressionNode receiver) { + return Optional.empty(); + } + + @Override + public Optional<ExpressionNode> visit(TypeName receiver) { + return CsharpPrimitiveMethods.getPrimitiveStaticMethod(receiver, call.getMethodName()) + .map(generator -> generator.generate(call.getArguments())); + } + }); + + } + + private TypeName addPrefix(TypeName name, String namespace) { + return TypeName.of(namespace + "." + name.getQualifiedName()); + } +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java index b53560d..9424b2d 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java @@ -3,25 +3,24 @@ package org.zwobble.couscous.backends.csharp; import com.google.common.collect.ImmutableMap; import org.zwobble.couscous.ast.ExpressionNode; import org.zwobble.couscous.ast.TypeName; -import org.zwobble.couscous.backends.SourceCodeWriter; import org.zwobble.couscous.values.ObjectValues; import java.util.List; import java.util.Map; import java.util.Optional; +import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall; +import static org.zwobble.couscous.util.ExtraLists.list; + public class CsharpPrimitiveMethods { private static final Map<String, PrimitiveStaticMethodGenerator> STATIC_INT_METHODS = ImmutableMap.<String, PrimitiveStaticMethodGenerator>builder() - .put("parseInt", (arguments, writer) -> { - writer.writeIdentifier("int"); - writer.writeSymbol("."); - writer.writeIdentifier("Parse"); - writer.writeSymbol("("); - writer.writeIdentifier(CsharpSerializer.serialize(arguments.get(0), "")); - writer.writeSymbol(")"); - }) + .put("parseInt", arguments -> staticMethodCall( + TypeName.of("int"), + "Parse", + list(arguments.get(0)), + TypeName.of("int"))) .build(); @@ -37,6 +36,6 @@ public class CsharpPrimitiveMethods { @FunctionalInterface public interface PrimitiveStaticMethodGenerator { - void generate(List<ExpressionNode> arguments, SourceCodeWriter writer); + ExpressionNode generate(List<ExpressionNode> arguments); } } diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java index 275ae13..ffd2f02 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java @@ -1,24 +1,13 @@ package org.zwobble.couscous.backends.csharp; -import com.google.common.collect.ImmutableMap; import org.zwobble.couscous.ast.*; import org.zwobble.couscous.ast.visitors.NodeVisitor; import org.zwobble.couscous.backends.SourceCodeWriter; -import org.zwobble.couscous.values.*; +import org.zwobble.couscous.values.PrimitiveValueVisitor; import java.util.List; -import java.util.Map; public class CsharpSerializer implements NodeVisitor { - private final static Map<TypeName, String> PRIMITIVES = ImmutableMap.<TypeName, String>builder() - .put(IntegerValue.REF, "int") - .put(StringValue.REF, "string") - .put(BooleanValue.REF, "bool") - .put(ObjectValues.OBJECT, "object") - .put(ObjectValues.CLASS, "System.Type") - .put(UnitValue.REF, "void") - .build(); - public static String serialize(Node node, String namespace) { SourceCodeWriter writer = new SourceCodeWriter( (writer2) -> { @@ -29,17 +18,16 @@ public class CsharpSerializer implements NodeVisitor { writer2.writeStatement(() -> writer2.writeSymbol("}")); } ); - CsharpSerializer serializer = new CsharpSerializer(writer, namespace); - serializer.write(node); + CsharpSerializer serializer = new CsharpSerializer(writer); + + serializer.write(CsharpCodeGenerator.generateCode(node, namespace)); return writer.asString(); } private final SourceCodeWriter writer; - private final String namespace; - private CsharpSerializer(SourceCodeWriter writer, String namespace) { + private CsharpSerializer(SourceCodeWriter writer) { this.writer = writer; - this.namespace = namespace; } private void write(Node node) { @@ -117,32 +105,10 @@ public class CsharpSerializer implements NodeVisitor { @Override public void visit(MethodCallNode methodCall) { - if (!writePrimitiveMethod(methodCall)) { - write(methodCall.getReceiver()); - writer.writeSymbol("."); - writer.writeIdentifier(methodCall.getMethodName()); - writeArguments(methodCall.getArguments()); - } - } - - private boolean writePrimitiveMethod(MethodCallNode methodCall) { - return methodCall.getReceiver().accept(new Receiver.Mapper<Boolean>() { - @Override - public Boolean visit(ExpressionNode receiver) { - return false; - } - - @Override - public Boolean visit(TypeName receiver) { - // TODO: transform AST before serialisation instead of exposing write to CsharpPrimitiveMethods - return CsharpPrimitiveMethods.getPrimitiveStaticMethod(receiver, methodCall.getMethodName()) - .map(generator -> { - generator.generate(methodCall.getArguments(), writer); - return true; - }) - .orElse(false); - } - }); + write(methodCall.getReceiver()); + writer.writeSymbol("."); + writer.writeIdentifier(methodCall.getMethodName()); + writeArguments(methodCall.getArguments()); } @Override @@ -278,13 +244,9 @@ public class CsharpSerializer implements NodeVisitor { @Override public void visit(ClassNode classNode) { - String namespace = this.namespace + - classNode.getName().getPackage() - .map(packageName -> "." + packageName) - .orElse(""); writer.writeKeyword("namespace"); writer.writeSpace(); - writer.writeIdentifier(namespace); + writer.writeIdentifier(classNode.getName().getPackage().get()); writer.startBlock(); writer.writeStatement(() -> { writer.writeKeyword("internal"); @@ -323,15 +285,10 @@ public class CsharpSerializer implements NodeVisitor { } private void writeTypeReference(TypeName value) { - // TODO: process the nodes before serialization - if (PRIMITIVES.containsKey(value)) { - writer.writeIdentifier(PRIMITIVES.get(value)); - } else { - writer.writeIdentifier(typeReference(value)); - } + writer.writeIdentifier(typeReference(value)); } private String typeReference(TypeName value) { - return namespace + "." + value.getQualifiedName(); + return value.getQualifiedName(); } } |
