aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-01-10 16:12:32 +0000
committerMichael Williamson <mike@zwobble.org>2016-01-10 16:12:32 +0000
commit1cca01d385e68aefe2131319c53c4811101f15f7 (patch)
tree08fbdf98f3e0d53ce1c64925bef8ad576c52ae64
parent29c9a38a112b53e4ca193af27818442493c876cb (diff)
Handle both static and instance method calls in one node
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ExpressionNode.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java59
-rw-r--r--src/main/java/org/zwobble/couscous/ast/MethodCallNode.java36
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Node.java18
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Receiver.java13
-rw-r--r--src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java120
-rw-r--r--src/main/java/org/zwobble/couscous/ast/StaticReceiver.java58
-rw-r--r--src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java15
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java1
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java15
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java4
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java4
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java68
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java28
-rw-r--r--src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java32
-rw-r--r--src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java2
17 files changed, 273 insertions, 209 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
index c483bcd..ac96c8c 100644
--- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
@@ -43,11 +43,6 @@ public interface ExpressionNode extends Node {
}
@Override
- public T visit(StaticMethodCallNode staticMethodCall) {
- return visitor.visit(staticMethodCall);
- }
-
- @Override
public T visit(ConstructorCallNode call) {
return visitor.visit(call);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java
new file mode 100644
index 0000000..926af5d
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java
@@ -0,0 +1,59 @@
+package org.zwobble.couscous.ast;
+
+import org.zwobble.couscous.ast.visitors.NodeMapper;
+
+import java.util.function.Function;
+
+public class InstanceReceiver implements Receiver {
+ public static Receiver instanceReceiver(ExpressionNode expression) {
+ return new InstanceReceiver(expression);
+ }
+
+ private final ExpressionNode expression;
+
+ public InstanceReceiver(ExpressionNode expression) {
+ this.expression = expression;
+ }
+
+ public ExpressionNode getExpression() {
+ return expression;
+ }
+
+ @Override
+ public Receiver replaceExpressions(Function<ExpressionNode, ExpressionNode> replace) {
+ return new InstanceReceiver(replace.apply(expression));
+ }
+
+ @Override
+ public <T> T accept(Mapper<T> visitor) {
+ return visitor.visit(expression);
+ }
+
+ @Override
+ public <T> T accept(NodeMapper<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return "InstanceReceiver(" +
+ "expression=" + expression +
+ ')';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ InstanceReceiver that = (InstanceReceiver) o;
+
+ return expression.equals(that.expression);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return expression.hashCode();
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
index efeee93..3bae839 100644
--- a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
@@ -8,6 +8,7 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Function;
+import static org.zwobble.couscous.ast.InstanceReceiver.instanceReceiver;
import static org.zwobble.couscous.util.ExtraLists.eagerMap;
import static org.zwobble.couscous.util.ExtraLists.list;
@@ -81,30 +82,41 @@ public class MethodCallNode implements ExpressionNode {
}
public static MethodCallNode methodCall(
- ExpressionNode receiver,
- String methodName,
- List<ExpressionNode> arguments,
- TypeName type) {
+ ExpressionNode receiver,
+ String methodName,
+ List<ExpressionNode> arguments,
+ TypeName type)
+ {
+ return methodCall(instanceReceiver(receiver), methodName, arguments, type);
+ }
+
+ public static MethodCallNode methodCall(
+ Receiver receiver,
+ String methodName,
+ List<ExpressionNode> arguments,
+ TypeName type)
+ {
return new MethodCallNode(receiver, methodName, arguments, type);
}
- private final ExpressionNode receiver;
+ private final Receiver receiver;
private final String methodName;
private final List<ExpressionNode> arguments;
private final TypeName type;
- public MethodCallNode(
- ExpressionNode receiver,
- String methodName,
- List<ExpressionNode> arguments,
- TypeName type) {
+ private MethodCallNode(
+ Receiver receiver,
+ String methodName,
+ List<ExpressionNode> arguments,
+ TypeName type)
+ {
this.receiver = receiver;
this.methodName = methodName;
this.arguments = arguments;
this.type = type;
}
- public ExpressionNode getReceiver() {
+ public Receiver getReceiver() {
return receiver;
}
@@ -132,7 +144,7 @@ public class MethodCallNode implements ExpressionNode {
@Override
public ExpressionNode replaceExpressions(Function<ExpressionNode, ExpressionNode> replace) {
return new MethodCallNode(
- replace.apply(receiver),
+ receiver.replaceExpressions(replace),
methodName,
eagerMap(arguments, replace::apply),
type);
diff --git a/src/main/java/org/zwobble/couscous/ast/Node.java b/src/main/java/org/zwobble/couscous/ast/Node.java
index c9eed67..a3e7f03 100644
--- a/src/main/java/org/zwobble/couscous/ast/Node.java
+++ b/src/main/java/org/zwobble/couscous/ast/Node.java
@@ -43,12 +43,6 @@ public interface Node {
}
@Override
- public Void visit(StaticMethodCallNode staticMethodCall) {
- visitor.visit(staticMethodCall);
- return null;
- }
-
- @Override
public Void visit(ConstructorCallNode call) {
visitor.visit(call);
return null;
@@ -67,6 +61,18 @@ public interface Node {
}
@Override
+ public Void visit(InstanceReceiver receiver) {
+ visitor.visit(receiver);
+ return null;
+ }
+
+ @Override
+ public Void visit(StaticReceiver receiver) {
+ visitor.visit(receiver);
+ return null;
+ }
+
+ @Override
public Void visit(ReturnNode returnNode) {
visitor.visit(returnNode);
return null;
diff --git a/src/main/java/org/zwobble/couscous/ast/Receiver.java b/src/main/java/org/zwobble/couscous/ast/Receiver.java
new file mode 100644
index 0000000..0e0e077
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/Receiver.java
@@ -0,0 +1,13 @@
+package org.zwobble.couscous.ast;
+
+import java.util.function.Function;
+
+public interface Receiver extends Node {
+ Receiver replaceExpressions(Function<ExpressionNode, ExpressionNode> replace);
+ <T> T accept(Mapper<T> mapper);
+
+ interface Mapper<T> {
+ T visit(ExpressionNode receiver);
+ T visit(TypeName receiver);
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java
index 4676b67..f16005a 100644
--- a/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/StaticMethodCallNode.java
@@ -1,20 +1,17 @@
package org.zwobble.couscous.ast;
-import java.util.List;
-import java.util.function.Function;
-
-import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.values.BooleanValue;
import org.zwobble.couscous.values.IntegerValue;
import org.zwobble.couscous.values.InternalCouscousValue;
import org.zwobble.couscous.values.ObjectValues;
-import static java.util.Arrays.asList;
+import java.util.List;
+
+import static org.zwobble.couscous.ast.StaticReceiver.staticReceiver;
import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion;
-import static org.zwobble.couscous.util.ExtraLists.eagerMap;
import static org.zwobble.couscous.util.ExtraLists.list;
-public class StaticMethodCallNode implements ExpressionNode {
+public class StaticMethodCallNode {
public static ExpressionNode same(ExpressionNode left, ExpressionNode right) {
return staticMethodCall(InternalCouscousValue.REF, "same", list(left, right), BooleanValue.REF);
}
@@ -27,7 +24,7 @@ public class StaticMethodCallNode implements ExpressionNode {
return typeCoercion(value, IntegerValue.REF);
}
- public static StaticMethodCallNode staticMethodCall(
+ public static ExpressionNode staticMethodCall(
String className,
String methodName,
List<ExpressionNode> arguments,
@@ -35,114 +32,11 @@ public class StaticMethodCallNode implements ExpressionNode {
return staticMethodCall(TypeName.of(className), methodName, arguments, type);
}
- public static StaticMethodCallNode staticMethodCall(
- TypeName className,
- String methodName,
- List<ExpressionNode> arguments,
- TypeName type) {
- return new StaticMethodCallNode(className, methodName, arguments, type);
- }
-
- private final TypeName className;
- private final String methodName;
- private final List<ExpressionNode> arguments;
- private final TypeName type;
-
- public StaticMethodCallNode(
+ public static ExpressionNode staticMethodCall(
TypeName className,
String methodName,
List<ExpressionNode> arguments,
TypeName type) {
- this.className = className;
- this.methodName = methodName;
- this.arguments = arguments;
- this.type = type;
- }
-
- public TypeName getClassName() {
- return className;
- }
-
- public String getMethodName() {
- return methodName;
- }
-
- public List<ExpressionNode> getArguments() {
- return arguments;
- }
-
- public TypeName getType() {
- return type;
- }
-
- public MethodSignature signature() {
- return new MethodSignature(methodName, eagerMap(arguments, argument -> argument.getType()));
- }
-
- @Override
- public <T> T accept(ExpressionNodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
- public ExpressionNode replaceExpressions(Function<ExpressionNode, ExpressionNode> replace) {
- return new StaticMethodCallNode(
- className,
- methodName,
- eagerMap(arguments, replace::apply),
- type);
- }
-
- @Override
- public String toString() {
- return "StaticMethodCallNode(className=" + className + ", methodName="
- + methodName + ", arguments=" + arguments + ", type=" + type
- + ")";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((arguments == null) ? 0 : arguments.hashCode());
- result = prime * result
- + ((className == null) ? 0 : className.hashCode());
- result = prime * result
- + ((methodName == null) ? 0 : methodName.hashCode());
- result = prime * result + ((type == null) ? 0 : type.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- StaticMethodCallNode other = (StaticMethodCallNode) obj;
- if (arguments == null) {
- if (other.arguments != null)
- return false;
- } else if (!arguments.equals(other.arguments))
- return false;
- if (className == null) {
- if (other.className != null)
- return false;
- } else if (!className.equals(other.className))
- return false;
- if (methodName == null) {
- if (other.methodName != null)
- return false;
- } else if (!methodName.equals(other.methodName))
- return false;
- if (type == null) {
- if (other.type != null)
- return false;
- } else if (!type.equals(other.type))
- return false;
- return true;
+ return MethodCallNode.methodCall(staticReceiver(className), methodName, arguments, type);
}
}
diff --git a/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java
new file mode 100644
index 0000000..4d35376
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java
@@ -0,0 +1,58 @@
+package org.zwobble.couscous.ast;
+
+import org.zwobble.couscous.ast.visitors.NodeMapper;
+
+import java.util.function.Function;
+
+public class StaticReceiver implements Receiver {
+ public static Receiver staticReceiver(TypeName type) {
+ return new StaticReceiver(type);
+ }
+
+ private final TypeName type;
+
+ public StaticReceiver(TypeName type) {
+ this.type = type;
+ }
+
+ public TypeName getType() {
+ return type;
+ }
+
+ @Override
+ public Receiver replaceExpressions(Function<ExpressionNode, ExpressionNode> replace) {
+ return this;
+ }
+
+ @Override
+ public <T> T accept(Mapper<T> mapper) {
+ return mapper.visit(type);
+ }
+
+ @Override
+ public <T> T accept(NodeMapper<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public String toString() {
+ return "StaticReceiver(" +
+ "type=" + type +
+ ')';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ StaticReceiver that = (StaticReceiver) o;
+
+ return type.equals(that.type);
+ }
+
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
index 8b65f35..c2380c7 100644
--- a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
+++ b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
@@ -65,11 +65,6 @@ public class NodeStructure {
}
@Override
- public Stream<ExpressionNode> visit(StaticMethodCallNode staticMethodCall) {
- return staticMethodCall.getArguments().stream();
- }
-
- @Override
public Stream<? extends ExpressionNode> visit(ConstructorCallNode call) {
return call.getArguments().stream();
}
@@ -85,6 +80,16 @@ public class NodeStructure {
}
@Override
+ public Stream<? extends Node> visit(InstanceReceiver receiver) {
+ return Stream.of(receiver.getExpression());
+ }
+
+ @Override
+ public Stream<? extends Node> visit(StaticReceiver receiver) {
+ return Stream.empty();
+ }
+
+ @Override
public Stream<Node> visit(ReturnNode returnNode) {
return Stream.of(returnNode.getValue());
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
index 87b8598..6eab8d4 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
@@ -9,7 +9,6 @@ public interface ExpressionNodeMapper<T> {
T visit(AssignmentNode assignment);
T visit(TernaryConditionalNode ternaryConditional);
T visit(MethodCallNode methodCall);
- T visit(StaticMethodCallNode staticMethodCall);
T visit(ConstructorCallNode call);
T visit(FieldAccessNode fieldAccess);
T visit(TypeCoercionNode typeCoercion);
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
index 4267c75..fe3b4a2 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
@@ -9,11 +9,13 @@ public interface NodeMapper<T> {
T visit(AssignmentNode assignment);
T visit(TernaryConditionalNode ternaryConditional);
T visit(MethodCallNode methodCall);
- T visit(StaticMethodCallNode staticMethodCall);
T visit(ConstructorCallNode call);
T visit(FieldAccessNode fieldAccess);
T visit(TypeCoercionNode typeCoercion);
+ T visit(InstanceReceiver receiver);
+ T visit(StaticReceiver receiver);
+
T visit(ReturnNode returnNode);
T visit(ExpressionStatementNode expressionStatement);
T visit(LocalVariableDeclarationNode localVariableDeclaration);
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
index 09cfcd3..388acb1 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
@@ -40,11 +40,6 @@ public class NodeMapperWithDefault<T> implements NodeMapper<T> {
}
@Override
- public T visit(StaticMethodCallNode staticMethodCall) {
- return defaultValue;
- }
-
- @Override
public T visit(ConstructorCallNode call) {
return defaultValue;
}
@@ -60,6 +55,16 @@ public class NodeMapperWithDefault<T> implements NodeMapper<T> {
}
@Override
+ public T visit(InstanceReceiver receiver) {
+ return defaultValue;
+ }
+
+ @Override
+ public T visit(StaticReceiver receiver) {
+ return defaultValue;
+ }
+
+ @Override
public T visit(ReturnNode returnNode) {
return defaultValue;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
index 9f6be92..189a0cd 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
@@ -9,11 +9,13 @@ public interface NodeVisitor {
void visit(AssignmentNode assignment);
void visit(TernaryConditionalNode ternaryConditional);
void visit(MethodCallNode methodCall);
- void visit(StaticMethodCallNode staticMethodCall);
void visit(ConstructorCallNode call);
void visit(FieldAccessNode fieldAccess);
void visit(TypeCoercionNode typeCoercion);
+ void visit(InstanceReceiver receiver);
+ void visit(StaticReceiver receiver);
+
void visit(ReturnNode returnNode);
void visit(ExpressionStatementNode expressionStatement);
void visit(LocalVariableDeclarationNode localVariableDeclaration);
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java b/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java
index db3cd2e..403e7ac 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java
@@ -130,10 +130,6 @@ public class PrimitiveMethods {
ImmutableMap.<TypeName, Map<String, PrimitiveStaticMethodGenerator>>builder()
.put(InternalCouscousValue.REF, INTERNAL_METHODS)
.build();
-
- public static boolean isPrimitive(TypeName type) {
- return METHODS.containsKey(type);
- }
public static Optional<PrimitiveMethodGenerator> getPrimitiveMethod(TypeName type, String methodName) {
return Optional.ofNullable(METHODS.get(type))
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 32910f3..4390207 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
@@ -10,14 +10,10 @@ import org.zwobble.couscous.ast.structure.NodeStructure;
import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
import org.zwobble.couscous.ast.visitors.NodeMapperWithDefault;
import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
-import org.zwobble.couscous.backends.python.PrimitiveMethods.PrimitiveMethodGenerator;
import org.zwobble.couscous.backends.python.ast.*;
import org.zwobble.couscous.values.*;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -92,8 +88,8 @@ public class PythonCodeGenerator {
return NodeStructure.descendantNodes(classNode)
.flatMap(node -> node.accept(new NodeMapperWithDefault<Stream<TypeName>>(Stream.empty()) {
@Override
- public Stream<TypeName> visit(StaticMethodCallNode staticMethodCall) {
- return Stream.of(staticMethodCall.getClassName());
+ public Stream<TypeName> visit(StaticReceiver receiver) {
+ return Stream.of(receiver.getType());
}
@Override
@@ -238,27 +234,31 @@ public class PythonCodeGenerator {
@Override
public PythonExpressionNode visit(MethodCallNode methodCall) {
- PythonExpressionNode receiver = generateExpression(methodCall.getReceiver());
+ PythonExpressionNode receiver = generateReceiver(methodCall.getReceiver());
List<PythonExpressionNode> arguments = generateExpressions(methodCall.getArguments());
- if (isPrimitive(methodCall.getReceiver())) {
- PrimitiveMethodGenerator primitiveMethodGenerator = PrimitiveMethods.getPrimitiveMethod(methodCall.getReceiver().getType(), methodCall.getMethodName()).get();
- return primitiveMethodGenerator.generate(receiver, arguments);
- } else {
- return pythonCall(pythonAttributeAccess(receiver, toName(methodCall.signature())), arguments);
- }
+
+ return getPrimitiveMethod(methodCall, receiver, arguments)
+ .orElseGet(() -> pythonCall(pythonAttributeAccess(receiver, toName(methodCall.signature())), arguments));
}
- @Override
- public PythonExpressionNode visit(StaticMethodCallNode staticMethodCall) {
- TypeName className = staticMethodCall.getClassName();
- PythonVariableReferenceNode classReference = pythonVariableReference(className.getSimpleName());
- PythonAttributeAccessNode methodReference =
- pythonAttributeAccess(classReference, toName(staticMethodCall.signature()));
- List<PythonExpressionNode> arguments = generateExpressions(staticMethodCall.getArguments());
-
- return PrimitiveMethods.getPrimitiveStaticMethod(className, staticMethodCall.getMethodName())
- .map(generator -> generator.generate(arguments))
- .orElseGet(() -> pythonCall(methodReference, arguments));
+ private Optional<PythonExpressionNode> getPrimitiveMethod(
+ MethodCallNode methodCall,
+ PythonExpressionNode pythonReceiver,
+ List<PythonExpressionNode> pythonArguments
+ ) {
+ return methodCall.getReceiver().accept(new Receiver.Mapper<Optional<PythonExpressionNode>>() {
+ @Override
+ public Optional<PythonExpressionNode> visit(ExpressionNode receiver) {
+ return PrimitiveMethods.getPrimitiveMethod(receiver.getType(), methodCall.getMethodName())
+ .map(generator -> generator.generate(pythonReceiver, pythonArguments));
+ }
+
+ @Override
+ public Optional<PythonExpressionNode> visit(TypeName receiver) {
+ return PrimitiveMethods.getPrimitiveStaticMethod(receiver, methodCall.getMethodName())
+ .map(generator -> generator.generate(pythonArguments));
+ }
+ });
}
@Override
@@ -290,6 +290,20 @@ public class PythonCodeGenerator {
}
}
+ private static PythonExpressionNode generateReceiver(Receiver receiver) {
+ return receiver.accept(new Receiver.Mapper<PythonExpressionNode>() {
+ @Override
+ public PythonExpressionNode visit(ExpressionNode receiver) {
+ return generateExpression(receiver);
+ }
+
+ @Override
+ public PythonExpressionNode visit(TypeName receiver) {
+ return pythonVariableReference(receiver.getSimpleName());
+ }
+ });
+ }
+
private static boolean isIntegerBox(TypeCoercionNode typeCoercion) {
return isInteger(typeCoercion.getExpression().getType()) && !isInteger(typeCoercion.getType());
}
@@ -307,8 +321,4 @@ public class PythonCodeGenerator {
list(signature.getName()),
transform(signature.getArguments(), argument -> argument.getQualifiedName().replace('.', '_'))));
}
-
- private static boolean isPrimitive(ExpressionNode value) {
- return PrimitiveMethods.isPrimitive(value.getType());
- }
} \ No newline at end of file
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
index 059f2ad..e319353 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
@@ -75,23 +75,25 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
@Override
public InterpreterValue visit(MethodCallNode methodCall) {
- InterpreterValue receiver = eval(methodCall.getReceiver());
- ConcreteType type = receiver.getType();
List<InterpreterValue> arguments = evalArguments(methodCall.getArguments());
MethodSignature signature = new MethodSignature(
methodCall.getMethodName(),
eagerMap(methodCall.getArguments(), argument -> argument.getType()));
- 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());
- MethodSignature signature = new MethodSignature(
- staticMethodCall.getMethodName(),
- eagerMap(arguments, argument -> argument.getType().getName()));
- return clazz.callStaticMethod(environment, signature, arguments);
+
+ return methodCall.getReceiver().accept(new Receiver.Mapper<InterpreterValue>() {
+ @Override
+ public InterpreterValue visit(ExpressionNode receiverExpression) {
+ InterpreterValue receiver = eval(receiverExpression);
+ ConcreteType type = receiver.getType();
+ return type.callMethod(environment, receiver, signature, arguments);
+ }
+
+ @Override
+ public InterpreterValue visit(TypeName receiver) {
+ ConcreteType clazz = environment.findClass(receiver);
+ return clazz.callStaticMethod(environment, signature, arguments);
+ }
+ });
}
@Override
diff --git a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
index e74ac78..6b0009a 100644
--- a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
@@ -1,15 +1,6 @@
package org.zwobble.couscous.tests;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
+import com.google.common.base.Joiner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -20,7 +11,15 @@ import org.zwobble.couscous.util.ExtraArrays;
import org.zwobble.couscous.values.PrimitiveValue;
import org.zwobble.couscous.values.StringValue;
-import com.google.common.base.Joiner;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
@@ -50,12 +49,13 @@ public class ValueObjectTests {
{FieldDeclarationNode.class},
{FormalArgumentNode.class},
{IfStatementNode.class},
+ {InstanceReceiver.class},
{LiteralNode.class},
{LocalVariableDeclarationNode.class},
{MethodCallNode.class},
{MethodNode.class},
{ReturnNode.class},
- {StaticMethodCallNode.class},
+ {StaticReceiver.class},
{TernaryConditionalNode.class},
{ThisReferenceNode.class},
{TypeCoercionNode.class},
@@ -140,6 +140,8 @@ public class ValueObjectTests {
return generateFirstInstance(StringValue.class);
} else if (type.equals(ExpressionNode.class)) {
return generateFirstInstance(LiteralNode.class);
+ } else if (type.equals(Receiver.class)) {
+ return generateFirstInstance(InstanceReceiver.class);
} else if (type.equals(AssignableExpressionNode.class)) {
return generateFirstInstance(VariableReferenceNode.class);
} else {
@@ -162,6 +164,8 @@ public class ValueObjectTests {
return generateSecondInstance(StringValue.class);
} else if (type.equals(ExpressionNode.class)) {
return generateSecondInstance(LiteralNode.class);
+ } else if (type.equals(Receiver.class)) {
+ return generateSecondInstance(InstanceReceiver.class);
} else if (type.equals(AssignableExpressionNode.class)) {
return generateSecondInstance(VariableReferenceNode.class);
} else {
@@ -184,6 +188,8 @@ public class ValueObjectTests {
return generateInstance(StringValue.class);
} else if (type.equals(ExpressionNode.class)) {
return generateInstance(LiteralNode.class);
+ } else if (type.equals(Receiver.class)) {
+ return generateInstance(InstanceReceiver.class);
} else if (type.equals(AssignableExpressionNode.class)) {
return generateInstance(VariableReferenceNode.class);
} else {
@@ -221,7 +227,7 @@ public class ValueObjectTests {
}
private static boolean isStaticConstructor(Class<?> type, Class<?>[] fieldTypes, Method method) {
- return method.getReturnType().equals(type) &&
+ return method.getReturnType().isAssignableFrom(type) &&
asList(fieldTypes).equals(asList(method.getParameterTypes()));
}
diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
index 75b3b62..fc27d75 100644
--- a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
@@ -207,7 +207,7 @@ public class JavaReaderTests {
@Test
public void argumentIsBoxedIfNecessary() {
- StaticMethodCallNode expression = (StaticMethodCallNode) readExpression(
+ MethodCallNode expression = (MethodCallNode) readExpression(
"String",
"java.util.Objects.toString(42)");
assertEquals(