diff options
Diffstat (limited to 'src')
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))); + } } |
