diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-10-05 12:29:48 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-10-05 12:29:48 +0100 |
| commit | 2f9374c7f32a761413da4c5484bec88a76c855d2 (patch) | |
| tree | ac38f0e750a534f446c361f3cd1771f37d6f75a3 /src/main/java/org/zwobble/couscous/interpreter/values | |
| parent | 96b1e6f776ae8ce8910c44a3bbec0b489fd10c88 (diff) | |
Move interpreter values into interpreter package
Diffstat (limited to 'src/main/java/org/zwobble/couscous/interpreter/values')
10 files changed, 320 insertions, 0 deletions
diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/BooleanValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/BooleanValue.java new file mode 100644 index 0000000..1837d6f --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/BooleanValue.java @@ -0,0 +1,23 @@ +package org.zwobble.couscous.interpreter.values; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Value; + +@Value +public class BooleanValue implements InterpreterValue { + private static final ConcreteType<BooleanValue> TYPE = ConcreteType.<BooleanValue>builder("Boolean") + .build(); + + @Getter(value = AccessLevel.NONE) + boolean value; + + public boolean getValue() { + return value; + } + + @Override + public ConcreteType<?> getType() { + return TYPE; + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/Callable.java b/src/main/java/org/zwobble/couscous/interpreter/values/Callable.java new file mode 100644 index 0000000..dc372bb --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/Callable.java @@ -0,0 +1,9 @@ +package org.zwobble.couscous.interpreter.values; + +import java.util.List; + +import org.zwobble.couscous.values.TypeReference; + +public interface Callable { + List<TypeReference> getArgumentTypes(); +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java new file mode 100644 index 0000000..b2abd2b --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java @@ -0,0 +1,141 @@ +package org.zwobble.couscous.interpreter.values; + +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.interpreter.Arguments; +import org.zwobble.couscous.interpreter.Environment; +import org.zwobble.couscous.interpreter.Executor; +import org.zwobble.couscous.interpreter.NoSuchMethod; +import org.zwobble.couscous.interpreter.UnexpectedValueType; +import org.zwobble.couscous.interpreter.WrongNumberOfArguments; +import org.zwobble.couscous.values.TypeReference; + +import com.google.common.collect.ImmutableMap; + +import static java.util.stream.Collectors.toMap; +import static org.zwobble.couscous.values.TypeReference.typeRef; + +import lombok.val; + +public class ConcreteType<T> { + public static class Builder<T> { + private final ImmutableMap.Builder<String, MethodValue<T>> methods = + ImmutableMap.builder(); + private final ImmutableMap.Builder<String, StaticMethodValue> staticMethods = + ImmutableMap.builder(); + private final String name; + + public Builder(String name) { + this.name = name; + } + + public Builder<T> method( + String name, + List<TypeReference> argumentsTypes, + BiFunction<T, Arguments, InterpreterValue> method) { + methods.put(name, new MethodValue<T>(argumentsTypes, method)); + return this; + } + + public Builder<T> staticMethod( + String name, + List<TypeReference> argumentsTypes, + BiFunction<Environment, Arguments, InterpreterValue> method) { + staticMethods.put(name, new StaticMethodValue(argumentsTypes, method)); + return this; + } + + public ConcreteType<T> build() { + return new ConcreteType<T>(name, methods.build(), staticMethods.build()); + } + } + + public static ConcreteType<?> fromNode(ClassNode classNode) { + val staticMethods = classNode.getMethods() + .stream() + .filter(method -> method.isStatic()) + .collect(toMap( + method -> method.getName(), + method -> { + List<TypeReference> argumentTypes = method.getArguments() + .stream() + .map(arg -> arg.getType()) + .collect(Collectors.toList()); + return new StaticMethodValue(argumentTypes, (environment, arguments) -> { + return Executor.callMethod(environment, method, arguments); + }); + })); + return new ConcreteType<Void>( + classNode.getName(), + ImmutableMap.of(), + staticMethods); + } + + private String name; + private Map<String, MethodValue<T>> methods; + private Map<String, StaticMethodValue> staticMethods; + + public ConcreteType( + String name, + Map<String, MethodValue<T>> methods, + Map<String, StaticMethodValue> staticMethods) { + this.name = name; + this.methods = methods; + this.staticMethods = staticMethods; + } + + public String getName() { + return name; + } + + public static <T> ConcreteType.Builder<T> builder(TypeReference reference) { + return new Builder<>(reference.getName()); + } + + public static <T> ConcreteType.Builder<T> builder(String name) { + return new Builder<>(name); + } + + @SuppressWarnings("unchecked") + public InterpreterValue callMethod(InterpreterValue receiver, String methodName, List<InterpreterValue> arguments) { + val method = findMethod(methods, methodName, arguments); + return method.apply((T)receiver, new Arguments(arguments)); + } + + public InterpreterValue callStaticMethod(Environment environment, String methodName, List<InterpreterValue> arguments) { + val method = findMethod(staticMethods, methodName, arguments); + return method.apply(environment, new Arguments(arguments)); + } + + private static <T extends Callable> T findMethod(Map<String, T> methods, String methodName, List<InterpreterValue> arguments) { + if (!methods.containsKey(methodName)) { + throw new NoSuchMethod(methodName); + } + val method = methods.get(methodName); + if (method.getArgumentTypes().size() != arguments.size()) { + throw new WrongNumberOfArguments(method.getArgumentTypes().size(), arguments.size()); + } + + for (int index = 0; index < arguments.size(); index++) { + val formalArgumentType = method.getArgumentTypes().get(index); + val actualArgumentType = arguments.get(index).getType(); + if (!formalArgumentType.equals(actualArgumentType.getReference())) { + throw new UnexpectedValueType(formalArgumentType, actualArgumentType.getReference()); + } + } + return method; + } + + public TypeReference getReference() { + return typeRef(name); + } + + @Override + public String toString() { + return "ConcreteType<" + name + ">"; + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/IntegerValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/IntegerValue.java new file mode 100644 index 0000000..89fd056 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/IntegerValue.java @@ -0,0 +1,30 @@ +package org.zwobble.couscous.interpreter.values; + +import org.zwobble.couscous.values.TypeReference; + +import static java.util.Arrays.asList; +import static org.zwobble.couscous.values.TypeReference.typeRef; + +import lombok.Value; +import lombok.val; + +@Value +public class IntegerValue implements InterpreterValue { + public static final TypeReference REF = typeRef("java.lang.Integer"); + + public static final ConcreteType<?> TYPE = ConcreteType.<IntegerValue>builder(REF) + .staticMethod("parseInt", asList(StringValue.REF), + (environment, arguments) -> { + val value = (StringValue)arguments.get(0); + return new IntegerValue(Integer.parseInt(value.getValue())); + }) + + .build(); + + int value; + + @Override + public ConcreteType<?> getType() { + return TYPE; + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValue.java new file mode 100644 index 0000000..cf2aa5b --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValue.java @@ -0,0 +1,5 @@ +package org.zwobble.couscous.interpreter.values; + +public interface InterpreterValue { + ConcreteType<?> getType(); +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValues.java b/src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValues.java new file mode 100644 index 0000000..ec2d97f --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValues.java @@ -0,0 +1,13 @@ +package org.zwobble.couscous.interpreter.values; + +public class InterpreterValues { + public static final UnitValue UNIT = UnitValue.UNIT; + + public static InterpreterValue value(int value) { + return new IntegerValue(value); + } + + public static InterpreterValue value(String value) { + return new StringValue(value); + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/MethodValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/MethodValue.java new file mode 100644 index 0000000..ea76870 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/MethodValue.java @@ -0,0 +1,22 @@ +package org.zwobble.couscous.interpreter.values; + +import java.util.List; +import java.util.function.BiFunction; + +import org.zwobble.couscous.interpreter.Arguments; +import org.zwobble.couscous.values.TypeReference; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Value; + +@Value +public class MethodValue<T> implements Callable { + List<TypeReference> argumentTypes; + @Getter(value=AccessLevel.NONE) + BiFunction<T, Arguments, InterpreterValue> apply; + + public InterpreterValue apply(T receiver, Arguments arguments) { + return apply.apply(receiver, arguments); + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/StaticMethodValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/StaticMethodValue.java new file mode 100644 index 0000000..21697b1 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/StaticMethodValue.java @@ -0,0 +1,24 @@ +package org.zwobble.couscous.interpreter.values; + +import java.util.List; +import java.util.function.BiFunction; + +import org.zwobble.couscous.interpreter.Arguments; +import org.zwobble.couscous.interpreter.Environment; +import org.zwobble.couscous.values.TypeReference; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Value; + +@Value +public class StaticMethodValue implements Callable { + List<TypeReference> argumentTypes; + @Getter(value=AccessLevel.NONE) + BiFunction<Environment, Arguments, InterpreterValue> apply; + + public InterpreterValue apply(Environment environment, Arguments arguments) { + return apply.apply(environment, arguments); + } + +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/StringValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/StringValue.java new file mode 100644 index 0000000..43a4bde --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/StringValue.java @@ -0,0 +1,34 @@ +package org.zwobble.couscous.interpreter.values; + +import org.zwobble.couscous.values.TypeReference; + +import static java.util.Arrays.asList; +import static org.zwobble.couscous.values.TypeReference.typeRef; + +import lombok.Value; +import lombok.val; + +@Value +public class StringValue implements InterpreterValue { + public static final TypeReference REF = typeRef("java.lang.String"); + + public static final ConcreteType<?> TYPE = ConcreteType.<StringValue>builder(REF) + .method("length", asList(), + (receiver, arguments) -> new IntegerValue(receiver.value.length())) + + .method("substring", asList(IntegerValue.REF, IntegerValue.REF), + (receiver, arguments) -> { + val startIndex = (IntegerValue)arguments.get(0); + val endIndex = (IntegerValue)arguments.get(1); + return new StringValue(receiver.value.substring(startIndex.getValue(), endIndex.getValue())); + }) + + .build(); + + String value; + + @Override + public ConcreteType<?> getType() { + return TYPE; + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/UnitValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/UnitValue.java new file mode 100644 index 0000000..4e2eb2c --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/values/UnitValue.java @@ -0,0 +1,19 @@ +package org.zwobble.couscous.interpreter.values; + +import lombok.ToString; + +@ToString +public class UnitValue implements InterpreterValue { + private static final ConcreteType<?> TYPE = ConcreteType.<UnitValue>builder("Unit") + .build(); + + public static final UnitValue UNIT = new UnitValue(); + + private UnitValue() { + } + + @Override + public ConcreteType<?> getType() { + return TYPE; + } +} |
