aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-03-29 19:56:41 +0100
committerMichael Williamson <mike@zwobble.org>2016-03-29 19:56:41 +0100
commitbbfc91caf379a07198bfa352023524c0b54e1bb0 (patch)
treea1b081d63bb693f9cad63f980e430540a20d0586 /src
parentdf10352d2eea46b3e82cbd7783ed16e3f02fced6 (diff)
Add support for reading vararg method invocations
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ArrayNode.java70
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ExpressionNode.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/LiteralNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Node.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java2
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java1
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java7
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java1
-rw-r--r--src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java5
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java5
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java20
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java3
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java7
-rw-r--r--src/main/java/org/zwobble/couscous/types/Types.java7
-rw-r--r--src/main/java/org/zwobble/couscous/util/ExtraArrays.java9
-rw-r--r--src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java1
-rw-r--r--src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java24
19 files changed, 178 insertions, 9 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/ArrayNode.java b/src/main/java/org/zwobble/couscous/ast/ArrayNode.java
new file mode 100644
index 0000000..ac4c284
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/ArrayNode.java
@@ -0,0 +1,70 @@
+package org.zwobble.couscous.ast;
+
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
+import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.types.Type;
+import org.zwobble.couscous.types.Types;
+
+import java.util.List;
+
+public class ArrayNode implements ExpressionNode {
+ public static ArrayNode array(Type elementType, List<ExpressionNode> expressions) {
+ return new ArrayNode(elementType, expressions);
+ }
+
+ private final Type elementType;
+ private final List<ExpressionNode> elements;
+
+ public ArrayNode(Type elementType, List<ExpressionNode> elements) {
+ this.elementType = elementType;
+ this.elements = elements;
+ }
+
+ public List<ExpressionNode> getElements() {
+ return elements;
+ }
+
+ @Override
+ public Type getType() {
+ return Types.array(elementType);
+ }
+
+ @Override
+ public <T> T accept(ExpressionNodeMapper<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public ExpressionNode transform(NodeTransformer transformer) {
+ return new ArrayNode(
+ transformer.transform(elementType),
+ transformer.transformExpressions(elements));
+ }
+
+ @Override
+ public String toString() {
+ return "ArrayNode(" +
+ "elementType=" + elementType +
+ ", elements=" + elements +
+ ')';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ArrayNode arrayNode = (ArrayNode) o;
+
+ if (!elementType.equals(arrayNode.elementType)) return false;
+ return elements.equals(arrayNode.elements);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = elementType.hashCode();
+ result = 31 * result + elements.hashCode();
+ return result;
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
index 817078f..37bd436 100644
--- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
@@ -28,6 +28,11 @@ public interface ExpressionNode extends Node {
}
@Override
+ public T visit(ArrayNode array) {
+ return visitor.visit(array);
+ }
+
+ @Override
public T visit(AssignmentNode assignment) {
return visitor.visit(assignment);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java
index 46a141e..d1be23f 100644
--- a/src/main/java/org/zwobble/couscous/ast/LiteralNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/LiteralNode.java
@@ -32,11 +32,11 @@ public class LiteralNode implements ExpressionNode {
public static LiteralNode literal(ScalarType type) {
return literal(value(type));
}
-
+
public static LiteralNode of(PrimitiveValue value, Type type) {
return new LiteralNode(value, type);
}
-
+
private final PrimitiveValue value;
private final Type type;
diff --git a/src/main/java/org/zwobble/couscous/ast/Node.java b/src/main/java/org/zwobble/couscous/ast/Node.java
index a055488..4f21904 100644
--- a/src/main/java/org/zwobble/couscous/ast/Node.java
+++ b/src/main/java/org/zwobble/couscous/ast/Node.java
@@ -25,6 +25,12 @@ public interface Node {
}
@Override
+ public Void visit(ArrayNode array) {
+ visitor.visit(array);
+ return null;
+ }
+
+ @Override
public Void visit(AssignmentNode assignment) {
visitor.visit(assignment);
return null;
diff --git a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
index f1f37a6..ed5b474 100644
--- a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
+++ b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
@@ -47,6 +47,11 @@ public class NodeStructure {
}
@Override
+ public Stream<? extends Node> visit(ArrayNode array) {
+ return array.getElements().stream();
+ }
+
+ @Override
public Stream<Node> visit(AssignmentNode assignment) {
return Stream.of(assignment.getValue(), assignment.getTarget());
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
index 2836a22..2c8ed24 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
@@ -6,6 +6,7 @@ public interface ExpressionNodeMapper<T> {
T visit(LiteralNode literal);
T visit(VariableReferenceNode variableReference);
T visit(ThisReferenceNode reference);
+ T visit(ArrayNode array);
T visit(AssignmentNode assignment);
T visit(TernaryConditionalNode ternaryConditional);
T visit(MethodCallNode methodCall);
@@ -14,5 +15,4 @@ public interface ExpressionNodeMapper<T> {
T visit(FieldAccessNode fieldAccess);
T visit(TypeCoercionNode typeCoercion);
T visit(CastNode cast);
-
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
index 338d8d2..3596896 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
@@ -6,6 +6,7 @@ public interface NodeMapper<T> {
T visit(LiteralNode literal);
T visit(VariableReferenceNode variableReference);
T visit(ThisReferenceNode reference);
+ T visit(ArrayNode array);
T visit(AssignmentNode assignment);
T visit(TernaryConditionalNode ternaryConditional);
T visit(MethodCallNode methodCall);
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
index bcb74d5..b3285ba 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
@@ -23,7 +23,12 @@ public class NodeMapperWithDefault<T> implements NodeMapper<T> {
public T visit(ThisReferenceNode reference) {
return defaultValue;
}
-
+
+ @Override
+ public T visit(ArrayNode array) {
+ return defaultValue;
+ }
+
@Override
public T visit(AssignmentNode assignment) {
return defaultValue;
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java
index 393bd7e..710ef99 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java
@@ -45,6 +45,11 @@ public class NodeTransformer {
}
@Override
+ public Node visit(ArrayNode array) {
+ return transformExpression(array);
+ }
+
+ @Override
public Node visit(AssignmentNode assignment) {
return transformExpression(assignment);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
index 28c38fc..c70d662 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
@@ -6,6 +6,7 @@ public interface NodeVisitor {
void visit(LiteralNode literal);
void visit(VariableReferenceNode variableReference);
void visit(ThisReferenceNode reference);
+ void visit(ArrayNode array);
void visit(AssignmentNode assignment);
void visit(TernaryConditionalNode ternaryConditional);
void visit(MethodCallNode methodCall);
diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
index 9b168ef..e7ac3d7 100644
--- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
+++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
@@ -87,6 +87,11 @@ public class CsharpSerializer implements NodeVisitor {
}
@Override
+ public void visit(ArrayNode array) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void visit(AssignmentNode assignment) {
write(assignment.getTarget());
writer.writeSpace();
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
index 5b1691b..1ed223e 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
@@ -251,6 +251,11 @@ public class PythonCodeGenerator {
}
@Override
+ public PythonExpressionNode visit(ArrayNode arrayNode) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public PythonExpressionNode visit(AssignmentNode assignment) {
throw new UnsupportedOperationException();
}
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
index c0b69b3..0694cc3 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
@@ -9,6 +9,7 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import static org.zwobble.couscous.ast.ArrayNode.array;
import static org.zwobble.couscous.ast.CastNode.cast;
import static org.zwobble.couscous.ast.ConstructorCallNode.constructorCall;
import static org.zwobble.couscous.ast.LiteralNode.literal;
@@ -239,10 +240,21 @@ public class JavaExpressionReader {
}
private List<ExpressionNode> readArguments(IMethodBinding method, List<Expression> javaArguments) {
- return IntStream.range(0, javaArguments.size())
- .mapToObj(index -> readExpression(
- typeOf(method.getParameterTypes()[index]),
- javaArguments.get(index)))
+ ITypeBinding[] parameterTypes = method.getParameterTypes();
+ return IntStream.range(0, parameterTypes.length)
+ .mapToObj(index -> {
+ if (method.isVarargs() && index == parameterTypes.length - 1) {
+ Type elementType = typeOf(parameterTypes[index].getElementType());
+ List<ExpressionNode> elements = IntStream.range(index, javaArguments.size())
+ .mapToObj(argumentIndex -> readExpression(elementType, javaArguments.get(argumentIndex)))
+ .collect(Collectors.toList());
+ return array(elementType, elements);
+ } else {
+ return readExpression(
+ typeOf(parameterTypes[index]),
+ javaArguments.get(index));
+ }
+ })
.collect(Collectors.toList());
}
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 a770108..4e3fe66 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaTypes.java
@@ -35,6 +35,9 @@ public class JavaTypes {
if (typeBinding.isAnonymous()) {
throw new RuntimeException("Cannot get type of anonymous type binding");
}
+ if (typeBinding.isArray()) {
+ return Types.array(typeOf(typeBinding.getElementType()));
+ }
ITypeBinding outerClass = typeBinding.getDeclaringClass();
if (outerClass == null) {
ScalarType rawType = ScalarType.of(typeBinding.getErasure().getQualifiedName());
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
index a721206..1082ed1 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
@@ -50,7 +50,12 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
InterpreterTypes.checkIsInstance(reference.getType(), thisValue);
return thisValue;
}
-
+
+ @Override
+ public InterpreterValue visit(ArrayNode arrayNode) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public InterpreterValue visit(AssignmentNode assignment) {
InterpreterValue value = eval(assignment.getValue());
diff --git a/src/main/java/org/zwobble/couscous/types/Types.java b/src/main/java/org/zwobble/couscous/types/Types.java
index 6902c33..02f7672 100644
--- a/src/main/java/org/zwobble/couscous/types/Types.java
+++ b/src/main/java/org/zwobble/couscous/types/Types.java
@@ -1,5 +1,7 @@
package org.zwobble.couscous.types;
+import static org.zwobble.couscous.util.ExtraLists.list;
+
public class Types {
public static final ScalarType VOID = ScalarType.of("void");
public static final ScalarType BOOLEAN = ScalarType.of("boolean");
@@ -9,6 +11,11 @@ public class Types {
public static final ScalarType OBJECT = ScalarType.of("java.lang.Object");
public static final ScalarType BOXED_INT = ScalarType.of("java.lang.Integer");
public static final ScalarType BOXED_BOOLEAN = ScalarType.of("java.lang.Boolean");
+ public static final ScalarType ARRAY = ScalarType.of("array");
+
+ public static Type array(Type elementType) {
+ return new ParameterizedType(ARRAY, list(elementType));
+ }
public static ScalarType erasure(Type type) {
return type.accept(new Type.Visitor<ScalarType>() {
diff --git a/src/main/java/org/zwobble/couscous/util/ExtraArrays.java b/src/main/java/org/zwobble/couscous/util/ExtraArrays.java
index 457b77b..3267a29 100644
--- a/src/main/java/org/zwobble/couscous/util/ExtraArrays.java
+++ b/src/main/java/org/zwobble/couscous/util/ExtraArrays.java
@@ -1,6 +1,7 @@
package org.zwobble.couscous.util;
import java.util.Arrays;
+import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.IntStream;
@@ -20,4 +21,12 @@ public class ExtraArrays {
public static <T> Stream<T> stream(T[] array) {
return StreamSupport.stream(Arrays.spliterator(array), false);
}
+
+ public static <T> Optional<T> last(T[] array) {
+ if (array.length == 0) {
+ return Optional.empty();
+ } else {
+ return Optional.of(array[array.length - 1]);
+ }
+ }
}
diff --git a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
index ede89d6..2a6fd85 100644
--- a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
@@ -42,6 +42,7 @@ public class ValueObjectTests {
public static Iterable<Object[]> valueObjectTypes() {
return asList(new Object[][] {
{AnnotationNode.class},
+ {ArrayNode.class},
{AssignmentNode.class},
{BoundTypeParameter.class},
{CastNode.class},
diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java
index 3ad255b..b1f5049 100644
--- a/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/ExpressionReadingTests.java
@@ -9,6 +9,7 @@ import java.util.List;
import static java.util.Collections.emptyList;
import static org.junit.Assert.assertEquals;
+import static org.zwobble.couscous.ast.ArrayNode.array;
import static org.zwobble.couscous.ast.AssignmentNode.assign;
import static org.zwobble.couscous.ast.CastNode.cast;
import static org.zwobble.couscous.ast.ConstructorCallNode.constructorCall;
@@ -25,6 +26,7 @@ import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion;
import static org.zwobble.couscous.ast.VariableReferenceNode.reference;
import static org.zwobble.couscous.tests.frontends.java.JavaReading.*;
+import static org.zwobble.couscous.types.ParameterizedType.parameterizedType;
import static org.zwobble.couscous.util.ExtraLists.list;
public class ExpressionReadingTests {
@@ -183,6 +185,28 @@ public class ExpressionReadingTests {
}
@Test
+ public void canReadMethodCallsWithZeroExpressionsAsVarargs() {
+ assertEquals(
+ staticMethodCall(
+ ScalarType.of("java.util.Arrays"),
+ "asList",
+ list(array(Types.STRING, list())),
+ parameterizedType(ScalarType.of("java.util.List"), list(Types.STRING))),
+ readExpression("java.util.List<String>", "java.util.Arrays.asList()"));
+ }
+
+ @Test
+ public void canReadMethodCallsWithMultipleExpressionsAsVarargs() {
+ assertEquals(
+ staticMethodCall(
+ ScalarType.of("java.util.Arrays"),
+ "asList",
+ list(array(Types.STRING, list(literal("one"), literal("two")))),
+ parameterizedType(ScalarType.of("java.util.List"), list(Types.STRING))),
+ readExpression("java.util.List<String>", "java.util.Arrays.asList(\"one\", \"two\")"));
+ }
+
+ @Test
public void canReadConstructorCalls() {
assertEquals(
constructorCall(ScalarType.of("java.lang.String"), list(literal("_"))),