aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/couscous/interpreter
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2015-10-05 12:29:48 +0100
committerMichael Williamson <mike@zwobble.org>2015-10-05 12:29:48 +0100
commit2f9374c7f32a761413da4c5484bec88a76c855d2 (patch)
treeac38f0e750a534f446c361f3cd1771f37d6f75a3 /src/main/java/org/zwobble/couscous/interpreter
parent96b1e6f776ae8ce8910c44a3bbec0b489fd10c88 (diff)
Move interpreter values into interpreter package
Diffstat (limited to 'src/main/java/org/zwobble/couscous/interpreter')
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Arguments.java2
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/ConditionMustBeBoolean.java2
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Environment.java4
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java4
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Executor.java4
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Interpreter.java2
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java2
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/BooleanValue.java23
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/Callable.java9
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java141
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/IntegerValue.java30
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValue.java5
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/InterpreterValues.java13
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/MethodValue.java22
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/StaticMethodValue.java24
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/StringValue.java34
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/UnitValue.java19
17 files changed, 330 insertions, 10 deletions
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Arguments.java b/src/main/java/org/zwobble/couscous/interpreter/Arguments.java
index af674a1..f34a456 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Arguments.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Arguments.java
@@ -2,7 +2,7 @@ package org.zwobble.couscous.interpreter;
import java.util.List;
-import org.zwobble.couscous.values.InterpreterValue;
+import org.zwobble.couscous.interpreter.values.InterpreterValue;
public class Arguments {
private List<InterpreterValue> values;
diff --git a/src/main/java/org/zwobble/couscous/interpreter/ConditionMustBeBoolean.java b/src/main/java/org/zwobble/couscous/interpreter/ConditionMustBeBoolean.java
index c69c290..7f2e901 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/ConditionMustBeBoolean.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/ConditionMustBeBoolean.java
@@ -1,6 +1,6 @@
package org.zwobble.couscous.interpreter;
-import org.zwobble.couscous.values.InterpreterValue;
+import org.zwobble.couscous.interpreter.values.InterpreterValue;
import lombok.EqualsAndHashCode;
import lombok.Value;
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Environment.java b/src/main/java/org/zwobble/couscous/interpreter/Environment.java
index 6838ba5..5e6e231 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Environment.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Environment.java
@@ -6,8 +6,8 @@ import java.util.Optional;
import org.zwobble.couscous.Project;
import org.zwobble.couscous.ast.VariableDeclaration;
import org.zwobble.couscous.ast.VariableNode;
-import org.zwobble.couscous.values.ConcreteType;
-import org.zwobble.couscous.values.InterpreterValue;
+import org.zwobble.couscous.interpreter.values.ConcreteType;
+import org.zwobble.couscous.interpreter.values.InterpreterValue;
import org.zwobble.couscous.values.TypeReference;
import static java.util.stream.Collectors.toMap;
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
index 6287348..6b61b7f 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
@@ -11,8 +11,8 @@ import org.zwobble.couscous.ast.StaticMethodCallNode;
import org.zwobble.couscous.ast.TernaryConditionalNode;
import org.zwobble.couscous.ast.VariableReferenceNode;
import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor;
-import org.zwobble.couscous.values.BooleanValue;
-import org.zwobble.couscous.values.InterpreterValue;
+import org.zwobble.couscous.interpreter.values.BooleanValue;
+import org.zwobble.couscous.interpreter.values.InterpreterValue;
import lombok.val;
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Executor.java b/src/main/java/org/zwobble/couscous/interpreter/Executor.java
index 95eddad..2f12e0c 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Executor.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java
@@ -11,8 +11,8 @@ import org.zwobble.couscous.ast.ReturnNode;
import org.zwobble.couscous.ast.StatementNode;
import org.zwobble.couscous.ast.VariableNode;
import org.zwobble.couscous.ast.visitors.StatementNodeVisitor;
-import org.zwobble.couscous.values.InterpreterValue;
-import org.zwobble.couscous.values.UnitValue;
+import org.zwobble.couscous.interpreter.values.InterpreterValue;
+import org.zwobble.couscous.interpreter.values.UnitValue;
import static org.zwobble.couscous.interpreter.Evaluator.eval;
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java
index 884a082..39191ce 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java
@@ -6,7 +6,7 @@ import java.util.stream.Collectors;
import org.zwobble.couscous.Project;
import org.zwobble.couscous.ast.ExpressionNode;
import org.zwobble.couscous.ast.LiteralNode;
-import org.zwobble.couscous.values.InterpreterValue;
+import org.zwobble.couscous.interpreter.values.InterpreterValue;
import com.google.common.collect.ImmutableMap;
diff --git a/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java b/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java
index 3b163f3..c546807 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/StackFrameBuilder.java
@@ -4,7 +4,7 @@ import java.util.Map;
import org.zwobble.couscous.ast.VariableDeclaration;
import org.zwobble.couscous.ast.VariableNode;
-import org.zwobble.couscous.values.InterpreterValue;
+import org.zwobble.couscous.interpreter.values.InterpreterValue;
import com.google.common.collect.ImmutableMap;
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;
+ }
+}