diff options
Diffstat (limited to 'src/main/java/org/zwobble')
6 files changed, 107 insertions, 67 deletions
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java index 910cba7..1271d72 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java @@ -10,6 +10,8 @@ import org.zwobble.couscous.values.IntegerValue; import java.util.List; import java.util.stream.Collectors; +import static org.zwobble.couscous.util.ExtraLists.eagerMap; + public class Evaluator implements ExpressionNodeMapper<InterpreterValue> { public static InterpreterValue eval(Environment environment, ExpressionNode expression) { return new Evaluator(environment).eval(expression); @@ -76,14 +78,20 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> { InterpreterValue receiver = eval(methodCall.getReceiver()); ConcreteType type = receiver.getType(); List<InterpreterValue> arguments = evalArguments(methodCall.getArguments()); - return type.callMethod(environment, receiver, methodCall.getMethodName(), arguments); + MethodSignature signature = new MethodSignature( + methodCall.getMethodName(), + eagerMap(arguments, argument -> argument.getType().getName())); + return type.callMethod(environment, receiver, signature, arguments); } @Override public InterpreterValue visit(StaticMethodCallNode staticMethodCall) { ConcreteType clazz = environment.findClass(staticMethodCall.getClassName()); List<InterpreterValue> arguments = evalArguments(staticMethodCall.getArguments()); - return clazz.callStaticMethod(environment, staticMethodCall.getMethodName(), arguments); + MethodSignature signature = new MethodSignature( + staticMethodCall.getMethodName(), + eagerMap(arguments, argument -> argument.getType().getName())); + return clazz.callStaticMethod(environment, signature, arguments); } @Override diff --git a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java index 95510cd..b506fdf 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java @@ -9,6 +9,8 @@ import org.zwobble.couscous.interpreter.values.InterpreterValue; import com.google.common.collect.ImmutableMap; +import static org.zwobble.couscous.util.ExtraLists.eagerMap; + public class Interpreter { private Project project; @@ -23,6 +25,9 @@ public class Interpreter { ImmutableMap.of()); ConcreteType clazz = environment.findClass(className); - return clazz.callStaticMethod(environment, methodName, arguments); + MethodSignature signature = new MethodSignature( + methodName, + eagerMap(arguments, argument -> argument.getType().getName())); + return clazz.callStaticMethod(environment, signature, arguments); } }
\ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/interpreter/MethodSignature.java b/src/main/java/org/zwobble/couscous/interpreter/MethodSignature.java new file mode 100644 index 0000000..708bc9a --- /dev/null +++ b/src/main/java/org/zwobble/couscous/interpreter/MethodSignature.java @@ -0,0 +1,38 @@ +package org.zwobble.couscous.interpreter; + +import org.zwobble.couscous.ast.TypeName; + +import java.util.List; +import java.util.Objects; + +public class MethodSignature { + private String name; + private List<TypeName> arguments; + + public MethodSignature(String name, List<TypeName> arguments) { + this.name = name; + this.arguments = arguments; + } + + @Override + public String toString() { + return "MethodSignature(" + + "name='" + name + '\'' + + ", arguments=" + arguments + + ')'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MethodSignature that = (MethodSignature) o; + return Objects.equals(name, that.name) && + Objects.equals(arguments, that.arguments); + } + + @Override + public int hashCode() { + return Objects.hash(name, arguments); + } +} diff --git a/src/main/java/org/zwobble/couscous/interpreter/NoSuchMethod.java b/src/main/java/org/zwobble/couscous/interpreter/NoSuchMethod.java index ddddd71..1bb934e 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/NoSuchMethod.java +++ b/src/main/java/org/zwobble/couscous/interpreter/NoSuchMethod.java @@ -2,43 +2,20 @@ package org.zwobble.couscous.interpreter; public final class NoSuchMethod extends InterpreterException { private static final long serialVersionUID = 1L; - private final String methodName; + private MethodSignature signature; - public NoSuchMethod(final String methodName) { - this.methodName = methodName; + public NoSuchMethod(MethodSignature signature) { + this.signature = signature; } - public String getMethodName() { - return this.methodName; + public MethodSignature getSignature() { + return signature; } - @java.lang.Override - public java.lang.String toString() { - return "NoSuchMethod(methodName=" + this.getMethodName() + ")"; - } - - @java.lang.Override - public boolean equals(final java.lang.Object o) { - if (o == this) return true; - if (!(o instanceof NoSuchMethod)) return false; - final NoSuchMethod other = (NoSuchMethod)o; - if (!other.canEqual((java.lang.Object)this)) return false; - final java.lang.Object this$methodName = this.getMethodName(); - final java.lang.Object other$methodName = other.getMethodName(); - if (this$methodName == null ? other$methodName != null : !this$methodName.equals(other$methodName)) return false; - return true; - } - - protected boolean canEqual(final java.lang.Object other) { - return other instanceof NoSuchMethod; - } - - @java.lang.Override - public int hashCode() { - final int PRIME = 59; - int result = 1; - final java.lang.Object $methodName = this.getMethodName(); - result = result * PRIME + ($methodName == null ? 43 : $methodName.hashCode()); - return result; + @Override + public String toString() { + return "NoSuchMethod(" + + "signature=" + signature + + ") " + super.toString(); } }
\ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java index 157bb41..536aeb3 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java @@ -5,17 +5,14 @@ import java.util.function.BiFunction; import java.util.stream.Collectors; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.FormalArgumentNode; +import org.zwobble.couscous.ast.MethodNode; import org.zwobble.couscous.ast.TypeName; -import org.zwobble.couscous.interpreter.Environment; -import org.zwobble.couscous.interpreter.Executor; -import org.zwobble.couscous.interpreter.InterpreterTypes; -import org.zwobble.couscous.interpreter.NoSuchMethod; -import org.zwobble.couscous.interpreter.PositionalArguments; -import org.zwobble.couscous.interpreter.WrongNumberOfArguments; +import org.zwobble.couscous.interpreter.*; import org.zwobble.couscous.util.Casts; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import static java.util.stream.Collectors.toMap; +import static org.zwobble.couscous.util.ExtraLists.eagerMap; public class ConcreteType { @@ -33,8 +30,8 @@ public class ConcreteType { public static class Builder<T> { private final ImmutableMap.Builder<String, FieldValue> fields = ImmutableMap.builder(); - private final ImmutableMap.Builder<String, MethodValue> methods = ImmutableMap.builder(); - private final ImmutableMap.Builder<String, StaticMethodValue> staticMethods = ImmutableMap.builder(); + 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 TypeName name; @@ -49,14 +46,14 @@ public class ConcreteType { } public Builder<T> method(String name, List<TypeName> argumentsTypes, BiFunction<Environment, MethodCallArguments<T>, InterpreterValue> method) { - methods.put(name, new MethodValue(argumentsTypes, (environment, arguments) -> { + methods.put(new MethodSignature(name, argumentsTypes), new MethodValue(argumentsTypes, (environment, arguments) -> { return Casts.tryCast(interpreterValueType, arguments.getReceiver()).map(typedReceiver -> method.apply(environment, MethodCallArguments.of(typedReceiver, arguments.getPositionalArguments()))).orElseThrow(() -> new RuntimeException("receiver is of wrong type")); })); return this; } public Builder<T> staticMethod(String name, List<TypeName> argumentsTypes, BiFunction<Environment, PositionalArguments, InterpreterValue> method) { - staticMethods.put(name, new StaticMethodValue(argumentsTypes, method)); + staticMethods.put(new MethodSignature(name, argumentsTypes), new StaticMethodValue(argumentsTypes, method)); return this; } @@ -74,19 +71,19 @@ public class ConcreteType { public static ConcreteType fromNode(ClassNode classNode) { Map<String, FieldValue> fields = classNode.getFields().stream().collect(toMap(field -> field.getName(), field -> new FieldValue(field.getName(), field.getType()))); MethodValue constructor = new MethodValue(getArgumentTypes(classNode.getConstructor().getArguments()), (environment, arguments) -> Executor.callMethod(environment, classNode.getConstructor(), Optional.of(arguments.getReceiver()), arguments.getPositionalArguments())); - Map<String, MethodValue> methods = classNode.getMethods() + Map<MethodSignature, MethodValue> methods = classNode.getMethods() .stream() .filter(method -> !method.isStatic()) - .collect(toMap(method -> method.getName(), method -> { + .collect(toMap(method -> signature(method), method -> { List<TypeName> argumentTypes = getArgumentTypes(method.getArguments()); return new MethodValue(argumentTypes, (environment, arguments) -> { return Executor.callMethod(environment, method, Optional.of(arguments.getReceiver()), arguments.getPositionalArguments()); }); })); - Map<String, StaticMethodValue> staticMethods = classNode.getMethods() + Map<MethodSignature, StaticMethodValue> staticMethods = classNode.getMethods() .stream() .filter(method -> method.isStatic()) - .collect(toMap(method -> method.getName(), method -> { + .collect(toMap(method -> signature(method), method -> { List<TypeName> argumentTypes = getArgumentTypes(method.getArguments()); return new StaticMethodValue(argumentTypes, (environment, arguments) -> { return Executor.callMethod(environment, method, Optional.empty(), arguments); @@ -94,7 +91,13 @@ public class ConcreteType { })); return new ConcreteType(classNode.getName(), classNode.getSuperTypes(), fields, constructor, methods, staticMethods); } - + + private static MethodSignature signature(MethodNode method) { + return new MethodSignature( + method.getName(), + eagerMap(method.getArguments(), argument -> argument.getType())); + } + private static List<TypeName> getArgumentTypes(List<FormalArgumentNode> arguments) { return arguments.stream().map(arg -> arg.getType()).collect(Collectors.toList()); } @@ -102,16 +105,17 @@ public class ConcreteType { private final Set<TypeName> superTypes; private final Map<String, FieldValue> fields; private final MethodValue constructor; - private final Map<String, MethodValue> methods; - private final Map<String, StaticMethodValue> staticMethods; + private final Map<MethodSignature, MethodValue> methods; + private final Map<MethodSignature, StaticMethodValue> staticMethods; private ConcreteType( TypeName name, Set<TypeName> superTypes, Map<String, FieldValue> fields, MethodValue constructor, - Map<String, MethodValue> methods, - Map<String, StaticMethodValue> staticMethods) { + Map<MethodSignature, MethodValue> methods, + Map<MethodSignature, StaticMethodValue> staticMethods) + { this.name = name; this.superTypes = superTypes; this.fields = fields; @@ -132,13 +136,13 @@ public class ConcreteType { return Optional.ofNullable(fields.get(fieldName)); } - public InterpreterValue callMethod(Environment environment, InterpreterValue receiver, String methodName, List<InterpreterValue> arguments) { - final org.zwobble.couscous.interpreter.values.MethodValue method = findMethod(methods, methodName, arguments); + public InterpreterValue callMethod(Environment environment, InterpreterValue receiver, MethodSignature signature, List<InterpreterValue> arguments) { + MethodValue method = findMethod(methods, signature, arguments); return method.apply(environment, MethodCallArguments.of(receiver, new PositionalArguments(arguments))); } - public InterpreterValue callStaticMethod(Environment environment, String methodName, List<InterpreterValue> arguments) { - final org.zwobble.couscous.interpreter.values.StaticMethodValue method = findMethod(staticMethods, methodName, arguments); + public InterpreterValue callStaticMethod(Environment environment, MethodSignature signature, List<InterpreterValue> arguments) { + StaticMethodValue method = findMethod(staticMethods, signature, arguments); return method.apply(environment, new PositionalArguments(arguments)); } @@ -149,11 +153,11 @@ public class ConcreteType { return object; } - private static <T extends Callable> T findMethod(Map<String, T> methods, String methodName, List<InterpreterValue> arguments) { - if (!methods.containsKey(methodName)) { - throw new NoSuchMethod(methodName); + private static <T extends Callable> T findMethod(Map<MethodSignature, T> methods, MethodSignature signature, List<InterpreterValue> arguments) { + if (!methods.containsKey(signature)) { + throw new NoSuchMethod(signature); } - final T method = methods.get(methodName); + final T method = methods.get(signature); checkMethodArguments(method, arguments); return method; } diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java index 3bcb41a..be58d56 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/IntegerInterpreterValue.java @@ -4,8 +4,7 @@ import java.util.Optional; import java.util.function.BiFunction; import org.zwobble.couscous.ast.Operator; -import org.zwobble.couscous.interpreter.Environment; -import org.zwobble.couscous.interpreter.NoSuchField; +import org.zwobble.couscous.interpreter.*; import org.zwobble.couscous.values.IntegerValue; import org.zwobble.couscous.values.ObjectValues; import org.zwobble.couscous.values.PrimitiveValue; @@ -29,11 +28,16 @@ public final class IntegerInterpreterValue implements InterpreterValue { (environment, arguments) -> { InterpreterValue right = arguments.getPositionalArguments().get(0); if (right instanceof IntegerInterpreterValue) { - return new BooleanInterpreterValue(arguments.getReceiver().getValue() == ((IntegerInterpreterValue)right).getValue()); + return integerEquals(arguments, ((IntegerInterpreterValue)right)); } else { return new BooleanInterpreterValue(false); } }) + .method(Operator.EQUALS.getMethodName(), asList(IntegerValue.REF), + (environment, arguments) -> { + IntegerInterpreterValue right = (IntegerInterpreterValue)arguments.getPositionalArguments().get(0); + return integerEquals(arguments, right); + }) .method(Operator.NOT_EQUALS.getMethodName(), asList(IntegerValue.REF), infixReturningBoolean((left, right) -> !left.equals(right))) .method(Operator.GREATER_THAN.getMethodName(), asList(IntegerValue.REF), @@ -45,7 +49,11 @@ public final class IntegerInterpreterValue implements InterpreterValue { .method(Operator.LESS_THAN_OR_EQUAL.getMethodName(), asList(IntegerValue.REF), infixReturningBoolean((left, right) -> left <= right)) .build(); - + + private static BooleanInterpreterValue integerEquals(MethodCallArguments<IntegerInterpreterValue> arguments, IntegerInterpreterValue right) { + return new BooleanInterpreterValue(arguments.getReceiver().getValue() == right.getValue()); + } + private static BiFunction<Environment, MethodCallArguments<IntegerInterpreterValue>, InterpreterValue> infixReturningInteger(BiFunction<Integer, Integer, Integer> func) { |
