aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/couscous/backends/python
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/zwobble/couscous/backends/python')
-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
5 files changed, 108 insertions, 17 deletions
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);