diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-10-01 21:04:37 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-10-01 21:04:37 +0100 |
| commit | 8187130b8a8aabbcf983e530413d6969141d6da2 (patch) | |
| tree | d72dcb499d08812e7391b95cdf780dff054b3a3c /src/main/java/org | |
| parent | 36f3fdbcad95dcc5bfec785fffca4f42b24d1307 (diff) | |
Allow static method calls
Diffstat (limited to 'src/main/java/org')
12 files changed, 158 insertions, 17 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java new file mode 100644 index 0000000..390c37f --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java @@ -0,0 +1,25 @@ +package org.zwobble.couscous.ast; + +import java.util.List; + +import org.zwobble.couscous.ast.visitors.ExpressionNodeVisitor; + +import static java.util.Arrays.asList; + +import lombok.Value; + +@Value +public class StaticMethodCallNode implements ExpressionNode { + public static StaticMethodCallNode staticMethodCall(String className, String methodName, ExpressionNode... arguments) { + return new StaticMethodCallNode(className, methodName, asList(arguments)); + } + + String className; + String methodName; + List<ExpressionNode> arguments; + + @Override + public <T> T accept(ExpressionNodeVisitor<T> visitor) { + return visitor.visit(this); + } +} diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java index f083625..5d3ea9b 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeVisitor.java @@ -3,6 +3,7 @@ package org.zwobble.couscous.ast.visitors; import org.zwobble.couscous.ast.Assignment; import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.ast.MethodCallNode; +import org.zwobble.couscous.ast.StaticMethodCallNode; import org.zwobble.couscous.ast.TernaryConditionalNode; import org.zwobble.couscous.ast.VariableReferenceNode; @@ -12,4 +13,5 @@ public interface ExpressionNodeVisitor<T> { T visit(Assignment assignment); T visit(TernaryConditionalNode ternaryConditional); T visit(MethodCallNode methodCall); + T visit(StaticMethodCallNode staticMethodCall); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Environment.java b/src/main/java/org/zwobble/couscous/interpreter/Environment.java index a3b3871..ea4a5e4 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Environment.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Environment.java @@ -3,6 +3,8 @@ package org.zwobble.couscous.interpreter; import java.util.HashMap; import java.util.Map; +import org.zwobble.couscous.values.ConcreteType; +import org.zwobble.couscous.values.IntegerValue; import org.zwobble.couscous.values.InterpreterValue; public class Environment { @@ -19,4 +21,12 @@ public class Environment { public void put(int referentId, InterpreterValue value) { stackFrame.put(referentId, value); } + + public ConcreteType<?> findClass(String className) { + if (className == "java.lang.Integer") { + return IntegerValue.TYPE; + } else { + 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 6a566c9..5acef94 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java @@ -1,11 +1,13 @@ package org.zwobble.couscous.interpreter; +import java.util.List; import java.util.stream.Collectors; import org.zwobble.couscous.ast.Assignment; import org.zwobble.couscous.ast.ExpressionNode; import org.zwobble.couscous.ast.LiteralNode; import org.zwobble.couscous.ast.MethodCallNode; +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; @@ -62,10 +64,21 @@ public class Evaluator implements ExpressionNodeVisitor<InterpreterValue> { public InterpreterValue visit(MethodCallNode methodCall) { val receiver = eval(methodCall.getReceiver()); val type = receiver.getType(); - val arguments = methodCall.getArguments() + val arguments = evalArguments(methodCall.getArguments()); + return type.callMethod(receiver, methodCall.getMethodName(), arguments); + } + + private List<InterpreterValue> evalArguments(List<ExpressionNode> arguments) { + return arguments .stream() .map(argument -> eval(argument)) .collect(Collectors.toList()); - return type.callMethod(receiver, methodCall.getMethodName(), arguments); + } + + @Override + public InterpreterValue visit(StaticMethodCallNode staticMethodCall) { + val clazz = environment.findClass(staticMethodCall.getClassName()); + val arguments = evalArguments(staticMethodCall.getArguments()); + return clazz.callStaticMethod(staticMethodCall.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 3f1f2a2..aeeb7e3 100644 --- a/src/main/java/org/zwobble/couscous/values/BooleanValue.java +++ b/src/main/java/org/zwobble/couscous/values/BooleanValue.java @@ -6,7 +6,7 @@ import lombok.Value; @Value public class BooleanValue implements InterpreterValue { - private static final ConcreteType<BooleanValue> TYPE = ConcreteType.<BooleanValue>builder() + private static final ConcreteType<BooleanValue> TYPE = ConcreteType.<BooleanValue>builder("Boolean") .build(); @Getter(value = AccessLevel.NONE) diff --git a/src/main/java/org/zwobble/couscous/values/Callable.java b/src/main/java/org/zwobble/couscous/values/Callable.java new file mode 100644 index 0000000..9f3e486 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/values/Callable.java @@ -0,0 +1,7 @@ +package org.zwobble.couscous.values; + +import java.util.List; + +public interface Callable { + List<ConcreteType<?>> getArgumentTypes(); +} diff --git a/src/main/java/org/zwobble/couscous/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/values/ConcreteType.java index 38b1b6e..db5209e 100644 --- a/src/main/java/org/zwobble/couscous/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/values/ConcreteType.java @@ -3,6 +3,8 @@ package org.zwobble.couscous.values; import java.util.List; import java.util.Map; import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; import org.zwobble.couscous.interpreter.Arguments; import org.zwobble.couscous.interpreter.NoSuchMethod; @@ -17,32 +19,64 @@ 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<ConcreteType<?>> argumentsTypes, + Supplier<List<ConcreteType<?>>> argumentsTypes, BiFunction<T, Arguments, InterpreterValue> method) { methods.put(name, new MethodValue<T>(argumentsTypes, method)); return this; } + public Builder<T> staticMethod( + String name, + Supplier<List<ConcreteType<?>>> argumentsTypes, + Function<Arguments, InterpreterValue> method) { + staticMethods.put(name, new StaticMethodValue(argumentsTypes, method)); + return this; + } + public ConcreteType<T> build() { - return new ConcreteType<T>(methods.build()); + return new ConcreteType<T>(name, methods.build(), staticMethods.build()); } } + private String name; private Map<String, MethodValue<T>> methods; + private ImmutableMap<String, StaticMethodValue> staticMethods; - public ConcreteType(Map<String, MethodValue<T>> methods) { + public ConcreteType( + String name, + Map<String, MethodValue<T>> methods, + ImmutableMap<String, StaticMethodValue> staticMethods) { + this.name = name; this.methods = methods; + this.staticMethods = staticMethods; } - public static <T> ConcreteType.Builder<T> builder() { - return new Builder<>(); + 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(String methodName, List<InterpreterValue> arguments) { + val method = findMethod(staticMethods, methodName, arguments); + return method.apply(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); } @@ -58,7 +92,11 @@ public class ConcreteType<T> { throw new UnexpectedValueType(formalArgumentType, actualArgumentType); } } - - return method.apply((T)receiver, new Arguments(arguments)); + return method; + } + + @Override + public String toString() { + return "ConcreteType<" + name + ">"; } } diff --git a/src/main/java/org/zwobble/couscous/values/IntegerValue.java b/src/main/java/org/zwobble/couscous/values/IntegerValue.java index 8b5b423..1b20a01 100644 --- a/src/main/java/org/zwobble/couscous/values/IntegerValue.java +++ b/src/main/java/org/zwobble/couscous/values/IntegerValue.java @@ -1,10 +1,19 @@ package org.zwobble.couscous.values; +import static java.util.Arrays.asList; + import lombok.Value; +import lombok.val; @Value public class IntegerValue implements InterpreterValue { - public static final ConcreteType<?> TYPE = ConcreteType.<IntegerValue>builder() + public static final ConcreteType<?> TYPE = ConcreteType.<IntegerValue>builder("Integer") + .staticMethod("parseInt", () -> asList(StringValue.TYPE), + arguments -> { + val value = (StringValue)arguments.get(0); + return new IntegerValue(Integer.parseInt(value.getValue())); + }) + .build(); int value; diff --git a/src/main/java/org/zwobble/couscous/values/MethodValue.java b/src/main/java/org/zwobble/couscous/values/MethodValue.java index fe23f94..df53722 100644 --- a/src/main/java/org/zwobble/couscous/values/MethodValue.java +++ b/src/main/java/org/zwobble/couscous/values/MethodValue.java @@ -2,6 +2,7 @@ package org.zwobble.couscous.values; import java.util.List; import java.util.function.BiFunction; +import java.util.function.Supplier; import org.zwobble.couscous.interpreter.Arguments; @@ -10,11 +11,17 @@ import lombok.Getter; import lombok.Value; @Value -public class MethodValue<T> { - List<ConcreteType<?>> argumentTypes; +public class MethodValue<T> implements Callable { + @Getter(value=AccessLevel.NONE) + Supplier<List<ConcreteType<?>>> argumentTypes; @Getter(value=AccessLevel.NONE) BiFunction<T, Arguments, InterpreterValue> apply; + @Override + public List<ConcreteType<?>> getArgumentTypes() { + return argumentTypes.get(); + } + public InterpreterValue apply(T receiver, Arguments arguments) { return apply.apply(receiver, arguments); } diff --git a/src/main/java/org/zwobble/couscous/values/StaticMethodValue.java b/src/main/java/org/zwobble/couscous/values/StaticMethodValue.java new file mode 100644 index 0000000..15a70d3 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/values/StaticMethodValue.java @@ -0,0 +1,29 @@ +package org.zwobble.couscous.values; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.zwobble.couscous.interpreter.Arguments; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Value; + +@Value +public class StaticMethodValue implements Callable { + @Getter(value=AccessLevel.NONE) + Supplier<List<ConcreteType<?>>> argumentTypes; + @Getter(value=AccessLevel.NONE) + Function<Arguments, InterpreterValue> apply; + + @Override + public List<ConcreteType<?>> getArgumentTypes() { + return argumentTypes.get(); + } + + public InterpreterValue apply(Arguments arguments) { + return apply.apply(arguments); + } + +} diff --git a/src/main/java/org/zwobble/couscous/values/StringValue.java b/src/main/java/org/zwobble/couscous/values/StringValue.java index 0ade0e1..e8a7c0e 100644 --- a/src/main/java/org/zwobble/couscous/values/StringValue.java +++ b/src/main/java/org/zwobble/couscous/values/StringValue.java @@ -7,10 +7,11 @@ import lombok.val; @Value public class StringValue implements InterpreterValue { - public static final ConcreteType<?> TYPE = ConcreteType.<StringValue>builder() - .method("length", asList(), (receiver, arguments) -> new IntegerValue(receiver.value.length())) + public static final ConcreteType<?> TYPE = ConcreteType.<StringValue>builder("String") + .method("length", () -> asList(), + (receiver, arguments) -> new IntegerValue(receiver.value.length())) - .method("substring", asList(IntegerValue.TYPE, IntegerValue.TYPE), + .method("substring", () -> asList(IntegerValue.TYPE, IntegerValue.TYPE), (receiver, arguments) -> { val startIndex = (IntegerValue)arguments.get(0); val endIndex = (IntegerValue)arguments.get(1); diff --git a/src/main/java/org/zwobble/couscous/values/UnitValue.java b/src/main/java/org/zwobble/couscous/values/UnitValue.java index 5742d8a..af00b32 100644 --- a/src/main/java/org/zwobble/couscous/values/UnitValue.java +++ b/src/main/java/org/zwobble/couscous/values/UnitValue.java @@ -4,7 +4,7 @@ import lombok.ToString; @ToString public class UnitValue implements InterpreterValue { - private static final ConcreteType<?> TYPE = ConcreteType.<UnitValue>builder() + private static final ConcreteType<?> TYPE = ConcreteType.<UnitValue>builder("Unit") .build(); public static final UnitValue UNIT = new UnitValue(); |
