aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-03-31 12:08:02 +0100
committerMichael Williamson <mike@zwobble.org>2016-03-31 12:08:02 +0100
commit6bb8fe3f983cd0a2be76239df2124af633f0e05c (patch)
tree8ae88b29f16ccbc0a408fa33f625b607c9fc32cc /src
parent2247cff5b5361a8124d4c261a1edb1852bd5f08f (diff)
Add evaluation of arrays to interpreter
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ArrayNode.java4
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java9
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/types/IntrinsicInterpreterType.java22
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/ArrayInterpreterValue.java50
-rw-r--r--src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java35
-rw-r--r--src/test/java/org/zwobble/couscous/tests/util/ExtraMatchers.java21
6 files changed, 121 insertions, 20 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/ArrayNode.java b/src/main/java/org/zwobble/couscous/ast/ArrayNode.java
index ac4c284..78e6869 100644
--- a/src/main/java/org/zwobble/couscous/ast/ArrayNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ArrayNode.java
@@ -20,6 +20,10 @@ public class ArrayNode implements ExpressionNode {
this.elements = elements;
}
+ public Type getElementType() {
+ return elementType;
+ }
+
public List<ExpressionNode> getElements() {
return elements;
}
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
index 1082ed1..8c3d355 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
@@ -1,18 +1,19 @@
package org.zwobble.couscous.interpreter;
import org.zwobble.couscous.ast.*;
-import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.ast.visitors.AssignableExpressionNodeVisitor;
import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.interpreter.errors.ConditionMustBeBoolean;
import org.zwobble.couscous.interpreter.errors.InvalidCast;
import org.zwobble.couscous.interpreter.values.*;
+import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.types.Types;
import java.util.List;
import java.util.stream.Collectors;
import static org.zwobble.couscous.types.Types.erasure;
+import static org.zwobble.couscous.util.ExtraLists.eagerMap;
public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
public static InterpreterValue eval(Environment environment, ExpressionNode expression) {
@@ -52,8 +53,10 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
}
@Override
- public InterpreterValue visit(ArrayNode arrayNode) {
- throw new UnsupportedOperationException();
+ public InterpreterValue visit(ArrayNode array) {
+ return new ArrayInterpreterValue(
+ array.getElementType(),
+ eagerMap(array.getElements(), this::eval));
}
@Override
diff --git a/src/main/java/org/zwobble/couscous/interpreter/types/IntrinsicInterpreterType.java b/src/main/java/org/zwobble/couscous/interpreter/types/IntrinsicInterpreterType.java
index d69c855..190908b 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/types/IntrinsicInterpreterType.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/types/IntrinsicInterpreterType.java
@@ -22,7 +22,7 @@ import static org.zwobble.couscous.util.ExtraLists.list;
import static org.zwobble.couscous.util.ExtraSets.set;
public class IntrinsicInterpreterType implements InterpreterType {
- public static <T> Builder<T> builder(Class<T> interpreterValueType, ScalarType reference) {
+ public static <T> Builder<T> builder(Class<T> interpreterValueType, Type reference) {
return new Builder<>(interpreterValueType, reference);
}
@@ -40,11 +40,11 @@ public class IntrinsicInterpreterType implements InterpreterType {
private final ImmutableMap.Builder<MethodSignature, MethodValue> methods = ImmutableMap.builder();
private final ImmutableMap.Builder<MethodSignature, StaticMethodValue> staticMethods = ImmutableMap.builder();
private final Class<T> interpreterValueType;
- private final ScalarType name;
+ private final Type type;
- public Builder(Class<T> interpreterValueType, ScalarType name) {
+ public Builder(Class<T> interpreterValueType, Type type) {
this.interpreterValueType = interpreterValueType;
- this.name = name;
+ this.type = type;
}
public Builder<T> field(String name, ScalarType type) {
@@ -88,7 +88,7 @@ public class IntrinsicInterpreterType implements InterpreterType {
public InterpreterType build() {
return new IntrinsicInterpreterType(
- name,
+ type,
fields.build(),
constructor,
methods.build(),
@@ -96,20 +96,20 @@ public class IntrinsicInterpreterType implements InterpreterType {
}
}
- private final ScalarType name;
+ private final Type type;
private final Map<String, FieldDeclarationNode> fields;
private final MethodValue constructor;
private final Map<MethodSignature, MethodValue> methods;
private final Map<MethodSignature, StaticMethodValue> staticMethods;
private IntrinsicInterpreterType(
- ScalarType name,
+ Type type,
Map<String, FieldDeclarationNode> fields,
MethodValue constructor,
Map<MethodSignature, MethodValue> methods,
Map<MethodSignature, StaticMethodValue> staticMethods)
{
- this.name = name;
+ this.type = type;
this.fields = fields;
this.constructor = constructor;
this.methods = methods;
@@ -117,8 +117,8 @@ public class IntrinsicInterpreterType implements InterpreterType {
}
@Override
- public ScalarType getType() {
- return name;
+ public Type getType() {
+ return type;
}
@Override
@@ -164,6 +164,6 @@ public class IntrinsicInterpreterType implements InterpreterType {
@Override
public String toString() {
- return "IntrinsicInterpreterType<" + name + ">";
+ return "IntrinsicInterpreterType<" + type + ">";
}
}
diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/ArrayInterpreterValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/ArrayInterpreterValue.java
new file mode 100644
index 0000000..3a1de58
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/interpreter/values/ArrayInterpreterValue.java
@@ -0,0 +1,50 @@
+package org.zwobble.couscous.interpreter.values;
+
+import org.zwobble.couscous.interpreter.errors.NoSuchField;
+import org.zwobble.couscous.interpreter.types.InterpreterType;
+import org.zwobble.couscous.interpreter.types.IntrinsicInterpreterType;
+import org.zwobble.couscous.types.Type;
+import org.zwobble.couscous.types.Types;
+import org.zwobble.couscous.values.PrimitiveValue;
+
+import java.util.List;
+import java.util.Optional;
+
+public class ArrayInterpreterValue implements InterpreterValue {
+ private final Type elementType;
+ private final List<InterpreterValue> elements;
+
+ public ArrayInterpreterValue(Type elementType, List<InterpreterValue> elements) {
+ this.elementType = elementType;
+ this.elements = elements;
+ }
+
+ public Type getElementType() {
+ return elementType;
+ }
+
+ public List<InterpreterValue> getElements() {
+ return elements;
+ }
+
+ @Override
+ public InterpreterType getType() {
+ return IntrinsicInterpreterType.builder(ArrayInterpreterValue.class, Types.array(elementType))
+ .build();
+ }
+
+ @Override
+ public Optional<PrimitiveValue> toPrimitiveValue() {
+ return Optional.empty();
+ }
+
+ @Override
+ public InterpreterValue getField(String fieldName) {
+ throw new NoSuchField(fieldName);
+ }
+
+ @Override
+ public void setField(String fieldName, InterpreterValue value) {
+ throw new NoSuchField(fieldName);
+ }
+}
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 6112c8e..5f42065 100644
--- a/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java
@@ -1,25 +1,31 @@
package org.zwobble.couscous.tests.interpreter;
import com.google.common.collect.ImmutableMap;
+import org.hamcrest.Matcher;
import org.junit.Test;
import org.zwobble.couscous.ast.*;
-import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.interpreter.Environment;
import org.zwobble.couscous.interpreter.JavaProject;
import org.zwobble.couscous.interpreter.MapBackedProject;
import org.zwobble.couscous.interpreter.StackFrameBuilder;
import org.zwobble.couscous.interpreter.errors.*;
+import org.zwobble.couscous.interpreter.values.ArrayInterpreterValue;
import org.zwobble.couscous.interpreter.values.IntegerInterpreterValue;
import org.zwobble.couscous.interpreter.values.InterpreterValue;
import org.zwobble.couscous.interpreter.values.StringInterpreterValue;
import org.zwobble.couscous.tests.BackendEvalTests;
+import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.types.Types;
import org.zwobble.couscous.values.PrimitiveValue;
import java.util.List;
import java.util.Optional;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.equalTo;
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.AssignmentNode.assignStatement;
import static org.zwobble.couscous.ast.CastNode.cast;
@@ -34,6 +40,7 @@ import static org.zwobble.couscous.interpreter.Evaluator.eval;
import static org.zwobble.couscous.interpreter.values.InterpreterValues.value;
import static org.zwobble.couscous.tests.TestIds.ANY_ID;
import static org.zwobble.couscous.tests.util.ExtraAsserts.assertThrows;
+import static org.zwobble.couscous.tests.util.ExtraMatchers.*;
import static org.zwobble.couscous.util.ExtraLists.list;
public class EvaluatorTests extends BackendEvalTests {
@@ -225,7 +232,31 @@ public class EvaluatorTests extends BackendEvalTests {
assertEquals(Types.STRING, exception.getExpected());
assertEquals(Types.INT, exception.getActual());
}
-
+
+ @Test
+ public void canEvaluateEmptyArray() {
+ InterpreterValue array = eval(emptyEnvironment(), array(Types.STRING, list()));
+ assertThat(array, isArrayInterpreterValue(Types.STRING, list()));
+ }
+
+ @Test
+ public void canEvaluateArrayWithElements() {
+ InterpreterValue array = eval(emptyEnvironment(), array(Types.STRING, list(literal("one"), literal("two"))));
+ assertThat(
+ array,
+ isArrayInterpreterValue(Types.STRING, list(
+ StringInterpreterValue.of("one"),
+ StringInterpreterValue.of("two"))));
+ }
+
+ private Matcher<InterpreterValue> isArrayInterpreterValue(ScalarType elementType, List<InterpreterValue> elements) {
+ return isInstance(
+ ArrayInterpreterValue.class,
+ allOf(
+ hasFeature("elementType", value -> value.getElementType(), equalTo(elementType)),
+ hasFeature("elements", value -> value.getElements(), containsExactElements(elements))));
+ }
+
private static Environment emptyEnvironment() {
return new Environment(
JavaProject.builder().build(),
diff --git a/src/test/java/org/zwobble/couscous/tests/util/ExtraMatchers.java b/src/test/java/org/zwobble/couscous/tests/util/ExtraMatchers.java
index d79cb05..074e449 100644
--- a/src/test/java/org/zwobble/couscous/tests/util/ExtraMatchers.java
+++ b/src/test/java/org/zwobble/couscous/tests/util/ExtraMatchers.java
@@ -1,12 +1,13 @@
package org.zwobble.couscous.tests.util;
-import org.hamcrest.Description;
-import org.hamcrest.DiagnosingMatcher;
-import org.hamcrest.FeatureMatcher;
-import org.hamcrest.Matcher;
+import org.hamcrest.*;
+import java.util.List;
import java.util.function.Function;
+import static org.hamcrest.Matchers.equalTo;
+import static org.zwobble.couscous.util.ExtraLists.eagerMap;
+
public class ExtraMatchers {
public static <T, U> Matcher<T> isInstance(Class<U> type, Matcher<? super U> downcastMatcher) {
return new DiagnosingMatcher<T>() {
@@ -51,4 +52,16 @@ public class ExtraMatchers {
}
};
}
+
+ public static <T> Matcher<Iterable<? extends T>> containsExactly(List<Matcher<? super T>> matchers) {
+ if (matchers.isEmpty()) {
+ return Matchers.emptyIterable();
+ } else {
+ return Matchers.contains(matchers);
+ }
+ }
+
+ public static <T> Matcher<Iterable<? extends T>> containsExactElements(List<T> values) {
+ return containsExactly(eagerMap(values, value -> equalTo(value)));
+ }
}