From 9fb39b1cff12bb2ec80ac9cd798f8a50069f4afc Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Fri, 22 Apr 2016 22:16:11 +0100 Subject: Handle try-with-resources --- .../frontends/java/JavaStatementReader.java | 42 +++++++++++++++------- .../java/org/zwobble/couscous/util/ExtraLists.java | 2 +- .../tests/frontends/java/JavaReaderTests.java | 29 ++++++++++++++- .../couscous/tests/frontends/java/JavaReading.java | 2 +- .../tests/frontends/java/NodeMatchers.java | 5 +++ 5 files changed, 65 insertions(+), 15 deletions(-) (limited to 'src') 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 c3c4f21..e75585f 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java @@ -1,5 +1,6 @@ package org.zwobble.couscous.frontends.java; +import com.google.common.collect.Lists; import org.eclipse.jdt.core.dom.*; import org.zwobble.couscous.ast.*; import org.zwobble.couscous.ast.sugar.SwitchCaseNode; @@ -167,11 +168,24 @@ class JavaStatementReader { private List readTryStatement(TryStatement statement) { @SuppressWarnings("unchecked") - List catchClauses = statement.catchClauses(); - return list(tryStatement( - readStatement(statement.getBody()), - eagerMap(catchClauses, this::readCatchClause), - statement.getFinally() == null ? list() : readStatement(statement.getFinally()))); + List resources = statement.resources(); + List resourceDeclarations = eagerFlatMap(resources, this::readVariableDeclarationExpression); + List body = readStatement(statement.getBody()); + for (LocalVariableDeclarationNode resource : Lists.reverse(resourceDeclarations)) { + body = list( + resource, + tryStatement(body, list(), list(expressionStatement(methodCall(reference(resource), "close", list(), Types.VOID)))) + ); + } + @SuppressWarnings("unchecked") + List javaCatchClauses = statement.catchClauses(); + List catchClauses = eagerMap(javaCatchClauses, this::readCatchClause); + List finallyBody = statement.getFinally() == null ? list() : readStatement(statement.getFinally()); + if (catchClauses.isEmpty() && finallyBody.isEmpty()) { + return body; + } else { + return list(tryStatement(body, catchClauses, finallyBody)); + } } private ExceptionHandlerNode readCatchClause(CatchClause clause) { @@ -191,18 +205,16 @@ class JavaStatementReader { } private List readForStatement(ForStatement statement) { - List javaInitialisers = statement.initializers(); + @SuppressWarnings("unchecked") + List javaInitialisers = statement.initializers(); if (javaInitialisers.size() != 1) { throw new UnsupportedOperationException(); } - VariableDeclarationExpression javaDeclaration = (VariableDeclarationExpression) javaInitialisers.get(0); - @SuppressWarnings("unchecked") - List fragments = javaDeclaration.fragments(); @SuppressWarnings("unchecked") List updaters = statement.updaters(); return append( - readDeclarationFragments(fragments, typeOf(javaDeclaration.getType())), + readVariableDeclarationExpression(javaInitialisers.get(0)), whileLoop( readExpression(Types.BOOLEAN, statement.getExpression()), concat( @@ -232,10 +244,16 @@ class JavaStatementReader { @SuppressWarnings("unchecked") List fragments = statement.fragments(); Type type = typeOf(statement.getType()); - return readDeclarationFragments(fragments, type); + return (List)readDeclarationFragments(fragments, type); + } + + private List readVariableDeclarationExpression(VariableDeclarationExpression expression) { + @SuppressWarnings("unchecked") + List fragments = expression.fragments(); + return readDeclarationFragments(fragments, typeOf(expression.getType())); } - private List readDeclarationFragments( + private List readDeclarationFragments( List fragments, Type type ) { diff --git a/src/main/java/org/zwobble/couscous/util/ExtraLists.java b/src/main/java/org/zwobble/couscous/util/ExtraLists.java index 3ee0ce3..76d3de7 100644 --- a/src/main/java/org/zwobble/couscous/util/ExtraLists.java +++ b/src/main/java/org/zwobble/couscous/util/ExtraLists.java @@ -33,7 +33,7 @@ public class ExtraLists { return concat(list(value), list); } - public static List append(List list, T value) { + public static List append(List list, T value) { return Stream.concat(list.stream(), Stream.of(value)).collect(Collectors.toList()); } 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 8225baa..35756f5 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 @@ -10,6 +10,7 @@ import org.zwobble.couscous.types.Types; import java.util.List; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -23,12 +24,14 @@ import static org.zwobble.couscous.ast.FormalTypeParameterNode.formalTypeParamet import static org.zwobble.couscous.ast.IfStatementNode.ifStatement; import static org.zwobble.couscous.ast.LiteralNode.literal; import static org.zwobble.couscous.ast.LocalVariableDeclarationNode.localVariableDeclaration; +import static org.zwobble.couscous.ast.MethodCallNode.methodCall; import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall; import static org.zwobble.couscous.ast.Operations.boxInt; import static org.zwobble.couscous.ast.Operations.integerAdd; import static org.zwobble.couscous.ast.ReturnNode.returns; import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference; import static org.zwobble.couscous.ast.ThrowNode.throwNode; +import static org.zwobble.couscous.ast.TryNode.tryStatement; import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion; import static org.zwobble.couscous.ast.VariableReferenceNode.reference; import static org.zwobble.couscous.ast.WhileNode.whileLoop; @@ -209,7 +212,31 @@ public class JavaReaderTests { hasTryBody(list(returns(literal(1)))), hasFinally(returns(literal(2))))); } - + + @Test + public void canReadTryWithResourceWithoutOtherClauses() { + ScalarType type = ScalarType.of("java.io.ByteArrayOutputStream"); + Identifier identifier = Identifiers.variable( + Identifiers.method( + Identifiers.type(Identifiers.TOP, "com.example.Example"), + "main" + ), + "closeable" + ); + LocalVariableDeclarationNode expectedResource = localVariableDeclaration(identifier, "closeable", type, constructorCall(type, list())); + assertThat( + readStatements("int", "try(java.io.ByteArrayOutputStream closeable = new java.io.ByteArrayOutputStream()) { return 1; }"), + equalTo(list( + expectedResource, + tryStatement( + list(returns(literal(1))), + list(), + list(expressionStatement(methodCall(reference(expectedResource), "close", list(), Types.VOID))) + ) + )) + ); + } + @Test public void canDeclareConstructor() { ClassNode classNode = readClass( diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReading.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReading.java index a7dc180..e64de11 100644 --- a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReading.java +++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReading.java @@ -76,7 +76,7 @@ public class JavaReading { } static String generateMethodSource(String returnType, String statementsSource) { - return "public static " + returnType + " main() {" + + return "public static " + returnType + " main() throws Exception {" + statementsSource + "}"; } diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java index 5a39e82..e9c77f0 100644 --- a/src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java +++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/NodeMatchers.java @@ -57,6 +57,11 @@ public class NodeMatchers { return hasFeature("type", ExpressionNode::getType, equalTo(type)); } + @SafeVarargs + public static Matcher isLocalVariableDeclaration(Matcher... matchers) { + return isInstance(LocalVariableDeclarationNode.class, allOf(matchers)); + } + @SafeVarargs public static Matcher isTryStatement(Matcher... matchers) { return isInstance(TryNode.class, allOf(matchers)); -- cgit v1.2.3