diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-11-15 14:20:06 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-11-15 14:20:06 +0000 |
| commit | 549099039ef76a04ed524448c070a0c5328c52b2 (patch) | |
| tree | 14c8eea1b8874d339282d854c612622c73a844e7 | |
| parent | f4019f5ed78b0d9c0eb7c7a1b4d97e5c83003ff1 (diff) | |
Handle boxing for return statements
7 files changed, 111 insertions, 45 deletions
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java b/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java index 39bd058..5cd55d2 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonBackend.java @@ -19,6 +19,7 @@ import static org.zwobble.couscous.backends.python.PythonSerializer.serialize; public class PythonBackend implements Backend { private static final List<String> RUNTIME_FILES = asList( "java.lang.Object", + "java.lang.Boolean", "java.lang.Integer", "_couscous"); diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java index a54ca55..4f07149 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java @@ -4,11 +4,12 @@ import org.eclipse.jdt.core.dom.*; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ClassNodeBuilder; import org.zwobble.couscous.ast.StatementNode; +import org.zwobble.couscous.ast.TypeName; import java.io.IOException; import java.nio.file.Path; +import java.util.Optional; -import static org.zwobble.couscous.frontends.java.JavaStatementReader.readStatement; import static org.zwobble.couscous.frontends.java.JavaTypes.typeOf; public class JavaReader { @@ -63,8 +64,12 @@ public class JavaReader { SingleVariableDeclaration parameter = (SingleVariableDeclaration)parameterObject; builder.argument(parameter.resolveBinding().getKey(), parameter.getName().getIdentifier(), typeOf(parameter.resolveBinding())); } + Optional<TypeName> returnType = method.getReturnType2() == null + ? Optional.empty() + : Optional.of(typeOf(method.getReturnType2())); + JavaStatementReader statementReader = new JavaStatementReader(returnType); for (Object statement : method.getBody().statements()) { - for (StatementNode intermediateStatement : readStatement((Statement)statement)) { + for (StatementNode intermediateStatement : statementReader.readStatement((Statement)statement)) { builder.statement(intermediateStatement); } } diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java index c5194b4..a766cce 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java @@ -5,6 +5,7 @@ import org.zwobble.couscous.ast.*; import org.zwobble.couscous.values.BooleanValue; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import static java.util.Arrays.asList; @@ -16,8 +17,14 @@ import static org.zwobble.couscous.frontends.java.JavaExpressionReader.readExpre import static org.zwobble.couscous.frontends.java.JavaTypes.typeOf; import static org.zwobble.couscous.util.ExtraLists.eagerMap; -public class JavaStatementReader { - static List<StatementNode> readStatement(Statement statement) { +class JavaStatementReader { + private final Optional<TypeName> returnType; + + JavaStatementReader(Optional<TypeName> returnType) { + this.returnType = returnType; + } + + List<StatementNode> readStatement(Statement statement) { switch (statement.getNodeType()) { case ASTNode.BLOCK: return readBlock((Block)statement); @@ -42,7 +49,7 @@ public class JavaStatementReader { } } - private static List<StatementNode> readBlock(Block block) { + private List<StatementNode> readBlock(Block block) { @SuppressWarnings("unchecked") List<Statement> statements = block.statements(); return statements.stream() @@ -50,23 +57,22 @@ public class JavaStatementReader { .collect(Collectors.toList()); } - private static StatementNode readReturnStatement(ReturnStatement statement) { - // TODO: set target type - return ReturnNode.returns(readExpressionWithoutBoxing(statement.getExpression())); + private StatementNode readReturnStatement(ReturnStatement statement) { + return ReturnNode.returns(readExpression(returnType.get(), statement.getExpression())); } private static StatementNode readExpressionStatement(ExpressionStatement statement) { return expressionStatement(readExpressionWithoutBoxing(statement.getExpression())); } - private static StatementNode readIfStatement(IfStatement statement) { + private StatementNode readIfStatement(IfStatement statement) { return IfStatementNode.ifStatement( readExpression(BooleanValue.REF, statement.getExpression()), readStatement(statement.getThenStatement()), readStatement(statement.getElseStatement())); } - private static WhileNode readWhileStatement(WhileStatement statement) { + private WhileNode readWhileStatement(WhileStatement statement) { return whileLoop( readExpression(BooleanValue.REF, statement.getExpression()), readStatement(statement.getBody())); diff --git a/src/main/resources/python/runtime/_couscous.py b/src/main/resources/python/runtime/_couscous.py index 70d9a97..aa108a5 100644 --- a/src/main/resources/python/runtime/_couscous.py +++ b/src/main/resources/python/runtime/_couscous.py @@ -1,4 +1,5 @@ from .java.lang.Integer import Integer +from .java.lang.Boolean import Boolean def _div_round_to_zero(a, b): @@ -9,3 +10,6 @@ def _mod_round_to_zero(a, b): def boxInt(value): return Integer(value) + +def boxBoolean(value): + return Boolean(value)
\ No newline at end of file diff --git a/src/main/resources/python/runtime/java/lang/Boolean.py b/src/main/resources/python/runtime/java/lang/Boolean.py new file mode 100644 index 0000000..6e08f29 --- /dev/null +++ b/src/main/resources/python/runtime/java/lang/Boolean.py @@ -0,0 +1,13 @@ +class Boolean(object): + def __init__(self, value): + self._value = value + + def equals(self, other): + # TODO: test this properly + return isinstance(other, Boolean) and other._value == self._value + + def __str__(self): + return str(self._value) + + def __repr__(self): + return str(self)
\ No newline at end of file diff --git a/src/main/resources/python/runtime/java/lang/Integer.py b/src/main/resources/python/runtime/java/lang/Integer.py index e16e7bb..8ea30a4 100644 --- a/src/main/resources/python/runtime/java/lang/Integer.py +++ b/src/main/resources/python/runtime/java/lang/Integer.py @@ -9,3 +9,9 @@ class Integer(object): def equals(self, other): # TODO: test this properly return isinstance(other, Integer) and other._value == self._value + + def __str__(self): + return str(self._value) + + def __repr__(self): + return str(self)
\ No newline at end of file diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java index ad2f755..ad8bcbb 100644 --- a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java +++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java @@ -40,10 +40,10 @@ import static org.zwobble.couscous.tests.util.ExtraFiles.deleteRecursively; public class JavaReaderTests { @Test public void canReadLiterals() { - assertEquals(literal("hello"), readExpression("\"hello\"")); - assertEquals(literal(true), readExpression("true")); - assertEquals(literal(false), readExpression("false")); - assertEquals(literal(42), readExpression("42")); + assertEquals(literal("hello"), readObjectExpression("\"hello\"")); + assertEquals(literal(true), readBooleanExpression("true")); + assertEquals(literal(false), readBooleanExpression("false")); + assertEquals(literal(42), readIntExpression("42")); } @Test @@ -93,9 +93,9 @@ public class JavaReaderTests { public void canReadInstanceMethodCalls() { assertEquals( methodCall(literal("hello"), "startsWith", asList(literal("h")), BooleanValue.REF), - readExpression("\"hello\".startsWith(\"h\")")); + readBooleanExpression("\"hello\".startsWith(\"h\")")); - List<StatementNode> statements = readStatements("Object x = 1; return x.hashCode();"); + List<StatementNode> statements = readStatements("int", "Object x = 1; return x.hashCode();"); LocalVariableDeclarationNode declaration = (LocalVariableDeclarationNode) statements.get(0); ReturnNode returnNode = (ReturnNode) statements.get(1); assertEquals( @@ -128,7 +128,7 @@ public class JavaReaderTests { "parseInt", asList(literal("42")), IntegerValue.REF), - readExpression("Integer.parseInt(\"42\")")); + readIntExpression("Integer.parseInt(\"42\")")); } @Test @@ -152,12 +152,12 @@ public class JavaReaderTests { public void canReadConstructorCalls() { assertEquals( constructorCall(TypeName.of("java.lang.String"), asList(literal("_"))), - readExpression("new String(\"_\")")); + readObjectExpression("new String(\"_\")")); } @Test public void argumentIsBoxedIfNecessary() { - StaticMethodCallNode expression = (StaticMethodCallNode)readExpression( + StaticMethodCallNode expression = (StaticMethodCallNode) readObjectExpression( "java.util.Objects.toString(42)"); assertEquals( boxInt(literal(42)), @@ -170,51 +170,51 @@ public class JavaReaderTests { same( constructorCall(TypeName.of("java.lang.Object"), emptyList()), constructorCall(TypeName.of("java.lang.Object"), emptyList())), - readExpression("new Object() == new Object()")); + readBooleanExpression("new Object() == new Object()")); assertEquals( not(same( constructorCall(TypeName.of("java.lang.Object"), emptyList()), constructorCall(TypeName.of("java.lang.Object"), emptyList()))), - readExpression("new Object() != new Object()")); + readBooleanExpression("new Object() != new Object()")); } @Test public void canUseOperatorsOnIntegers() { assertEquals( integerAdd(literal(1), literal(2)), - readExpression("1 + 2")); + readIntExpression("1 + 2")); assertEquals( integerSubtract(literal(1), literal(2)), - readExpression("1 - 2")); + readIntExpression("1 - 2")); assertEquals( integerMultiply(literal(1), literal(2)), - readExpression("1 * 2")); + readIntExpression("1 * 2")); assertEquals( integerDivide(literal(1), literal(2)), - readExpression("1 / 2")); + readIntExpression("1 / 2")); assertEquals( integerMod(literal(1), literal(2)), - readExpression("1 % 2")); + readIntExpression("1 % 2")); assertEquals( equal(literal(1), literal(2)), - readExpression("1 == 2")); + readBooleanExpression("1 == 2")); assertEquals( notEqual(literal(1), literal(2)), - readExpression("1 != 2")); + readBooleanExpression("1 != 2")); assertEquals( greaterThan(literal(1), literal(2)), - readExpression("1 > 2")); + readBooleanExpression("1 > 2")); assertEquals( greaterThanOrEqual(literal(1), literal(2)), - readExpression("1 >= 2")); + readBooleanExpression("1 >= 2")); assertEquals( lessThan(literal(1), literal(2)), - readExpression("1 < 2")); + readBooleanExpression("1 < 2")); assertEquals( lessThanOrEqual(literal(1), literal(2)), - readExpression("1 <= 2")); + readBooleanExpression("1 <= 2")); } @Test @@ -223,13 +223,13 @@ public class JavaReaderTests { equal( literal(1), unboxInt(constructorCall(TypeName.of("java.lang.Integer"), asList(literal(1))))), - readExpression("1 == new Integer(1)")); + readBooleanExpression("1 == new Integer(1)")); assertEquals( notEqual( literal(1), unboxInt(constructorCall(TypeName.of("java.lang.Integer"), asList(literal(1))))), - readExpression("1 != new Integer(1)")); + readBooleanExpression("1 != new Integer(1)")); } @Test @@ -238,13 +238,13 @@ public class JavaReaderTests { same( constructorCall(TypeName.of("java.lang.Integer"), asList(literal(1))), constructorCall(TypeName.of("java.lang.Integer"), asList(literal(2)))), - readExpression("new Integer(1) == new Integer(2)")); + readBooleanExpression("new Integer(1) == new Integer(2)")); assertEquals( not(same( constructorCall(TypeName.of("java.lang.Integer"), asList(literal(1))), constructorCall(TypeName.of("java.lang.Integer"), asList(literal(2))))), - readExpression("new Integer(1) != new Integer(2)")); + readBooleanExpression("new Integer(1) != new Integer(2)")); } @Test @@ -253,14 +253,14 @@ public class JavaReaderTests { integerAdd( unboxInt(constructorCall(TypeName.of("java.lang.Integer"), asList(literal(1)))), unboxInt(constructorCall(TypeName.of("java.lang.Integer"), asList(literal(2))))), - readExpression("new Integer(1) + new Integer(2)")); + readIntExpression("new Integer(1) + new Integer(2)")); } @Test public void canReadTernaryConditionals() { assertEquals( ternaryConditional(literal(true), literal(1), literal(2)), - readExpression("true ? 1 : 2")); + readIntExpression("true ? 1 : 2")); } @Test @@ -303,7 +303,7 @@ public class JavaReaderTests { @Test public void canDeclareAndReferenceLocalVariables() { - List<StatementNode> statements = readStatements("int x = 4; return x;"); + List<StatementNode> statements = readStatements("int", "int x = 4; return x;"); LocalVariableDeclarationNode declaration = (LocalVariableDeclarationNode) statements.get(0); assertEquals("x", declaration.getName()); @@ -360,7 +360,7 @@ public class JavaReaderTests { @Test public void canDeclareAndReferenceArguments() { ClassNode classNode = readClass( - "public String identity(int value) {" + + "public int identity(int value) {" + " return value;" + "}"); @@ -493,7 +493,7 @@ public class JavaReaderTests { literal(true), asList(returns(literal(1))), asList(returns(literal(2)))), - readStatement("if (true) { return 1; } else { return 2; }")); + readStatement("int", "if (true) { return 1; } else { return 2; }")); } @Test @@ -502,7 +502,7 @@ public class JavaReaderTests { whileLoop( literal(true), asList(returns(literal(1)))), - readStatement("while (true) { return 1; }")); + readStatement("int", "while (true) { return 1; }")); } @Test @@ -538,6 +538,17 @@ public class JavaReaderTests { method.getAnnotations()); } + @Test + public void returnValueHandlesBoxing() { + ClassNode classNode = readClass( + "public Integer one() { return 1; }"); + + MethodNode method = classNode.getMethods().get(0); + assertEquals( + asList(returns(boxInt(literal(1)))), + method.getBody()); + } + private ExpressionNode readExpressionInInstanceMethod(String expressionSource) { String javaClass = "public Object main() {" + @@ -549,8 +560,20 @@ public class JavaReaderTests { return returnStatement.getValue(); } - private ExpressionNode readExpression(String expressionSource) { - ReturnNode returnStatement = (ReturnNode) readStatement("return " + expressionSource + ";"); + private ExpressionNode readObjectExpression(String expressionSource) { + return readExpression("Object", expressionSource); + } + + private ExpressionNode readBooleanExpression(String expressionSource) { + return readExpression("boolean", expressionSource); + } + + private ExpressionNode readIntExpression(String expressionSource) { + return readExpression("int", expressionSource); + } + + private ExpressionNode readExpression(String returnType, String expressionSource) { + ReturnNode returnStatement = (ReturnNode) readStatement(returnType, "return " + expressionSource + ";"); return returnStatement.getValue(); } @@ -558,9 +581,17 @@ public class JavaReaderTests { return readStatements(statementSource).get(0); } + private StatementNode readStatement(String returnType, String statementSource) { + return readStatements(returnType, statementSource).get(0); + } + private List<StatementNode> readStatements(String statementsSource) { + return readStatements("Object", statementsSource); + } + + private List<StatementNode> readStatements(String returnType, String statementsSource) { String javaClass = - "public static Object main() {" + + "public static " + returnType + " main() {" + statementsSource + "}"; |
