From b69c8f7c8e2c16aade681ceaae046456a5ef2a85 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 6 Jan 2016 08:31:13 +0000 Subject: Partially implement method overloading --- README.md | 3 ++ .../org/zwobble/couscous/ast/MethodCallNode.java | 4 ++ .../java/org/zwobble/couscous/ast/MethodNode.java | 8 ++++ .../org/zwobble/couscous/ast/MethodSignature.java | 44 ++++++++++++++++++++++ .../zwobble/couscous/ast/StaticMethodCallNode.java | 4 ++ .../backends/python/PythonCodeGenerator.java | 11 ++++-- .../zwobble/couscous/interpreter/Interpreter.java | 1 + .../couscous/interpreter/MethodSignature.java | 38 ------------------- .../zwobble/couscous/interpreter/NoSuchMethod.java | 2 + .../couscous/interpreter/values/ConcreteType.java | 17 ++------- .../resources/python/runtime/java/lang/Integer.py | 4 +- .../org/zwobble/couscous/tests/CompilerTests.java | 2 - .../tests/backends/python/PythonMethodRunner.java | 8 +++- .../couscous/tests/interpreter/EvaluatorTests.java | 1 + .../tests/interpreter/InterpreterMethodTests.java | 7 +--- 15 files changed, 89 insertions(+), 65 deletions(-) create mode 100644 src/main/java/org/zwobble/couscous/ast/MethodSignature.java delete mode 100644 src/main/java/org/zwobble/couscous/interpreter/MethodSignature.java diff --git a/README.md b/README.md index f693f7f..81ccf1f 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ just the simple name of the class, with an integer ID if the codebase has more than one type of the same name? + Overloading is done for the interpreter. Partially done for the Python + backend: currently only supports overloading by number of arguments. + * Handle boxing/unboxing when overriding method in supertype with more/less specific return types/arguments. For instance, if an interface defines a method that returns `Object`, then a subtype may override that method diff --git a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java index f65a9ae..ba50f17 100644 --- a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java +++ b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java @@ -111,6 +111,10 @@ public class MethodCallNode implements ExpressionNode { public TypeName getType() { return type; } + + public MethodSignature signature() { + return new MethodSignature(methodName, eagerMap(arguments, argument -> argument.getType())); + } @Override public T accept(ExpressionNodeMapper visitor) { diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java index 5763b11..86ae649 100644 --- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java +++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java @@ -6,6 +6,8 @@ import org.zwobble.couscous.ast.visitors.NodeMapper; import java.util.List; import java.util.function.Function; +import static org.zwobble.couscous.util.ExtraLists.eagerMap; + public class MethodNode implements CallableNode { public static Builder staticMethod(String name) { return builder(name).isStatic(true); @@ -116,6 +118,12 @@ public class MethodNode implements CallableNode { return body; } + public MethodSignature signature() { + return new MethodSignature( + name, + eagerMap(arguments, argument -> argument.getType())); + } + public MethodNode mapBody(Function, List> function) { return new MethodNode(annotations, isStatic, name, arguments, function.apply(body)); } diff --git a/src/main/java/org/zwobble/couscous/ast/MethodSignature.java b/src/main/java/org/zwobble/couscous/ast/MethodSignature.java new file mode 100644 index 0000000..fb2dc64 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/MethodSignature.java @@ -0,0 +1,44 @@ +package org.zwobble.couscous.ast; + +import java.util.List; +import java.util.Objects; + +public class MethodSignature { + private String name; + private List arguments; + + public MethodSignature(String name, List arguments) { + this.name = name; + this.arguments = arguments; + } + + public String getName() { + return name; + } + + public List getArguments() { + return 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/ast/StaticMethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java index 7c3b90b..1309c6e 100644 --- a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java +++ b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java @@ -81,6 +81,10 @@ public class StaticMethodCallNode implements ExpressionNode { public TypeName getType() { return type; } + + public MethodSignature signature() { + return new MethodSignature(methodName, eagerMap(arguments, argument -> argument.getType())); + } @Override public T accept(ExpressionNodeMapper visitor) { diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java index 2320a5a..95f8b9e 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java @@ -140,7 +140,7 @@ public class PythonCodeGenerator { method.isStatic() ? Collections.emptyList() : asList("self"), explicitArgumentNames); List pythonBody = generateStatements(method.getBody()); - return pythonFunctionDefinition(method.getName(), ImmutableList.copyOf(argumentNames), new PythonBlock(pythonBody)); + return pythonFunctionDefinition(toName(method.signature()), ImmutableList.copyOf(argumentNames), new PythonBlock(pythonBody)); } private static List generateStatements(List statements) { @@ -233,7 +233,7 @@ public class PythonCodeGenerator { PrimitiveMethodGenerator primitiveMethodGenerator = PrimitiveMethods.getPrimitiveMethod(methodCall.getReceiver().getType(), methodCall.getMethodName()).get(); return primitiveMethodGenerator.generate(receiver, arguments); } else { - return pythonCall(pythonAttributeAccess(receiver, methodCall.getMethodName()), arguments); + return pythonCall(pythonAttributeAccess(receiver, toName(methodCall.signature())), arguments); } } @@ -241,7 +241,8 @@ public class PythonCodeGenerator { public PythonExpressionNode visit(StaticMethodCallNode staticMethodCall) { TypeName className = staticMethodCall.getClassName(); PythonVariableReferenceNode classReference = pythonVariableReference(className.getSimpleName()); - PythonAttributeAccessNode methodReference = pythonAttributeAccess(classReference, staticMethodCall.getMethodName()); + PythonAttributeAccessNode methodReference = + pythonAttributeAccess(classReference, toName(staticMethodCall.signature())); List arguments = generateExpressions(staticMethodCall.getArguments()); return PrimitiveMethods.getPrimitiveStaticMethod(className, staticMethodCall.getMethodName()) @@ -292,6 +293,10 @@ public class PythonCodeGenerator { } } + public static String toName(MethodSignature signature) { + return signature.getName() + "_" + signature.getArguments().size(); + } + private static boolean isPrimitive(ExpressionNode value) { return PrimitiveMethods.isPrimitive(value.getType()); } diff --git a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java index b506fdf..da84de0 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Interpreter.java @@ -3,6 +3,7 @@ package org.zwobble.couscous.interpreter; import java.util.List; import java.util.Optional; +import org.zwobble.couscous.ast.MethodSignature; import org.zwobble.couscous.ast.TypeName; import org.zwobble.couscous.interpreter.values.ConcreteType; import org.zwobble.couscous.interpreter.values.InterpreterValue; diff --git a/src/main/java/org/zwobble/couscous/interpreter/MethodSignature.java b/src/main/java/org/zwobble/couscous/interpreter/MethodSignature.java deleted file mode 100644 index 708bc9a..0000000 --- a/src/main/java/org/zwobble/couscous/interpreter/MethodSignature.java +++ /dev/null @@ -1,38 +0,0 @@ -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 arguments; - - public MethodSignature(String name, List 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 1bb934e..734c254 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/NoSuchMethod.java +++ b/src/main/java/org/zwobble/couscous/interpreter/NoSuchMethod.java @@ -1,5 +1,7 @@ package org.zwobble.couscous.interpreter; +import org.zwobble.couscous.ast.MethodSignature; + public final class NoSuchMethod extends InterpreterException { private static final long serialVersionUID = 1L; private MethodSignature signature; 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 536aeb3..6abb56c 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java +++ b/src/main/java/org/zwobble/couscous/interpreter/values/ConcreteType.java @@ -3,16 +3,13 @@ package org.zwobble.couscous.interpreter.values; import java.util.*; 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.ast.*; 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 { @@ -74,7 +71,7 @@ public class ConcreteType { Map methods = classNode.getMethods() .stream() .filter(method -> !method.isStatic()) - .collect(toMap(method -> signature(method), method -> { + .collect(toMap(method -> method.signature(), method -> { List argumentTypes = getArgumentTypes(method.getArguments()); return new MethodValue(argumentTypes, (environment, arguments) -> { return Executor.callMethod(environment, method, Optional.of(arguments.getReceiver()), arguments.getPositionalArguments()); @@ -83,7 +80,7 @@ public class ConcreteType { Map staticMethods = classNode.getMethods() .stream() .filter(method -> method.isStatic()) - .collect(toMap(method -> signature(method), method -> { + .collect(toMap(method -> method.signature(), method -> { List argumentTypes = getArgumentTypes(method.getArguments()); return new StaticMethodValue(argumentTypes, (environment, arguments) -> { return Executor.callMethod(environment, method, Optional.empty(), arguments); @@ -92,12 +89,6 @@ 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 getArgumentTypes(List arguments) { return arguments.stream().map(arg -> arg.getType()).collect(Collectors.toList()); } diff --git a/src/main/resources/python/runtime/java/lang/Integer.py b/src/main/resources/python/runtime/java/lang/Integer.py index 8ea30a4..0cf55af 100644 --- a/src/main/resources/python/runtime/java/lang/Integer.py +++ b/src/main/resources/python/runtime/java/lang/Integer.py @@ -1,12 +1,12 @@ class Integer(object): @staticmethod - def parseInt(value): + def parseInt_1(value): return int(value) def __init__(self, value): self._value = value - def equals(self, other): + def equals_1(self, other): # TODO: test this properly return isinstance(other, Integer) and other._value == self._value diff --git a/src/test/java/org/zwobble/couscous/tests/CompilerTests.java b/src/test/java/org/zwobble/couscous/tests/CompilerTests.java index 4caa687..710db7d 100644 --- a/src/test/java/org/zwobble/couscous/tests/CompilerTests.java +++ b/src/test/java/org/zwobble/couscous/tests/CompilerTests.java @@ -1,6 +1,5 @@ package org.zwobble.couscous.tests; -import org.junit.Ignore; import org.junit.Test; import org.zwobble.couscous.ast.TypeName; import org.zwobble.couscous.values.PrimitiveValue; @@ -134,7 +133,6 @@ public abstract class CompilerTests { } @Test - @Ignore("WIP") public void staticMethodOverloads() throws Exception { assertEquals( value(42), diff --git a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java index 0c09178..5818de0 100644 --- a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java +++ b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonMethodRunner.java @@ -7,6 +7,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import org.zwobble.couscous.ast.ClassNode; +import org.zwobble.couscous.ast.MethodSignature; import org.zwobble.couscous.ast.TypeName; import org.zwobble.couscous.backends.python.PythonCodeGenerator; import org.zwobble.couscous.backends.python.PythonBackend; @@ -19,6 +20,7 @@ import com.google.common.base.Joiner; import com.google.common.io.CharStreams; import static java.lang.Integer.parseInt; import static org.zwobble.couscous.tests.util.ExtraFiles.deleteRecursively; +import static org.zwobble.couscous.util.ExtraLists.eagerMap; import static org.zwobble.couscous.values.PrimitiveValues.value; public class PythonMethodRunner implements MethodRunner { @@ -46,7 +48,11 @@ public class PythonMethodRunner implements MethodRunner { throws IOException, InterruptedException { String argumentsString = Joiner.on(", ").join(arguments.stream().map(PythonCodeGenerator::generateCode).map(PythonSerializer::serialize).iterator()); - String program = "from couscous." + className.getQualifiedName() + " import " + className.getSimpleName() + ";print(repr(" + className.getSimpleName() + "." + methodName + "(" + argumentsString + ")))"; + String pythonMethodName = PythonCodeGenerator.toName(new MethodSignature( + methodName, + eagerMap(arguments, argument -> argument.getType()))); + String program = "from couscous." + className.getQualifiedName() + " import " + className.getSimpleName() + ";" + + "print(repr(" + className.getSimpleName() + "." + pythonMethodName + "(" + argumentsString + ")))"; Process process = new ProcessBuilder("python3.4", "-c", program).directory(directoryPath.toFile()).start(); int exitCode = process.waitFor(); String output = readString(process.getInputStream()).trim(); diff --git a/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java b/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java index df97248..f3087ed 100644 --- a/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java +++ b/src/test/java/org/zwobble/couscous/tests/interpreter/EvaluatorTests.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ExpressionNode; import org.zwobble.couscous.ast.FormalArgumentNode; +import org.zwobble.couscous.ast.MethodSignature; import org.zwobble.couscous.interpreter.*; import org.zwobble.couscous.interpreter.values.IntegerInterpreterValue; import org.zwobble.couscous.interpreter.values.InterpreterValue; diff --git a/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java b/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java index 2be59a8..8023ee5 100644 --- a/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java +++ b/src/test/java/org/zwobble/couscous/tests/interpreter/InterpreterMethodTests.java @@ -4,12 +4,7 @@ import java.util.List; import java.util.stream.Collectors; import org.junit.Test; -import org.zwobble.couscous.ast.ClassNode; -import org.zwobble.couscous.ast.FormalArgumentNode; -import org.zwobble.couscous.ast.LiteralNode; -import org.zwobble.couscous.ast.LocalVariableDeclarationNode; -import org.zwobble.couscous.ast.MethodNode; -import org.zwobble.couscous.ast.TypeName; +import org.zwobble.couscous.ast.*; import org.zwobble.couscous.interpreter.*; import org.zwobble.couscous.interpreter.values.InterpreterValue; import org.zwobble.couscous.interpreter.values.InterpreterValues; -- cgit v1.2.3