aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/zwobble')
-rw-r--r--src/main/java/org/zwobble/couscous/ast/AssignmentNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ClassNode.java9
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ExpressionNode.java48
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/LiteralNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/MethodCallNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/MethodNode.java9
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Node.java7
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ReturnNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/StatementNode.java31
-rw-r--r--src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java (renamed from src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java)2
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java29
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java59
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java97
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/StatementNodeMapper.java (renamed from src/main/java/org/zwobble/couscous/ast/visitors/StatementNodeVisitor.java)2
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java69
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCompiler.java29
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java10
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/ast/PythonImportNode.java15
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java2
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java4
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Executor.java6
-rw-r--r--src/main/java/org/zwobble/couscous/util/ExtraLists.java18
27 files changed, 432 insertions, 50 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java b/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java
index 8989ef3..349b492 100644
--- a/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/AssignmentNode.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.values.TypeReference;
import static org.zwobble.couscous.ast.VariableReferenceNode.reference;
@@ -17,7 +17,7 @@ public class AssignmentNode implements ExpressionNode {
ExpressionNode value;
@Override
- public <T> T accept(ExpressionNodeVisitor<T> visitor) {
+ public <T> T accept(ExpressionNodeMapper<T> visitor) {
return visitor.visit(this);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
index 3d785d2..77480b5 100644
--- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
@@ -2,13 +2,15 @@ package org.zwobble.couscous.ast;
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 {
+public class ClassNode implements Node {
public static ClassNode.Builder builder(String name) {
return new Builder(name);
}
@@ -40,4 +42,9 @@ public class ClassNode {
// TODO Stronger notion of class names? Should look up the terminology
return name.substring(name.lastIndexOf(".") + 1);
}
+
+ @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 bc27a99..297133d 100644
--- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
@@ -1,9 +1,51 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
+import org.zwobble.couscous.ast.visitors.NodeVisitor;
import org.zwobble.couscous.values.TypeReference;
-public interface ExpressionNode {
+public interface ExpressionNode extends Node {
TypeReference getType();
- <T> T accept(ExpressionNodeVisitor<T> visitor);
+ <T> T accept(ExpressionNodeMapper<T> visitor);
+
+ @Override
+ default void accept(NodeVisitor visitor) {
+ accept(new ExpressionNodeMapper<Void>() {
+ @Override
+ public Void visit(LiteralNode literal) {
+ visitor.visit(literal);
+ return null;
+ }
+
+ @Override
+ public Void visit(VariableReferenceNode variableReference) {
+ visitor.visit(variableReference);
+ return null;
+ }
+
+ @Override
+ public Void visit(AssignmentNode assignment) {
+ visitor.visit(assignment);
+ return null;
+ }
+
+ @Override
+ public Void visit(TernaryConditionalNode ternaryConditional) {
+ visitor.visit(ternaryConditional);
+ return null;
+ }
+
+ @Override
+ public Void visit(MethodCallNode methodCall) {
+ visitor.visit(methodCall);
+ return null;
+ }
+
+ @Override
+ public Void visit(StaticMethodCallNode staticMethodCall) {
+ visitor.visit(staticMethodCall);
+ return null;
+ }
+ });
+ }
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java
index ec04663..5bbe2b5 100644
--- a/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ExpressionStatementNode.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.StatementNodeVisitor;
+import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
import lombok.Value;
@@ -9,7 +9,7 @@ public class ExpressionStatementNode implements StatementNode {
ExpressionNode expression;
@Override
- public <T> T accept(StatementNodeVisitor<T> visitor) {
+ public <T> T accept(StatementNodeMapper<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 2d77cd4..a608104 100644
--- a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.values.BooleanValue;
import org.zwobble.couscous.values.IntegerValue;
import org.zwobble.couscous.values.PrimitiveValue;
@@ -33,7 +33,7 @@ public class LiteralNode implements ExpressionNode {
TypeReference type;
@Override
- public <T> T accept(ExpressionNodeVisitor<T> visitor) {
+ public <T> T accept(ExpressionNodeMapper<T> visitor) {
return visitor.visit(this);
}
}
diff --git a/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java b/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java
index cf6c5f0..2b5c63a 100644
--- a/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/LocalVariableDeclarationNode.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.StatementNodeVisitor;
+import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
import org.zwobble.couscous.values.TypeReference;
import static org.zwobble.couscous.ast.VariableDeclaration.var;
@@ -21,7 +21,7 @@ public class LocalVariableDeclarationNode implements VariableNode, StatementNode
ExpressionNode initialValue;
@Override
- public <T> T accept(StatementNodeVisitor<T> visitor) {
+ public <T> T accept(StatementNodeMapper<T> visitor) {
return visitor.visit(this);
}
}
diff --git a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
index f240971..e1358c2 100644
--- a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
@@ -2,7 +2,7 @@ package org.zwobble.couscous.ast;
import java.util.List;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.values.TypeReference;
import lombok.Value;
@@ -23,7 +23,7 @@ public class MethodCallNode implements ExpressionNode {
}
@Override
- public <T> T accept(ExpressionNodeVisitor<T> visitor) {
+ public <T> T accept(ExpressionNodeMapper<T> visitor) {
return visitor.visit(this);
}
}
diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java
index 91acbd5..e924299 100644
--- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java
@@ -2,13 +2,15 @@ package org.zwobble.couscous.ast;
import java.util.List;
+import org.zwobble.couscous.ast.visitors.NodeVisitor;
+
import lombok.Builder;
import lombok.Singular;
import lombok.Value;
@Builder
@Value
-public class MethodNode {
+public class MethodNode implements Node {
public static MethodNodeBuilder staticMethod(String name) {
return builder().isStatic(true).name(name);
}
@@ -19,4 +21,9 @@ public class MethodNode {
List<FormalArgumentNode> arguments;
@Singular("statement")
List<StatementNode> body;
+
+ @Override
+ public void accept(NodeVisitor visitor) {
+ visitor.visit(this);
+ }
}
diff --git a/src/main/java/org/zwobble/couscous/ast/Node.java b/src/main/java/org/zwobble/couscous/ast/Node.java
new file mode 100644
index 0000000..acde931
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/Node.java
@@ -0,0 +1,7 @@
+package org.zwobble.couscous.ast;
+
+import org.zwobble.couscous.ast.visitors.NodeVisitor;
+
+public interface Node {
+ void accept(NodeVisitor visitor);
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/ReturnNode.java b/src/main/java/org/zwobble/couscous/ast/ReturnNode.java
index 529dbb5..7f4a57e 100644
--- a/src/main/java/org/zwobble/couscous/ast/ReturnNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ReturnNode.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.StatementNodeVisitor;
+import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
import lombok.Value;
@@ -9,7 +9,7 @@ public class ReturnNode implements StatementNode {
ExpressionNode value;
@Override
- public <T> T accept(StatementNodeVisitor<T> visitor) {
+ public <T> T accept(StatementNodeMapper<T> visitor) {
return visitor.visit(this);
}
}
diff --git a/src/main/java/org/zwobble/couscous/ast/StatementNode.java b/src/main/java/org/zwobble/couscous/ast/StatementNode.java
index 773420e..7a1b25b 100644
--- a/src/main/java/org/zwobble/couscous/ast/StatementNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/StatementNode.java
@@ -1,7 +1,32 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.StatementNodeVisitor;
+import org.zwobble.couscous.ast.visitors.NodeVisitor;
+import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
-public interface StatementNode {
- <T> T accept(StatementNodeVisitor<T> visitor);
+public interface StatementNode extends Node {
+ <T> T accept(StatementNodeMapper<T> visitor);
+
+ @Override
+ default void accept(NodeVisitor visitor) {
+ accept(new StatementNodeMapper<Void>() {
+ @Override
+ public Void visit(ReturnNode returnNode) {
+ visitor.visit(returnNode);
+ return null;
+ }
+
+ @Override
+ public Void visit(ExpressionStatementNode expressionStatement) {
+ visitor.visit(expressionStatement);
+ return null;
+ }
+
+ @Override
+ public Void visit(
+ LocalVariableDeclarationNode localVariableDeclaration) {
+ visitor.visit(localVariableDeclaration);
+ return null;
+ }
+ });
+ }
}
diff --git a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java
index 0228514..96e2e4c 100644
--- a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java
@@ -2,7 +2,7 @@ package org.zwobble.couscous.ast;
import java.util.List;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.values.TypeReference;
import static java.util.Arrays.asList;
@@ -24,7 +24,7 @@ public class StaticMethodCallNode implements ExpressionNode {
List<ExpressionNode> arguments;
@Override
- public <T> T accept(ExpressionNodeVisitor<T> visitor) {
+ public <T> T accept(ExpressionNodeMapper<T> visitor) {
return visitor.visit(this);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java b/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java
index 8b30024..99b5f60 100644
--- a/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/TernaryConditionalNode.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.values.TypeReference;
import lombok.Value;
@@ -12,7 +12,7 @@ public class TernaryConditionalNode implements ExpressionNode {
ExpressionNode ifFalse;
@Override
- public <T> T accept(ExpressionNodeVisitor<T> visitor) {
+ 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 5499d50..fe47a84 100644
--- a/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/VariableReferenceNode.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.values.TypeReference;
import lombok.Value;
@@ -14,7 +14,7 @@ public class VariableReferenceNode implements ExpressionNode {
VariableDeclaration referent;
@Override
- public <T> T accept(ExpressionNodeVisitor<T> visitor) {
+ public <T> T accept(ExpressionNodeMapper<T> visitor) {
return visitor.visit(this);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
index c47b942..2be2894 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
@@ -7,7 +7,7 @@ import org.zwobble.couscous.ast.StaticMethodCallNode;
import org.zwobble.couscous.ast.TernaryConditionalNode;
import org.zwobble.couscous.ast.VariableReferenceNode;
-public interface ExpressionNodeVisitor<T> {
+public interface ExpressionNodeMapper<T> {
T visit(LiteralNode literal);
T visit(VariableReferenceNode variableReference);
T visit(AssignmentNode assignment);
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
new file mode 100644
index 0000000..014b48e
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
@@ -0,0 +1,29 @@
+package org.zwobble.couscous.ast.visitors;
+
+import org.zwobble.couscous.ast.AssignmentNode;
+import org.zwobble.couscous.ast.ClassNode;
+import org.zwobble.couscous.ast.ExpressionStatementNode;
+import org.zwobble.couscous.ast.LiteralNode;
+import org.zwobble.couscous.ast.LocalVariableDeclarationNode;
+import org.zwobble.couscous.ast.MethodCallNode;
+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.VariableReferenceNode;
+
+public interface NodeVisitor {
+ void visit(LiteralNode literal);
+ void visit(VariableReferenceNode variableReference);
+ void visit(AssignmentNode assignment);
+ void visit(TernaryConditionalNode ternaryConditional);
+ void visit(MethodCallNode methodCall);
+ void visit(StaticMethodCallNode staticMethodCall);
+
+ void visit(ReturnNode returnNode);
+ void visit(ExpressionStatementNode expressionStatement);
+ void visit(LocalVariableDeclarationNode localVariableDeclaration);
+
+ void visit(ClassNode classNode);
+ void visit(MethodNode methodNode);
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java
new file mode 100644
index 0000000..3a58614
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitorWithEmptyDefaults.java
@@ -0,0 +1,59 @@
+package org.zwobble.couscous.ast.visitors;
+
+import org.zwobble.couscous.ast.AssignmentNode;
+import org.zwobble.couscous.ast.ClassNode;
+import org.zwobble.couscous.ast.ExpressionStatementNode;
+import org.zwobble.couscous.ast.LiteralNode;
+import org.zwobble.couscous.ast.LocalVariableDeclarationNode;
+import org.zwobble.couscous.ast.MethodCallNode;
+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.VariableReferenceNode;
+
+public interface NodeVisitorWithEmptyDefaults extends NodeVisitor {
+ @Override
+ default void visit(LiteralNode literal) {
+ }
+
+ @Override
+ default void visit(VariableReferenceNode variableReference) {
+ }
+
+ @Override
+ default void visit(AssignmentNode assignment) {
+ }
+
+ @Override
+ default void visit(TernaryConditionalNode ternaryConditional) {
+ }
+
+ @Override
+ default void visit(MethodCallNode methodCall) {
+ }
+
+ @Override
+ default void visit(StaticMethodCallNode staticMethodCall) {
+ }
+
+ @Override
+ default void visit(ReturnNode returnNode) {
+ }
+
+ @Override
+ default void visit(ExpressionStatementNode expressionStatement) {
+ }
+
+ @Override
+ default void visit(LocalVariableDeclarationNode localVariableDeclaration) {
+ }
+
+ @Override
+ default void visit(ClassNode classNode) {
+ }
+
+ @Override
+ default void visit(MethodNode methodNode) {
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java
new file mode 100644
index 0000000..88c6e10
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitors.java
@@ -0,0 +1,97 @@
+package org.zwobble.couscous.ast.visitors;
+
+import org.zwobble.couscous.ast.AssignmentNode;
+import org.zwobble.couscous.ast.ClassNode;
+import org.zwobble.couscous.ast.ExpressionStatementNode;
+import org.zwobble.couscous.ast.LiteralNode;
+import org.zwobble.couscous.ast.LocalVariableDeclarationNode;
+import org.zwobble.couscous.ast.MethodCallNode;
+import org.zwobble.couscous.ast.MethodNode;
+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.VariableReferenceNode;
+
+import lombok.val;
+
+public class NodeVisitors {
+ public static void visitAll(Node node, NodeVisitor visitor) {
+ node.accept(new NodeVisitor() {
+ @Override
+ public void visit(LiteralNode literal) {
+ visitor.visit(literal);
+ }
+
+ @Override
+ public void visit(VariableReferenceNode variableReference) {
+ visitor.visit(variableReference);
+ }
+
+ @Override
+ public void visit(AssignmentNode assignment) {
+ visitor.visit(assignment);
+ assignment.getValue().accept(this);
+ visit(assignment.getTarget());
+ }
+
+ @Override
+ public void visit(TernaryConditionalNode ternaryConditional) {
+ visitor.visit(ternaryConditional);
+ ternaryConditional.getCondition().accept(this);
+ ternaryConditional.getIfTrue().accept(this);
+ ternaryConditional.getIfFalse().accept(this);
+ }
+
+ @Override
+ public void visit(MethodCallNode methodCall) {
+ visitor.visit(methodCall);
+ methodCall.getReceiver().accept(this);
+ for (val argument : methodCall.getArguments()) {
+ argument.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(StaticMethodCallNode staticMethodCall) {
+ visitor.visit(staticMethodCall);
+ for (val argument : staticMethodCall.getArguments()) {
+ argument.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(ReturnNode returnNode) {
+ visitor.visit(returnNode);
+ returnNode.getValue().accept(this);
+ }
+
+ @Override
+ public void visit(ExpressionStatementNode expressionStatement) {
+ visitor.visit(expressionStatement);
+ expressionStatement.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(LocalVariableDeclarationNode localVariableDeclaration) {
+ visitor.visit(localVariableDeclaration);
+ localVariableDeclaration.getInitialValue().accept(this);
+ }
+
+ @Override
+ public void visit(ClassNode classNode) {
+ visitor.visit(classNode);
+ for (val method : classNode.getMethods()) {
+ method.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(MethodNode methodNode) {
+ for (val statement : methodNode.getBody()) {
+ statement.accept(this);
+ }
+ }
+ });
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/StatementNodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/StatementNodeMapper.java
index 620f6f8..4bae481 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/StatementNodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/StatementNodeMapper.java
@@ -4,7 +4,7 @@ import org.zwobble.couscous.ast.ExpressionStatementNode;
import org.zwobble.couscous.ast.LocalVariableDeclarationNode;
import org.zwobble.couscous.ast.ReturnNode;
-public interface StatementNodeVisitor<T> {
+public interface StatementNodeMapper<T> {
T visit(ReturnNode returnNode);
T visit(ExpressionStatementNode expressionStatement);
T visit(LocalVariableDeclarationNode localVariableDeclaration);
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
index cf48ba0..551abcb 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
@@ -1,6 +1,8 @@
package org.zwobble.couscous.backends.python;
import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.zwobble.couscous.ast.AssignmentNode;
@@ -16,11 +18,14 @@ import org.zwobble.couscous.ast.StatementNode;
import org.zwobble.couscous.ast.StaticMethodCallNode;
import org.zwobble.couscous.ast.TernaryConditionalNode;
import org.zwobble.couscous.ast.VariableReferenceNode;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
-import org.zwobble.couscous.ast.visitors.StatementNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
+import org.zwobble.couscous.ast.visitors.NodeVisitorWithEmptyDefaults;
+import org.zwobble.couscous.ast.visitors.NodeVisitors;
+import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
import org.zwobble.couscous.backends.python.ast.PythonBlock;
import org.zwobble.couscous.backends.python.ast.PythonExpressionNode;
import org.zwobble.couscous.backends.python.ast.PythonFunctionDefinitionNode;
+import org.zwobble.couscous.backends.python.ast.PythonImportNode;
import org.zwobble.couscous.backends.python.ast.PythonModuleNode;
import org.zwobble.couscous.backends.python.ast.PythonStatementNode;
import org.zwobble.couscous.backends.python.ast.PythonVariableReferenceNode;
@@ -31,6 +36,11 @@ import org.zwobble.couscous.values.PrimitiveValueVisitor;
import org.zwobble.couscous.values.StringValue;
import org.zwobble.couscous.values.UnitValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterators;
+
+import static com.google.common.collect.Iterators.singletonIterator;
import static java.util.Arrays.asList;
import static org.zwobble.couscous.backends.python.ast.PythonAssignmentNode.pythonAssignment;
import static org.zwobble.couscous.backends.python.ast.PythonAttributeAccessNode.pythonAttributeAccess;
@@ -44,18 +54,37 @@ import static org.zwobble.couscous.backends.python.ast.PythonModuleNode.pythonMo
import static org.zwobble.couscous.backends.python.ast.PythonReturnNode.pythonReturn;
import static org.zwobble.couscous.backends.python.ast.PythonStringLiteralNode.pythonStringLiteral;
import static org.zwobble.couscous.backends.python.ast.PythonVariableReferenceNode.pythonVariableReference;
+import static org.zwobble.couscous.util.ExtraLists.foldLeft;
import lombok.val;
public class PythonCodeGenerator {
public static PythonModuleNode generateCode(ClassNode classNode) {
+ val imports = findImports(classNode).stream()
+ .map(PythonImportNode::pythonImport)
+ .iterator();
+
val pythonBody = classNode.getMethods()
.stream()
.map(PythonCodeGenerator::generateFunction)
.collect(Collectors.toList());
val pythonClass = pythonClass(classNode.getLocalName(), pythonBody);
- return pythonModule(asList(pythonClass));
+
+ return pythonModule(ImmutableList.copyOf(Iterators.concat(
+ imports,
+ singletonIterator(pythonClass))));
+ }
+
+ private static Set<String> findImports(ClassNode classNode) {
+ val imports = ImmutableSet.<String>builder();
+ NodeVisitors.visitAll(classNode, new NodeVisitorWithEmptyDefaults() {
+ @Override
+ public void visit(StaticMethodCallNode staticMethodCall) {
+ imports.add(staticMethodCall.getClassName());
+ }
+ });
+ return imports.build();
}
public static PythonExpressionNode generateCode(PrimitiveValue value) {
@@ -99,7 +128,7 @@ public class PythonCodeGenerator {
return statement.accept(new StatementGenerator());
}
- private static class StatementGenerator implements StatementNodeVisitor<PythonStatementNode> {
+ private static class StatementGenerator implements StatementNodeMapper<PythonStatementNode> {
@Override
public PythonStatementNode visit(ReturnNode returnNode) {
return pythonReturn(generateExpression(returnNode.getValue()));
@@ -131,7 +160,7 @@ public class PythonCodeGenerator {
private static final ExpressionGenerator EXPRESSION_GENERATOR = new ExpressionGenerator();
- private static class ExpressionGenerator implements ExpressionNodeVisitor<PythonExpressionNode> {
+ private static class ExpressionGenerator implements ExpressionNodeMapper<PythonExpressionNode> {
@Override
public PythonExpressionNode visit(LiteralNode literal) {
return generateCode(literal.getValue());
@@ -171,16 +200,36 @@ public class PythonCodeGenerator {
}
}
+ @Override
+ public PythonExpressionNode visit(StaticMethodCallNode staticMethodCall) {
+ val className = staticMethodCall.getClassName();
+ val moduleParts = asList(className.split(Pattern.quote(".")));
+
+ val module = foldLeft(
+ moduleParts,
+ part -> (PythonExpressionNode)pythonVariableReference(part),
+ (parent, part) -> pythonAttributeAccess(parent, part));
+
+ val classReference = pythonAttributeAccess(
+ module,
+ className.substring(className.lastIndexOf(".") + 1));
+
+ val methodReference = pythonAttributeAccess(
+ classReference,
+ staticMethodCall.getMethodName());
+
+ val arguments = staticMethodCall.getArguments().stream()
+ .map(PythonCodeGenerator::generateExpression)
+ .collect(Collectors.toList());;
+
+ return pythonCall(methodReference, arguments);
+ }
+
private List<PythonExpressionNode> generateArguments(MethodCallNode methodCall) {
return methodCall.getArguments().stream()
.map(PythonCodeGenerator::generateExpression)
.collect(Collectors.toList());
}
-
- @Override
- public PythonExpressionNode visit(StaticMethodCallNode staticMethodCall) {
- throw new UnsupportedOperationException();
- }
}
private static boolean isPrimitive(ExpressionNode value) {
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonCompiler.java b/src/main/java/org/zwobble/couscous/backends/python/PythonCompiler.java
index b38bc73..a54f037 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCompiler.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCompiler.java
@@ -15,20 +15,35 @@ import lombok.SneakyThrows;
import lombok.val;
public class PythonCompiler {
- public void compile(List<ClassNode> classes, Path path) {
+ private final Path root;
+
+ public PythonCompiler(Path root) {
+ this.root = root;
+ }
+
+ public void compile(List<ClassNode> classes) {
for (val classNode : classes) {
- compileClass(classNode, pathForClass(classNode, path));
+ compileClass(classNode);
}
+ writeClass("java.lang.Integer",
+ "class Integer(object):\n" +
+ " def parseInt(value):\n" +
+ " return int(value)"
+ );
+ }
+
+ private Path pathForClass(String className) {
+ return root.resolve(className.replace(".", File.separator) + ".py");
}
- private Path pathForClass(ClassNode classNode, Path path) {
- return path.resolve(classNode.getName().replace(".", File.separator) + ".py");
+ private void compileClass(ClassNode classNode) {
+ writeClass(classNode.getName(), serialize(generateCode(classNode)));
}
@SneakyThrows
- private void compileClass(ClassNode classNode, Path path) {
+ private void writeClass(String name, String contents) {
+ val path = pathForClass(name);
Files.createDirectories(path.getParent());
- Files.write(path, asList(serialize(generateCode(classNode))));
-
+ Files.write(path, asList(contents));
}
}
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java b/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java
index 0bd71f7..9c82b5d 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java
@@ -13,6 +13,7 @@ import org.zwobble.couscous.backends.python.ast.PythonConditionalExpressionNode;
import org.zwobble.couscous.backends.python.ast.PythonExpressionNode;
import org.zwobble.couscous.backends.python.ast.PythonFunctionDefinitionNode;
import org.zwobble.couscous.backends.python.ast.PythonGetSliceNode;
+import org.zwobble.couscous.backends.python.ast.PythonImportNode;
import org.zwobble.couscous.backends.python.ast.PythonIntegerLiteralNode;
import org.zwobble.couscous.backends.python.ast.PythonModuleNode;
import org.zwobble.couscous.backends.python.ast.PythonNode;
@@ -160,6 +161,15 @@ public class PythonSerializer implements PythonNodeVisitor {
});
}
+ @Override
+ public void visit(PythonImportNode importNode) {
+ writer.writeStatement(() -> {
+ writer.writeKeyword("import");
+ writer.writeSpace();
+ writer.writeIdentifier(importNode.getName());
+ });
+ }
+
private void writeParenthesised(PythonExpressionNode expression) {
writer.writeSymbol("(");
write(expression);
diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonImportNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonImportNode.java
new file mode 100644
index 0000000..2d38004
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonImportNode.java
@@ -0,0 +1,15 @@
+package org.zwobble.couscous.backends.python.ast;
+
+import org.zwobble.couscous.backends.python.ast.visitors.PythonNodeVisitor;
+
+import lombok.Value;
+
+@Value(staticConstructor="pythonImport")
+public class PythonImportNode implements PythonStatementNode {
+ String name;
+
+ @Override
+ public void accept(PythonNodeVisitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java b/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java
index 29d6108..7632342 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java
@@ -8,6 +8,7 @@ import org.zwobble.couscous.backends.python.ast.PythonClassNode;
import org.zwobble.couscous.backends.python.ast.PythonConditionalExpressionNode;
import org.zwobble.couscous.backends.python.ast.PythonFunctionDefinitionNode;
import org.zwobble.couscous.backends.python.ast.PythonGetSliceNode;
+import org.zwobble.couscous.backends.python.ast.PythonImportNode;
import org.zwobble.couscous.backends.python.ast.PythonIntegerLiteralNode;
import org.zwobble.couscous.backends.python.ast.PythonModuleNode;
import org.zwobble.couscous.backends.python.ast.PythonPassNode;
@@ -30,6 +31,7 @@ public interface PythonNodeVisitor {
void visit(PythonClassNode pythonClass);
void visit(PythonFunctionDefinitionNode functionDefinition);
void visit(PythonAssignmentNode assignment);
+ void visit(PythonImportNode importNode);
void visit(PythonModuleNode module);
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
index c2eeb59..9f183ec 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
@@ -10,14 +10,14 @@ import org.zwobble.couscous.ast.MethodCallNode;
import org.zwobble.couscous.ast.StaticMethodCallNode;
import org.zwobble.couscous.ast.TernaryConditionalNode;
import org.zwobble.couscous.ast.VariableReferenceNode;
-import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.interpreter.values.BooleanInterpreterValue;
import org.zwobble.couscous.interpreter.values.InterpreterValue;
import org.zwobble.couscous.interpreter.values.InterpreterValues;
import lombok.val;
-public class Evaluator implements ExpressionNodeVisitor<InterpreterValue> {
+public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
public static InterpreterValue eval(Environment environment, ExpressionNode expression) {
return new Evaluator(environment).eval(expression);
}
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Executor.java b/src/main/java/org/zwobble/couscous/interpreter/Executor.java
index 4ed4a04..93adf16 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Executor.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java
@@ -10,7 +10,7 @@ import org.zwobble.couscous.ast.MethodNode;
import org.zwobble.couscous.ast.ReturnNode;
import org.zwobble.couscous.ast.StatementNode;
import org.zwobble.couscous.ast.VariableNode;
-import org.zwobble.couscous.ast.visitors.StatementNodeVisitor;
+import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
import org.zwobble.couscous.interpreter.values.InterpreterValue;
import org.zwobble.couscous.interpreter.values.UnitInterpreterValue;
@@ -18,7 +18,7 @@ import static org.zwobble.couscous.interpreter.Evaluator.eval;
import lombok.val;
-public class Executor implements StatementNodeVisitor<Optional<InterpreterValue>> {
+public class Executor implements StatementNodeMapper<Optional<InterpreterValue>> {
public static InterpreterValue callMethod(Environment environment, MethodNode method, Arguments arguments) {
val innerEnvironment = buildEnvironment(environment, method, arguments);
@@ -49,7 +49,7 @@ public class Executor implements StatementNodeVisitor<Optional<InterpreterValue>
private static Stream<VariableNode> findDeclarations(List<StatementNode> body) {
return body.stream()
- .flatMap(statement -> statement.accept(new StatementNodeVisitor<Stream<VariableNode>>() {
+ .flatMap(statement -> statement.accept(new StatementNodeMapper<Stream<VariableNode>>() {
@Override
public Stream<VariableNode> visit(ReturnNode returnNode) {
return Stream.empty();
diff --git a/src/main/java/org/zwobble/couscous/util/ExtraLists.java b/src/main/java/org/zwobble/couscous/util/ExtraLists.java
new file mode 100644
index 0000000..b3c017f
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/util/ExtraLists.java
@@ -0,0 +1,18 @@
+package org.zwobble.couscous.util;
+
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+public class ExtraLists {
+ public static <T, R> R foldLeft(
+ List<T> list,
+ Function<T, R> initialValue,
+ BiFunction<R, T, R> function) {
+ R accumulator = initialValue.apply(list.get(0));
+ for (int index = 1; index < list.size(); index++) {
+ accumulator = function.apply(accumulator, list.get(index));
+ }
+ return accumulator;
+ }
+}