diff options
Diffstat (limited to 'src')
8 files changed, 106 insertions, 32 deletions
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Arguments.java b/src/main/java/org/zwobble/couscous/interpreter/Arguments.java new file mode 100644 index 0000000..d08393d --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/Arguments.java @@ -0,0 +1,29 @@ +package org.zwobble.couscous.interpreter; + +import java.util.List; + +import org.zwobble.couscous.values.InterpreterValue; + +import lombok.val; + +public class Arguments { + private int index = 0; + private List<InterpreterValue> values; + + public Arguments(List<InterpreterValue> values) { + this.values = values; + } + + @SuppressWarnings("unchecked") + public <T extends InterpreterValue> T pop(Class<T> valueType) { + val value = values.get(index); + index++; + if (valueType.isInstance(value)) { + return (T) value; + } else { + // TODO: throw a more specific error + throw new UnsupportedOperationException(); + } + + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java index 7aba54b..6a566c9 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java @@ -61,12 +61,11 @@ public class Evaluator implements ExpressionNodeVisitor<InterpreterValue> { @Override public InterpreterValue visit(MethodCallNode methodCall) { val receiver = eval(methodCall.getReceiver()); + val type = receiver.getType(); val arguments = methodCall.getArguments() .stream() .map(argument -> eval(argument)) .collect(Collectors.toList()); - val method = receiver.getMethod(methodCall.getMethodName()) - .orElseThrow(() -> new NoSuchMethod(methodCall.getMethodName())); - return method.call(arguments); + return type.callMethod(receiver, methodCall.getMethodName(), arguments); } } diff --git a/src/main/java/org/zwobble/couscous/values/BooleanValue.java b/src/main/java/org/zwobble/couscous/values/BooleanValue.java index 0bcb256..3f1f2a2 100644 --- a/src/main/java/org/zwobble/couscous/values/BooleanValue.java +++ b/src/main/java/org/zwobble/couscous/values/BooleanValue.java @@ -1,13 +1,14 @@ package org.zwobble.couscous.values; -import java.util.Optional; - import lombok.AccessLevel; import lombok.Getter; import lombok.Value; @Value public class BooleanValue implements InterpreterValue { + private static final ConcreteType<BooleanValue> TYPE = ConcreteType.<BooleanValue>builder() + .build(); + @Getter(value = AccessLevel.NONE) boolean value; @@ -16,7 +17,7 @@ public class BooleanValue implements InterpreterValue { } @Override - public Optional<MethodValue> getMethod(String methodName) { - throw new UnsupportedOperationException(); + public ConcreteType<?> getType() { + return TYPE; } } diff --git a/src/main/java/org/zwobble/couscous/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/values/ConcreteType.java new file mode 100644 index 0000000..c3ead74 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/values/ConcreteType.java @@ -0,0 +1,46 @@ +package org.zwobble.couscous.values; + +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +import org.zwobble.couscous.interpreter.Arguments; +import org.zwobble.couscous.interpreter.NoSuchMethod; + +import com.google.common.collect.ImmutableMap; + +import lombok.val; + +public class ConcreteType<T> { + public static class Builder<T> { + private final ImmutableMap.Builder<String, BiFunction<T, Arguments, InterpreterValue>> methods = + ImmutableMap.builder(); + + public Builder<T> method(String name, BiFunction<T, Arguments, InterpreterValue> method) { + methods.put(name, method); + return this; + } + + public ConcreteType<T> build() { + return new ConcreteType<T>(methods.build()); + } + } + + private Map<String, BiFunction<T, Arguments, InterpreterValue>> methods; + + public ConcreteType(Map<String, BiFunction<T, Arguments, InterpreterValue>> methods) { + this.methods = methods; + } + + public static <T> ConcreteType.Builder<T> builder() { + return new Builder<>(); + } + + public InterpreterValue callMethod(InterpreterValue receiver, String methodName, List<InterpreterValue> arguments) { + if (!methods.containsKey(methodName)) { + throw new NoSuchMethod(methodName); + } + val method = methods.get(methodName); + return method.apply((T)receiver, new Arguments(arguments)); + } +} diff --git a/src/main/java/org/zwobble/couscous/values/IntegerValue.java b/src/main/java/org/zwobble/couscous/values/IntegerValue.java index 9b77b69..eb7031d 100644 --- a/src/main/java/org/zwobble/couscous/values/IntegerValue.java +++ b/src/main/java/org/zwobble/couscous/values/IntegerValue.java @@ -1,15 +1,16 @@ package org.zwobble.couscous.values; -import java.util.Optional; - import lombok.Value; @Value public class IntegerValue implements InterpreterValue { + private static final ConcreteType<?> TYPE = ConcreteType.<IntegerValue>builder() + .build(); + int value; @Override - public Optional<MethodValue> getMethod(String methodName) { - throw new UnsupportedOperationException(); + public ConcreteType<?> getType() { + return TYPE; } } diff --git a/src/main/java/org/zwobble/couscous/values/InterpreterValue.java b/src/main/java/org/zwobble/couscous/values/InterpreterValue.java index 17a3722..f1afa85 100644 --- a/src/main/java/org/zwobble/couscous/values/InterpreterValue.java +++ b/src/main/java/org/zwobble/couscous/values/InterpreterValue.java @@ -1,7 +1,5 @@ package org.zwobble.couscous.values; -import java.util.Optional; - public interface InterpreterValue { - Optional<MethodValue> getMethod(String methodName); + ConcreteType<?> getType(); } diff --git a/src/main/java/org/zwobble/couscous/values/StringValue.java b/src/main/java/org/zwobble/couscous/values/StringValue.java index 3f4b2b0..da45f02 100644 --- a/src/main/java/org/zwobble/couscous/values/StringValue.java +++ b/src/main/java/org/zwobble/couscous/values/StringValue.java @@ -1,26 +1,25 @@ package org.zwobble.couscous.values; -import java.util.Optional; - import lombok.Value; import lombok.val; @Value public class StringValue implements InterpreterValue { + private static final ConcreteType<?> TYPE = ConcreteType.<StringValue>builder() + .method("length", (receiver, arguments) -> new IntegerValue(receiver.value.length())) + + .method("substring", (receiver, arguments) -> { + val startIndex = arguments.pop(IntegerValue.class); + val endIndex = arguments.pop(IntegerValue.class); + return new StringValue(receiver.value.substring(startIndex.getValue(), endIndex.getValue())); + }) + + .build(); + String value; @Override - public Optional<MethodValue> getMethod(String methodName) { - if (methodName == "length") { - return Optional.of(arguments -> new IntegerValue(value.length())); - } else if (methodName == "substring") { - return Optional.of(arguments -> { - val startIndex = (IntegerValue)arguments.get(0); - val endIndex = (IntegerValue)arguments.get(1); - return new StringValue(value.substring(startIndex.getValue(), endIndex.getValue())); - }); - } else { - return Optional.empty(); - } + public ConcreteType<?> getType() { + return TYPE; } } diff --git a/src/main/java/org/zwobble/couscous/values/UnitValue.java b/src/main/java/org/zwobble/couscous/values/UnitValue.java index 8d75529..5742d8a 100644 --- a/src/main/java/org/zwobble/couscous/values/UnitValue.java +++ b/src/main/java/org/zwobble/couscous/values/UnitValue.java @@ -1,18 +1,19 @@ package org.zwobble.couscous.values; -import java.util.Optional; - import lombok.ToString; @ToString public class UnitValue implements InterpreterValue { + private static final ConcreteType<?> TYPE = ConcreteType.<UnitValue>builder() + .build(); + public static final UnitValue UNIT = new UnitValue(); private UnitValue() { } @Override - public Optional<MethodValue> getMethod(String methodName) { - throw new UnsupportedOperationException(); + public ConcreteType<?> getType() { + return TYPE; } } |
