diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-10-05 11:04:17 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-10-05 11:04:17 +0100 |
| commit | 96b1e6f776ae8ce8910c44a3bbec0b489fd10c88 (patch) | |
| tree | 86658222ef741b1620c1635d3fd98d99452a387b /src/test/java/org/zwobble/couscous/tests/backends/python | |
| parent | cdf51cdb9b3f8cef5896315496f348d9f7220903 (diff) | |
Add the beginnings of a Python backend
Diffstat (limited to 'src/test/java/org/zwobble/couscous/tests/backends/python')
| -rw-r--r-- | src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerTests.java | 70 | ||||
| -rw-r--r-- | src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java | 80 |
2 files changed, 150 insertions, 0 deletions
diff --git a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerTests.java b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerTests.java new file mode 100644 index 0000000..7419aca --- /dev/null +++ b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerTests.java @@ -0,0 +1,70 @@ +package org.zwobble.couscous.tests.backends.python; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.util.List; + +import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.backends.python.PythonCompiler; +import org.zwobble.couscous.tests.BackendTests; +import org.zwobble.couscous.tests.MethodRunner; +import org.zwobble.couscous.values.InterpreterValue; + +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; + +import static java.lang.Integer.parseInt; +import static java.util.Arrays.asList; +import static org.zwobble.couscous.tests.util.ExtraFiles.deleteRecursively; +import static org.zwobble.couscous.values.InterpreterValues.UNIT; +import static org.zwobble.couscous.values.InterpreterValues.value; + +import lombok.SneakyThrows; +import lombok.val; + +public class PythonCompilerTests extends BackendTests { + @Override + protected MethodRunner buildMethodRunner() { + return new MethodRunner() { + @Override + @SneakyThrows + public InterpreterValue runMethod( + ClassNode classNode, + String methodName, + List<InterpreterValue> arguments) { + val compiler = new PythonCompiler(); + val directoryPath = Files.createTempDirectory(null); + try { + compiler.compile(asList(classNode), directoryPath); + + val program = "from " + classNode.getName() + " import " + classNode.getLocalName() + + ";print(repr(" + classNode.getLocalName() + "." + methodName + "()))"; + + val process = new ProcessBuilder("python3.4", "-c", program) + .directory(directoryPath.toFile()) + .start(); + val exitCode = process.waitFor(); + val output = readString(process.getInputStream()).trim(); + val stderrOutput = readString(process.getErrorStream()); + if (exitCode != 0) { + throw new RuntimeException("stderr was: " + stderrOutput); + } else if (output.equals("None")) { + return UNIT; + } else if (output.startsWith("'")) { + return value(output.substring(1, output.length() - 1)); + } else { + return value(parseInt(output)); + } + } finally { + deleteRecursively(directoryPath.toFile()); + } + } + + private String readString(final InputStream stream) throws IOException { + return CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8)); + } + }; + } +} diff --git a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java new file mode 100644 index 0000000..4f9b63b --- /dev/null +++ b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java @@ -0,0 +1,80 @@ +package org.zwobble.couscous.tests.backends.python; + +import org.junit.Test; +import org.zwobble.couscous.backends.python.ast.PythonClassNode; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; +import static org.zwobble.couscous.backends.python.PythonSerializer.serialize; +import static org.zwobble.couscous.backends.python.ast.PythonFunctionDefinitionNode.pythonFunctionDefinition; +import static org.zwobble.couscous.backends.python.ast.PythonIntegerLiteralNode.pythonIntegerLiteral; +import static org.zwobble.couscous.backends.python.ast.PythonModuleNode.pythonModule; +import static org.zwobble.couscous.backends.python.ast.PythonPassNode.PASS; +import static org.zwobble.couscous.backends.python.ast.PythonReturnNode.pythonReturn; +import static org.zwobble.couscous.backends.python.ast.PythonStringLiteralNode.pythonStringLiteral; + +import lombok.val; + +public class PythonSerializerTests { + @Test + public void integersAreNotBoxed() { + val output = serialize(pythonIntegerLiteral(42)); + assertEquals("42", output); + } + + @Test + public void stringsAreNotBoxed() { + // TODO: escaping + val output = serialize(pythonStringLiteral("blah")); + assertEquals("\"blah\"", output); + } + + @Test + public void returnKeywordIsUsedForReturns() { + val output = serialize(pythonReturn(pythonIntegerLiteral(42))); + assertEquals("return 42\n", output); + } + + @Test + public void passStatementIsSerializedAsPassKeyword() { + val output = serialize(PASS); + assertEquals("pass\n", output); + } + + @Test + public void emptyFunctionHasPassStatement() { + val output = serialize(pythonFunctionDefinition("empty", asList())); + assertEquals("def empty():\n pass\n", output); + } + + @Test + public void emptyClassHasPassStatement() { + val classNode = PythonClassNode.builder("Empty") + .build(); + val output = serialize(classNode); + assertEquals("class Empty(object):\n pass\n", output); + } + + @Test + public void moduleIsSerializedStatements() { + val classNode = pythonModule(asList(PASS)); + val output = serialize(classNode); + assertEquals("pass\n", output); + } + + @Test + public void bodiesOfBlocksAreIndented() { + val classNode = PythonClassNode.builder("Foo") + .statement(pythonFunctionDefinition("one", asList())) + .statement(pythonFunctionDefinition("two", asList())) + .build(); + val output = serialize(classNode); + val expectedOutput = + "class Foo(object):\n" + + " def one():\n" + + " pass\n" + + " def two():\n" + + " pass\n"; + assertEquals(expectedOutput, output); + } +} |
