From f8824d99ce826ebf83498dbce2bbf1d98472a9e3 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Tue, 6 Oct 2015 11:52:26 +0100 Subject: Support user-defined static methods in Python backend --- .../zwobble/couscous/tests/BackendEvalTests.java | 27 +++++++++++++++++- .../zwobble/couscous/tests/BackendMethodTests.java | 6 +++- .../org/zwobble/couscous/tests/MethodRunner.java | 7 ++++- .../backends/python/PythonCompilerEvalTests.java | 24 ++++++++++++---- .../tests/backends/python/PythonMethodRunner.java | 11 ++++---- .../couscous/tests/interpreter/EvaluatorTests.java | 33 +++++++--------------- .../tests/interpreter/InterpreterMethodTests.java | 16 +++++------ 7 files changed, 79 insertions(+), 45 deletions(-) (limited to 'src/test') diff --git a/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java b/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java index e2ce667..ebfbd88 100644 --- a/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java +++ b/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java @@ -1,12 +1,19 @@ package org.zwobble.couscous.tests; +import java.util.List; + import org.junit.Test; +import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ExpressionNode; +import org.zwobble.couscous.ast.MethodNode; +import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.TernaryConditionalNode; import org.zwobble.couscous.values.IntegerValue; import org.zwobble.couscous.values.PrimitiveValue; import org.zwobble.couscous.values.StringValue; +import com.google.common.collect.ImmutableList; + import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.zwobble.couscous.ast.LiteralNode.literal; @@ -64,5 +71,23 @@ public abstract class BackendEvalTests { assertEquals(value(42), result); } - protected abstract PrimitiveValue evalExpression(ExpressionNode expression); + @Test + public void canCallStaticMethodFromUserDefinedStaticMethod() { + val classNode = ClassNode.builder("com.example.Example") + .method(MethodNode.staticMethod("main") + .statement(new ReturnNode(staticMethodCall("java.lang.Integer", "parseInt", literal("42")))) + .build()) + .build(); + val result = evalExpression(asList(classNode), + staticMethodCall("com.example.Example", "main")); + assertEquals(value(42), result); + } + + protected PrimitiveValue evalExpression(ExpressionNode expression) { + return evalExpression(ImmutableList.of(), expression); + } + + protected abstract PrimitiveValue evalExpression( + List classes, + ExpressionNode expression); } diff --git a/src/test/java/org/zwobble/couscous/tests/BackendMethodTests.java b/src/test/java/org/zwobble/couscous/tests/BackendMethodTests.java index b55a2ca..fd6d91e 100644 --- a/src/test/java/org/zwobble/couscous/tests/BackendMethodTests.java +++ b/src/test/java/org/zwobble/couscous/tests/BackendMethodTests.java @@ -96,7 +96,11 @@ public abstract class BackendMethodTests { .build(); val runner = buildMethodRunner(); - return runner.runMethod(classNode, method.getName(), asList(arguments)); + return runner.runMethod( + asList(classNode), + classNode.getName(), + method.getName(), + asList(arguments)); } protected abstract MethodRunner buildMethodRunner(); diff --git a/src/test/java/org/zwobble/couscous/tests/MethodRunner.java b/src/test/java/org/zwobble/couscous/tests/MethodRunner.java index ff9439c..3f69779 100644 --- a/src/test/java/org/zwobble/couscous/tests/MethodRunner.java +++ b/src/test/java/org/zwobble/couscous/tests/MethodRunner.java @@ -3,8 +3,13 @@ package org.zwobble.couscous.tests; import java.util.List; import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.TypeName; import org.zwobble.couscous.values.PrimitiveValue; public interface MethodRunner { - PrimitiveValue runMethod(ClassNode classNode, String methodName, List arguments); + PrimitiveValue runMethod( + List classNodes, + TypeName className, + String methodName, + List arguments); } diff --git a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerEvalTests.java b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerEvalTests.java index 6f19eb3..e4a5ddf 100644 --- a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerEvalTests.java +++ b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonCompilerEvalTests.java @@ -1,5 +1,7 @@ package org.zwobble.couscous.tests.backends.python; +import java.util.List; + import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ExpressionNode; import org.zwobble.couscous.ast.MethodNode; @@ -8,19 +10,29 @@ import org.zwobble.couscous.tests.BackendEvalTests; import org.zwobble.couscous.values.PrimitiveValue; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +import static java.util.Arrays.asList; import lombok.val; public class PythonCompilerEvalTests extends BackendEvalTests { @Override - protected PrimitiveValue evalExpression(ExpressionNode expression) { + protected PrimitiveValue evalExpression( + List classes, + ExpressionNode expression) { + + val programNode = ClassNode.builder("Program") + .method(MethodNode.staticMethod("run") + .statement(new ReturnNode(expression)) + .build()) + .build(); + val runner = new PythonMethodRunner(); + return runner.runMethod( - ClassNode.builder("Program") - .method(MethodNode.staticMethod("run") - .statement(new ReturnNode(expression)) - .build()) - .build(), + ImmutableList.copyOf(Iterables.concat(classes, asList(programNode))), + programNode.getName(), "run", ImmutableList.of()); } diff --git a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java index 73c1c52..33de465 100644 --- a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java +++ b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java @@ -7,6 +7,7 @@ import java.nio.file.Files; import java.util.List; import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.TypeName; import org.zwobble.couscous.backends.python.PythonCodeGenerator; import org.zwobble.couscous.backends.python.PythonCompiler; import org.zwobble.couscous.backends.python.PythonSerializer; @@ -19,7 +20,6 @@ import com.google.common.base.Joiner; 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.PrimitiveValues.value; @@ -30,21 +30,22 @@ public class PythonMethodRunner implements MethodRunner { @Override @SneakyThrows public PrimitiveValue runMethod( - ClassNode classNode, + List classNodes, + TypeName className, String methodName, List arguments) { val directoryPath = Files.createTempDirectory(null); val compiler = new PythonCompiler(directoryPath); try { - compiler.compile(asList(classNode)); + compiler.compile(classNodes); val argumentsString = Joiner.on(", ").join(arguments.stream() .map(PythonCodeGenerator::generateCode) .map(PythonSerializer::serialize) .iterator()); - val program = "from " + classNode.getName().getQualifiedName() + " import " + classNode.getSimpleName() + - ";print(repr(" + classNode.getSimpleName() + "." + methodName + "(" + argumentsString + ")))"; + val program = "from " + className.getQualifiedName() + " import " + className.getSimpleName() + + ";print(repr(" + className.getSimpleName() + "." + methodName + "(" + argumentsString + ")))"; val process = new ProcessBuilder("python3.4", "-c", program) .directory(directoryPath.toFile()) diff --git a/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java b/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java index bc6a205..4ec8428 100644 --- a/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java +++ b/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java @@ -1,12 +1,12 @@ package org.zwobble.couscous.tests.interpreter; +import java.util.List; + import org.junit.Test; import org.zwobble.couscous.JavaProject; import org.zwobble.couscous.MapBackedProject; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ExpressionNode; -import org.zwobble.couscous.ast.MethodNode; -import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.TernaryConditionalNode; import org.zwobble.couscous.interpreter.ConditionMustBeBoolean; import org.zwobble.couscous.interpreter.Environment; @@ -14,7 +14,6 @@ import org.zwobble.couscous.interpreter.NoSuchMethod; import org.zwobble.couscous.interpreter.StackFrameBuilder; import org.zwobble.couscous.interpreter.UnexpectedValueType; import org.zwobble.couscous.interpreter.WrongNumberOfArguments; -import org.zwobble.couscous.interpreter.values.ConcreteType; import org.zwobble.couscous.interpreter.values.IntegerInterpreterValue; import org.zwobble.couscous.interpreter.values.StringInterpreterValue; import org.zwobble.couscous.tests.BackendEvalTests; @@ -30,7 +29,6 @@ import static org.zwobble.couscous.ast.AssignmentNode.assign; import static org.zwobble.couscous.ast.FormalArgumentNode.formalArg; import static org.zwobble.couscous.ast.LiteralNode.literal; import static org.zwobble.couscous.ast.MethodCallNode.methodCall; -import static org.zwobble.couscous.ast.StaticMethodCallNode.staticMethodCall; import static org.zwobble.couscous.ast.VariableDeclaration.var; import static org.zwobble.couscous.interpreter.Evaluator.eval; import static org.zwobble.couscous.interpreter.values.InterpreterValues.value; @@ -93,23 +91,6 @@ public class EvaluatorTests extends BackendEvalTests { assertEquals(new UnexpectedValueType(IntegerValue.REF, StringValue.REF), exception); } - @Test - public void canCallStaticMethodFromAnotherStaticMethod() { - val classNode = ClassNode.builder("com.example.Program") - .method(MethodNode.staticMethod("main") - .statement(new ReturnNode(staticMethodCall("java.lang.Integer", "parseInt", literal("42")))) - .build()) - .build(); - val environment = new Environment( - JavaProject.builder() - .addClass(ConcreteType.fromNode(classNode)) - .build(), - ImmutableMap.of()); - val result = eval(environment, - staticMethodCall("com.example.Program", "main")); - assertEquals(new IntegerInterpreterValue(42), result); - } - private static Environment emptyEnvironment() { return new Environment( JavaProject.builder().build(), @@ -117,7 +98,13 @@ public class EvaluatorTests extends BackendEvalTests { } @Override - protected PrimitiveValue evalExpression(ExpressionNode expression) { - return eval(emptyEnvironment(), expression).toPrimitiveValue().get(); + protected PrimitiveValue evalExpression( + List classes, + ExpressionNode expression) { + + val environment = new Environment( + JavaProject.of(classes), + ImmutableMap.of()); + return eval(environment, expression).toPrimitiveValue().get(); } } diff --git a/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java b/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java index 26939dc..449a251 100644 --- a/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java +++ b/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java @@ -4,18 +4,18 @@ import java.util.List; import java.util.stream.Collectors; import org.junit.Test; -import org.zwobble.couscous.MapBackedProject; +import org.zwobble.couscous.JavaProject; 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.ReturnNode; +import org.zwobble.couscous.ast.TypeName; import org.zwobble.couscous.interpreter.Interpreter; import org.zwobble.couscous.interpreter.UnboundVariable; import org.zwobble.couscous.interpreter.UnexpectedValueType; import org.zwobble.couscous.interpreter.VariableNotInScope; import org.zwobble.couscous.interpreter.WrongNumberOfArguments; -import org.zwobble.couscous.interpreter.values.ConcreteType; import org.zwobble.couscous.interpreter.values.InterpreterValues; import org.zwobble.couscous.tests.BackendMethodTests; import org.zwobble.couscous.tests.MethodRunner; @@ -23,8 +23,6 @@ import org.zwobble.couscous.values.IntegerValue; import org.zwobble.couscous.values.PrimitiveValue; import org.zwobble.couscous.values.StringValue; -import com.google.common.collect.ImmutableMap; - import static org.junit.Assert.assertEquals; import static org.zwobble.couscous.ast.FormalArgumentNode.formalArg; import static org.zwobble.couscous.ast.LiteralNode.literal; @@ -106,16 +104,18 @@ public class InterpreterMethodTests extends BackendMethodTests { return new MethodRunner() { @Override public PrimitiveValue runMethod( - ClassNode classNode, + List classNodes, + TypeName className, String methodName, List arguments) { - val interpreter = new Interpreter(new MapBackedProject(ImmutableMap.of( - classNode.getName(), ConcreteType.fromNode(classNode)))); + + val project = JavaProject.of(classNodes); + val interpreter = new Interpreter(project); val argumentValues = arguments.stream() .map(InterpreterValues::value) .collect(Collectors.toList()); - return interpreter.run(classNode.getName(), methodName, argumentValues) + return interpreter.run(className, methodName, argumentValues) .toPrimitiveValue().get(); } }; -- cgit v1.2.3