diff options
11 files changed, 132 insertions, 1 deletions
diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java index 3cd778b..6e648e6 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpBackend.java @@ -18,7 +18,11 @@ public class CsharpBackend implements Backend { private static final List<String> RUNTIME_FILES = ImmutableList.of( "java/lang/Integer.cs", "java/lang/Object.cs", - "java/lang/String.cs"); + "java/lang/String.cs", + "java/util/Arrays.cs", + // TODO: implement Iterable/Iterator in Java + "java/lang/Iterable.cs", + "java/lang/Iterator.cs"); private final Path directoryPath; private final String namespace; 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 4185f88..83c10f4 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaStatementReader.java @@ -61,6 +61,9 @@ class JavaStatementReader { case ASTNode.FOR_STATEMENT: return readForStatement((ForStatement)statement); + case ASTNode.ENHANCED_FOR_STATEMENT: + return readEnhancedForStatement((EnhancedForStatement)statement); + case ASTNode.VARIABLE_DECLARATION_STATEMENT: return readVariableDeclarationStatement((VariableDeclarationStatement)statement); @@ -180,6 +183,24 @@ class JavaStatementReader { eagerMap(updaters, updater -> expressionStatement(readExpressionWithoutBoxing(updater)))))); } + private List<StatementNode> readEnhancedForStatement(EnhancedForStatement statement) { + SingleVariableDeclaration parameter = statement.getParameter(); + Type elementType = typeOf(parameter.getType()); + + ExpressionNode iterableValue = readExpression(JavaTypes.iterable(elementType), statement.getExpression()); + ExpressionNode iteratorValue = methodCall(iterableValue, "iterator", list(), JavaTypes.iterator(elementType)); + LocalVariableDeclarationNode iterator = scope.temporaryVariable(iteratorValue); + + ExpressionNode hasNext = methodCall(reference(iterator), "hasNext", list(), Types.BOOLEAN); + ExpressionNode next = methodCall(reference(iterator), "next", list(), elementType); + IVariableBinding parameterBinding = parameter.resolveBinding(); + WhileNode loop = whileLoop(hasNext, cons( + scope.localVariable(parameterBinding.getKey(), parameterBinding.getName(), elementType, next), + readStatement(statement.getBody()))); + + return list(iterator, loop); + } + private List<StatementNode> readVariableDeclarationStatement(VariableDeclarationStatement statement) { @SuppressWarnings("unchecked") List<VariableDeclarationFragment> fragments = statement.fragments(); diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java index 0148b9b..d63ec89 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java @@ -14,9 +14,11 @@ import java.util.Set; import static com.google.common.collect.Iterables.transform; import static java.util.Arrays.asList; +import static org.zwobble.couscous.types.ParameterizedType.parameterizedType; import static org.zwobble.couscous.types.Types.erasure; import static org.zwobble.couscous.util.Casts.tryCast; import static org.zwobble.couscous.util.ExtraLists.eagerMap; +import static org.zwobble.couscous.util.ExtraLists.list; public class JavaTypes { static Type typeOf(Expression expression) { @@ -119,4 +121,12 @@ public class JavaTypes { return Optional.empty(); } } + + public static Type iterable(Type elementType) { + return parameterizedType(ScalarType.of("java.lang.Iterable"), list(elementType)); + } + + public static Type iterator(Type elementType) { + return parameterizedType(ScalarType.of("java.lang.Iterator"), list(elementType)); + } } diff --git a/src/main/resources/csharp/runtime/java/lang/Iterable.cs b/src/main/resources/csharp/runtime/java/lang/Iterable.cs new file mode 100644 index 0000000..090b3e5 --- /dev/null +++ b/src/main/resources/csharp/runtime/java/lang/Iterable.cs @@ -0,0 +1,6 @@ +namespace Couscous.java.lang { + // TODO: implement in Java + internal interface Iterable<T> { + Iterator<T> iterator(); + } +} diff --git a/src/main/resources/csharp/runtime/java/lang/Iterator.cs b/src/main/resources/csharp/runtime/java/lang/Iterator.cs new file mode 100644 index 0000000..75d985f --- /dev/null +++ b/src/main/resources/csharp/runtime/java/lang/Iterator.cs @@ -0,0 +1,7 @@ +namespace Couscous.java.lang { + // TODO: implement in Java + internal interface Iterator<T> { + bool hasNext(); + T next(); + } +} diff --git a/src/main/resources/csharp/runtime/java/util/Arrays.cs b/src/main/resources/csharp/runtime/java/util/Arrays.cs new file mode 100644 index 0000000..6833582 --- /dev/null +++ b/src/main/resources/csharp/runtime/java/util/Arrays.cs @@ -0,0 +1,37 @@ +namespace Couscous.java.util { + internal static class Arrays { + internal static java.lang.Iterable<T> asList<T>(T[] values) { + return new _ArrayList<T>(values); + } + } + + internal class _ArrayList<T> : java.lang.Iterable<T> { + private readonly T[] values; + + internal _ArrayList(T[] values) { + this.values = values; + } + + public java.lang.Iterator<T> iterator() { + return new _ArrayIterator<T>(values); + } + } + + internal class _ArrayIterator<T> : java.lang.Iterator<T> { + private readonly T[] values; + private int nextIndex; + + internal _ArrayIterator(T[] values) { + this.values = values; + this.nextIndex = 0; + } + + public bool hasNext() { + return nextIndex < values.Length; + } + + public T next() { + return values[nextIndex++]; + } + } +} diff --git a/src/test/java/org/zwobble/couscous/tests/CompilerTests.java b/src/test/java/org/zwobble/couscous/tests/CompilerTests.java index 0099d26..7a60821 100644 --- a/src/test/java/org/zwobble/couscous/tests/CompilerTests.java +++ b/src/test/java/org/zwobble/couscous/tests/CompilerTests.java @@ -85,6 +85,18 @@ public abstract class CompilerTests { } @Test + public void forEach() throws Exception { + assertEquals( + value("abc"), + execTestProgram( + "for-each", + ScalarType.of("com.example.ForEach"), + "value", + list(), + Types.STRING)); + } + + @Test public void staticNestedClasses() throws Exception { assertEquals( value(42), diff --git a/src/test/java/org/zwobble/couscous/tests/JavaToInterpreterTests.java b/src/test/java/org/zwobble/couscous/tests/JavaToInterpreterTests.java index 2c8a1e6..209aaa8 100644 --- a/src/test/java/org/zwobble/couscous/tests/JavaToInterpreterTests.java +++ b/src/test/java/org/zwobble/couscous/tests/JavaToInterpreterTests.java @@ -1,6 +1,8 @@ package org.zwobble.couscous.tests; import com.google.common.collect.ImmutableList; +import org.junit.Ignore; +import org.junit.Test; import org.zwobble.couscous.ast.TypeNode; import org.zwobble.couscous.frontends.java.JavaFrontend; import org.zwobble.couscous.interpreter.Interpreter; @@ -20,6 +22,11 @@ import static com.google.common.collect.Iterables.transform; import static org.zwobble.couscous.util.ExtraLists.list; public class JavaToInterpreterTests extends CompilerTests { + @Test + @Ignore("WIP") + public void forEach() throws Exception { + } + @Override protected PrimitiveValue execProgram( Path directory, diff --git a/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java b/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java index f482d11..ba2e8b4 100644 --- a/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java +++ b/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java @@ -1,5 +1,7 @@ package org.zwobble.couscous.tests; +import org.junit.Ignore; +import org.junit.Test; import org.zwobble.couscous.CouscousCompiler; import org.zwobble.couscous.types.ScalarType; import org.zwobble.couscous.backends.python.PythonBackend; @@ -16,6 +18,11 @@ import static org.zwobble.couscous.tests.util.ExtraFiles.deleteRecursively; import static org.zwobble.couscous.util.ExtraLists.list; public class JavaToPythonTests extends CompilerTests { + @Test + @Ignore("WIP") + public void forEach() throws Exception { + } + protected PrimitiveValue execProgram( Path directory, ScalarType type, 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 739d664..a1b60e9 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 @@ -10,6 +10,10 @@ import static org.zwobble.couscous.tests.util.ExtraMatchers.hasFeature; import static org.zwobble.couscous.tests.util.ExtraMatchers.isInstance; public class NodeMatchers { + public static Matcher<LocalVariableDeclarationNode> declarationHasValue(Matcher<ExpressionNode> matcher) { + return hasFeature("initial value", node -> node.getInitialValue(), matcher); + } + @SafeVarargs public static Matcher<ExpressionNode> isFieldAccess(Matcher<? super FieldAccessNode>... matchers) { return isInstance(FieldAccessNode.class, allOf(matchers)); diff --git a/src/test/resources/java/for-each/com/example/ForEach.java b/src/test/resources/java/for-each/com/example/ForEach.java new file mode 100644 index 0000000..807927d --- /dev/null +++ b/src/test/resources/java/for-each/com/example/ForEach.java @@ -0,0 +1,16 @@ +package com.example; + +import static java.util.Arrays.asList; + +public class ForEach { + public static String value() { + Iterable<String> values = asList("a", "b", "c"); + String result = ""; + + for (String value : values) { + result += value; + } + + return result; + } +} |
