aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-07-14 16:35:31 +0100
committerMichael Williamson <mike@zwobble.org>2016-07-14 16:35:31 +0100
commit284d439f4db00be49de12862b2610a40d84cfc81 (patch)
treea6a3161536b58ff9e5a4491d9820046096e9907c /src/main/java/org
parent6d5608b5061bc7b5e40db9c37f186cfd0d48a3e6 (diff)
Remove NodeMapper in favour of a DynamicNodeMapper
Diffstat (limited to 'src/main/java/org')
-rw-r--r--src/main/java/org/zwobble/couscous/ast/AnnotationNode.java8
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ClassNode.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ConstructorNode.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/EnumNode.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ExpressionNode.java72
-rw-r--r--src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java8
-rw-r--r--src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java8
-rw-r--r--src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/InterfaceNode.java8
-rw-r--r--src/main/java/org/zwobble/couscous/ast/MethodNode.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Node.java2
-rw-r--r--src/main/java/org/zwobble/couscous/ast/StatementNode.java42
-rw-r--r--src/main/java/org/zwobble/couscous/ast/StaticReceiver.java8
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java145
-rw-r--r--src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java246
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java66
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java68
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Executor.java28
-rw-r--r--src/main/java/org/zwobble/couscous/util/ExtraIterables.java11
20 files changed, 342 insertions, 414 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java b/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java
index 1d4b8ce..7cba234 100644
--- a/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java
@@ -1,8 +1,7 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.types.Type;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.types.Type;
import org.zwobble.couscous.util.ExtraIterables;
public class AnnotationNode implements Node {
@@ -21,11 +20,6 @@ public class AnnotationNode implements Node {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public int type() {
return NodeTypes.ANNOTATION;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
index 4664bc0..80f3d38 100644
--- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
@@ -1,7 +1,6 @@
package org.zwobble.couscous.ast;
import com.google.common.collect.Iterables;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.types.Type;
@@ -93,11 +92,6 @@ public class ClassNode implements TypeNode {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public int type() {
return NodeTypes.CLASS;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java
index cca7a31..5b49659 100644
--- a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java
@@ -1,7 +1,6 @@
package org.zwobble.couscous.ast;
import com.google.common.collect.Iterables;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import java.util.Collections;
@@ -35,11 +34,6 @@ public class ConstructorNode implements Node {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public int type() {
return NodeTypes.CONSTRUCTOR;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/EnumNode.java b/src/main/java/org/zwobble/couscous/ast/EnumNode.java
index c1db294..f207618 100644
--- a/src/main/java/org/zwobble/couscous/ast/EnumNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/EnumNode.java
@@ -1,6 +1,5 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.types.Type;
@@ -68,11 +67,6 @@ public class EnumNode implements TypeNode {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public String toString() {
return "EnumNode(" +
"name=" + name +
diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
index 4c104f3..16a47e8 100644
--- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
@@ -1,83 +1,13 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.types.Type;
import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.types.Type;
public interface ExpressionNode extends Node {
Type getType();
<T> T accept(ExpressionNodeMapper<T> visitor);
-
- @Override
- default <T> T accept(NodeMapper<T> visitor) {
- return accept(new ExpressionNodeMapper<T>() {
- @Override
- public T visit(LiteralNode literal) {
- return visitor.visit(literal);
- }
-
- @Override
- public T visit(VariableReferenceNode variableReference) {
- return visitor.visit(variableReference);
- }
-
- @Override
- public T visit(ThisReferenceNode reference) {
- return visitor.visit(reference);
- }
-
- @Override
- public T visit(ArrayNode array) {
- return visitor.visit(array);
- }
-
- @Override
- public T visit(AssignmentNode assignment) {
- return visitor.visit(assignment);
- }
-
- @Override
- public T visit(TernaryConditionalNode ternaryConditional) {
- return visitor.visit(ternaryConditional);
- }
-
- @Override
- public T visit(MethodCallNode methodCall) {
- return visitor.visit(methodCall);
- }
-
- @Override
- public T visit(ConstructorCallNode call) {
- return visitor.visit(call);
- }
-
- @Override
- public T visit(OperationNode operation) {
- return visitor.visit(operation);
- }
-
- @Override
- public T visit(InstanceOfNode instanceOf) {
- return visitor.visit(instanceOf);
- }
-
- @Override
- public T visit(FieldAccessNode fieldAccess) {
- return visitor.visit(fieldAccess);
- }
-
- @Override
- public T visit(TypeCoercionNode typeCoercion) {
- return visitor.visit(typeCoercion);
- }
- @Override
- public T visit(CastNode cast) {
- return visitor.visit(cast);
- }
- });
- }
ExpressionNode transform(NodeTransformer transformer);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java b/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java
index 59fcab8..3e23ec9 100644
--- a/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java
@@ -1,8 +1,7 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.types.Type;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.types.Type;
import org.zwobble.couscous.util.ExtraIterables;
public class FieldDeclarationNode implements Node {
@@ -41,11 +40,6 @@ public class FieldDeclarationNode implements Node {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public int type() {
return NodeTypes.FIELD_DECLARATION;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java
index 9c20aff..f1d28c1 100644
--- a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java
@@ -1,8 +1,7 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.types.Type;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.types.Type;
import org.zwobble.couscous.util.ExtraIterables;
public class FormalArgumentNode implements VariableNode, Node {
@@ -29,11 +28,6 @@ public class FormalArgumentNode implements VariableNode, Node {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public int type() {
return NodeTypes.FORMAL_ARGUMENT;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java b/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java
index d51a4a4..f7d1609 100644
--- a/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java
@@ -1,7 +1,6 @@
package org.zwobble.couscous.ast;
import org.zwobble.couscous.ast.identifiers.Identifier;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.types.TypeParameter;
import org.zwobble.couscous.util.ExtraIterables;
@@ -44,11 +43,6 @@ public class FormalTypeParameterNode implements Node {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public String toString() {
return "FormalTypeParameterNode(" +
"type=" + type +
diff --git a/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java
index d86d5d1..413c06c 100644
--- a/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java
+++ b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java
@@ -1,6 +1,5 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.util.ExtraIterables;
@@ -40,11 +39,6 @@ public class InstanceReceiver implements Receiver {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public String toString() {
return "InstanceReceiver(" +
"expression=" + expression +
diff --git a/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java
index c01df04..cba6d38 100644
--- a/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java
@@ -1,9 +1,8 @@
package org.zwobble.couscous.ast;
+import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.types.Type;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
-import org.zwobble.couscous.ast.visitors.NodeTransformer;
import java.util.List;
import java.util.Set;
@@ -56,11 +55,6 @@ public class InterfaceNode implements TypeNode {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public String toString() {
return "InterfaceNode(" +
"name=" + name +
diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java
index 143158a..5497995 100644
--- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java
@@ -2,7 +2,6 @@ package org.zwobble.couscous.ast;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.types.Type;
import org.zwobble.couscous.types.Types;
@@ -190,11 +189,6 @@ public class MethodNode implements Node {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public int type() {
return NodeTypes.METHOD;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/Node.java b/src/main/java/org/zwobble/couscous/ast/Node.java
index 32cd4d8..4039e31 100644
--- a/src/main/java/org/zwobble/couscous/ast/Node.java
+++ b/src/main/java/org/zwobble/couscous/ast/Node.java
@@ -1,11 +1,9 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
public interface Node {
int type();
Iterable<? extends Node> childNodes();
- <T> T accept(NodeMapper<T> visitor);
Node transform(NodeTransformer transformer);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/StatementNode.java b/src/main/java/org/zwobble/couscous/ast/StatementNode.java
index 4755de7..cdcd636 100644
--- a/src/main/java/org/zwobble/couscous/ast/StatementNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/StatementNode.java
@@ -1,51 +1,9 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
public interface StatementNode extends Node {
<T> T accept(StatementNodeMapper<T> visitor);
-
- @Override
- default <T> T accept(NodeMapper<T> visitor) {
- return accept(new StatementNodeMapper<T>() {
- @Override
- public T visit(ReturnNode returnNode) {
- return visitor.visit(returnNode);
- }
-
- @Override
- public T visit(ThrowNode throwNode) {
- return visitor.visit(throwNode);
- }
-
- @Override
- public T visit(ExpressionStatementNode expressionStatement) {
- return visitor.visit(expressionStatement);
- }
-
- @Override
- public T visit(LocalVariableDeclarationNode localVariableDeclaration) {
- return visitor.visit(localVariableDeclaration);
- }
-
- @Override
- public T visit(IfStatementNode ifStatement) {
- return visitor.visit(ifStatement);
- }
-
- @Override
- public T visit(WhileNode whileLoop) {
- return visitor.visit(whileLoop);
- }
-
- @Override
- public T visit(TryNode tryStatement) {
- return visitor.visit(tryStatement);
- }
- });
- }
-
StatementNode transform(NodeTransformer transformer);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java
index 34f9e13..cbef8c5 100644
--- a/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java
+++ b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java
@@ -1,8 +1,7 @@
package org.zwobble.couscous.ast;
-import org.zwobble.couscous.types.ScalarType;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.util.ExtraIterables;
public class StaticReceiver implements Receiver {
@@ -30,11 +29,6 @@ public class StaticReceiver implements Receiver {
}
@Override
- public <T> T accept(NodeMapper<T> visitor) {
- return visitor.visit(this);
- }
-
- @Override
public int type() {
return NodeTypes.STATIC_RECEIVER;
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java
new file mode 100644
index 0000000..29fb4dd
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java
@@ -0,0 +1,145 @@
+package org.zwobble.couscous.ast.visitors;
+
+import net.bytebuddy.ByteBuddy;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.modifier.FieldManifestation;
+import net.bytebuddy.description.modifier.Visibility;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.implementation.bytecode.Duplication;
+import net.bytebuddy.implementation.bytecode.StackManipulation;
+import net.bytebuddy.implementation.bytecode.Throw;
+import net.bytebuddy.implementation.bytecode.TypeCreation;
+import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
+import net.bytebuddy.implementation.bytecode.member.FieldAccess;
+import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
+import net.bytebuddy.implementation.bytecode.member.MethodReturn;
+import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.zwobble.couscous.ast.Node;
+import org.zwobble.couscous.ast.NodeTypes;
+import org.zwobble.couscous.util.ExtraIterables;
+import org.zwobble.couscous.util.asm.Implementations;
+import org.zwobble.couscous.util.asm.StackManipulationSwitch;
+import org.zwobble.couscous.util.asm.TypeDescriptions;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+
+import static java.util.Arrays.asList;
+import static org.zwobble.couscous.util.ExtraLists.eagerFilter;
+import static org.zwobble.couscous.util.ExtraLists.eagerMap;
+
+public class DynamicNodeMapper<T, R> {
+ public static <T, R> DynamicNodeMapper<T, R> build(Class<T> clazz, Class<R> returnType, String methodName) {
+ return build(clazz, new TypeDescription.ForLoadedType(returnType), methodName);
+ }
+
+ public static <T, R> DynamicNodeMapper<T, R> build(Class<T> clazz, TypeDescription returnType, String methodName) {
+ List<Method> visitMethods = eagerFilter(
+ asList(clazz.getMethods()),
+ method -> isVisitMethod(methodName, method)
+ );
+
+ Optional<Method> defaultMethod = ExtraIterables.find(
+ asList(clazz.getMethods()),
+ method ->
+ method.getName().equals(methodName) &&
+ method.getParameterCount() == 1 &&
+ method.getParameterTypes()[0].equals(Node.class)
+ );
+
+ Class<? extends Function> visitor = new ByteBuddy()
+ .subclass(Function.class)
+
+ .defineField("visitor", clazz, Visibility.PRIVATE, FieldManifestation.FINAL)
+
+ .defineConstructor(Visibility.PUBLIC)
+ .withParameters(clazz)
+ .intercept(Implementations.stackManipulation(target -> new StackManipulation.Compound(
+ // this()
+ MethodVariableAccess.REFERENCE.loadOffset(0),
+ MethodInvocation.invoke(TypeDescriptions.findConstructor(Object.class)),
+
+ // this.visitor = visitor
+ MethodVariableAccess.REFERENCE.loadOffset(0),
+ MethodVariableAccess.REFERENCE.loadOffset(1),
+ FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).putter(),
+
+ // return
+ MethodReturn.VOID
+ )))
+
+ .method(ElementMatchers.named("apply"))
+ .intercept(Implementations.stackManipulation(target -> {
+ MethodDescription typeMethod = TypeDescriptions.findMethod(Node.class, "type");
+ return new StackManipulation.Compound(
+ MethodVariableAccess.REFERENCE.loadOffset(1),
+ MethodInvocation.invoke(typeMethod),
+ new StackManipulationSwitch(
+ defaultMethod
+ .map(defaultMethodValue ->
+ new StackManipulation.Compound(
+ MethodVariableAccess.REFERENCE.loadOffset(0),
+ FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).getter(),
+ MethodVariableAccess.REFERENCE.loadOffset(1),
+ TypeCasting.to(new TypeDescription.ForLoadedType(Node.class)),
+ MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(defaultMethodValue)),
+ MethodReturn.REFERENCE
+ ))
+ .orElseGet(() -> new StackManipulation.Compound(
+ TypeCreation.of(new TypeDescription.ForLoadedType(UnsupportedOperationException.class)),
+ Duplication.SINGLE,
+ MethodInvocation.invoke(TypeDescriptions.findConstructor(UnsupportedOperationException.class)),
+ Throw.INSTANCE
+ )),
+ eagerMap(visitMethods, method -> {
+ Class<?> nodeClass = method.getParameterTypes()[0];
+ return StackManipulationSwitch.switchCase(
+ NodeTypes.forClass(nodeClass),
+ new StackManipulation.Compound(
+ MethodVariableAccess.REFERENCE.loadOffset(0),
+ FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).getter(),
+ MethodVariableAccess.REFERENCE.loadOffset(1),
+ TypeCasting.to(new TypeDescription.ForLoadedType(nodeClass)),
+ MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(method)),
+ MethodReturn.REFERENCE
+ )
+ );
+ })
+ )
+ );
+ }))
+ .make()
+ .load(DynamicNodeMapper.class.getClassLoader())
+ .getLoaded();
+
+ return new DynamicNodeMapper<T, R>(clazz, visitor);
+ }
+
+ private static boolean isVisitMethod(String methodName, Method method) {
+ return
+ method.getName().equals(methodName) &&
+ method.getParameterCount() == 1 &&
+ Node.class.isAssignableFrom(method.getParameterTypes()[0]) &&
+ !method.getParameterTypes()[0].equals(Node.class);
+ }
+
+ private final Class<T> clazz;
+ private final Class<? extends Function> visitor;
+
+ public DynamicNodeMapper(Class<T> clazz, Class<? extends Function> visitor) {
+ this.clazz = clazz;
+ this.visitor = visitor;
+ }
+
+ public Function<Node, R> instantiate(T instance) {
+ try {
+ return visitor.getConstructor(clazz).newInstance(instance);
+ } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
index 6c8a3ab..8765b9b 100644
--- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
+++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
@@ -2,8 +2,8 @@ package org.zwobble.couscous.backends.csharp;
import com.google.common.collect.ImmutableSet;
import org.zwobble.couscous.ast.*;
+import org.zwobble.couscous.ast.visitors.DynamicNodeMapper;
import org.zwobble.couscous.ast.visitors.DynamicNodeVisitor;
-import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.backends.SourceCodeWriter;
import org.zwobble.couscous.types.*;
import org.zwobble.couscous.util.Action;
@@ -12,6 +12,7 @@ import org.zwobble.couscous.values.PrimitiveValue;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Function;
import static java.util.Arrays.asList;
import static org.zwobble.couscous.util.ExtraIterables.lazyFilter;
@@ -674,186 +675,103 @@ public class CsharpSerializer {
}
}
- private int precedence(Node node) {
- return node.accept(new NodeMapper<Integer>() {
- @Override
- public Integer visit(LiteralNode literal) {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public Integer visit(VariableReferenceNode variableReference) {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public Integer visit(ThisReferenceNode reference) {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public Integer visit(ArrayNode array) {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public Integer visit(AssignmentNode assignment) {
- return 1;
- }
-
- @Override
- public Integer visit(TernaryConditionalNode ternaryConditional) {
- return 2;
- }
-
- @Override
- public Integer visit(MethodCallNode methodCall) {
- return 15;
- }
-
- @Override
- public Integer visit(ConstructorCallNode call) {
- return 13;
- }
+ private static final Function<Node, Integer> precedence = DynamicNodeMapper.build(
+ Precedence.class,
+ Integer.class,
+ "visit"
+ ).instantiate(new Precedence());
- @Override
- public Integer visit(OperationNode operation) {
- switch (operation.getOperator()) {
- case BOOLEAN_NOT:
- return 14;
- case MULTIPLY:
- case DIVIDE:
- case MOD:
- return 12;
- case ADD:
- case SUBTRACT:
- return 11;
- case LESS_THAN:
- case LESS_THAN_OR_EQUAL:
- case GREATER_THAN:
- case GREATER_THAN_OR_EQUAL:
- return 9;
- case EQUALS:
- case NOT_EQUALS:
- return 8;
- case BOOLEAN_AND:
- return 4;
- case BOOLEAN_OR:
- return 3;
- default:
- throw new UnsupportedOperationException();
- }
- }
-
- @Override
- public Integer visit(InstanceOfNode instanceOf) {
- return 9;
- }
-
- @Override
- public Integer visit(FieldAccessNode fieldAccess) {
- return 15;
- }
-
- @Override
- public Integer visit(TypeCoercionNode typeCoercion) {
- return precedence(typeCoercion.getExpression());
- }
-
- @Override
- public Integer visit(CastNode cast) {
- return 13;
- }
-
- @Override
- public Integer visit(InstanceReceiver receiver) {
- return precedence(receiver.getExpression());
- }
-
- @Override
- public Integer visit(StaticReceiver receiver) {
- return Integer.MAX_VALUE;
- }
+ public static class Precedence {
+ public Integer visit(LiteralNode literal) {
+ return Integer.MAX_VALUE;
+ }
- @Override
- public Integer visit(ReturnNode returnNode) {
- return 0;
- }
+ public Integer visit(VariableReferenceNode variableReference) {
+ return Integer.MAX_VALUE;
+ }
- @Override
- public Integer visit(ThrowNode throwNode) {
- return 0;
- }
+ public Integer visit(ThisReferenceNode reference) {
+ return Integer.MAX_VALUE;
+ }
- @Override
- public Integer visit(ExpressionStatementNode expressionStatement) {
- return 0;
- }
+ public Integer visit(ArrayNode array) {
+ return Integer.MAX_VALUE;
+ }
- @Override
- public Integer visit(LocalVariableDeclarationNode localVariableDeclaration) {
- return 0;
- }
+ public Integer visit(AssignmentNode assignment) {
+ return 1;
+ }
- @Override
- public Integer visit(IfStatementNode ifStatement) {
- return 0;
- }
+ public Integer visit(TernaryConditionalNode ternaryConditional) {
+ return 2;
+ }
- @Override
- public Integer visit(WhileNode whileLoop) {
- return 0;
- }
+ public Integer visit(MethodCallNode methodCall) {
+ return 15;
+ }
- @Override
- public Integer visit(TryNode tryStatement) {
- return 0;
- }
+ public Integer visit(ConstructorCallNode call) {
+ return 13;
+ }
- @Override
- public Integer visit(FormalTypeParameterNode parameter) {
- return 0;
+ public Integer visit(OperationNode operation) {
+ switch (operation.getOperator()) {
+ case BOOLEAN_NOT:
+ return 14;
+ case MULTIPLY:
+ case DIVIDE:
+ case MOD:
+ return 12;
+ case ADD:
+ case SUBTRACT:
+ return 11;
+ case LESS_THAN:
+ case LESS_THAN_OR_EQUAL:
+ case GREATER_THAN:
+ case GREATER_THAN_OR_EQUAL:
+ return 9;
+ case EQUALS:
+ case NOT_EQUALS:
+ return 8;
+ case BOOLEAN_AND:
+ return 4;
+ case BOOLEAN_OR:
+ return 3;
+ default:
+ throw new UnsupportedOperationException();
}
+ }
- @Override
- public Integer visit(FormalArgumentNode formalArgumentNode) {
- return 0;
- }
+ public Integer visit(InstanceOfNode instanceOf) {
+ return 9;
+ }
- @Override
- public Integer visit(AnnotationNode annotation) {
- return 0;
- }
+ public Integer visit(FieldAccessNode fieldAccess) {
+ return 15;
+ }
- @Override
- public Integer visit(MethodNode methodNode) {
- return 0;
- }
+ public Integer visit(TypeCoercionNode typeCoercion) {
+ return precedence(typeCoercion.getExpression());
+ }
- @Override
- public Integer visit(ConstructorNode constructorNode) {
- return 0;
- }
+ public Integer visit(CastNode cast) {
+ return 13;
+ }
- @Override
- public Integer visit(FieldDeclarationNode declaration) {
- return 0;
- }
+ public Integer visit(InstanceReceiver receiver) {
+ return precedence(receiver.getExpression());
+ }
- @Override
- public Integer visit(ClassNode classNode) {
- return 0;
- }
+ public Integer visit(StaticReceiver receiver) {
+ return Integer.MAX_VALUE;
+ }
- @Override
- public Integer visit(InterfaceNode interfaceNode) {
- return 0;
- }
+ public Integer visit(Node node) {
+ return 0;
+ }
+ }
- @Override
- public Integer visit(EnumNode enumNode) {
- return 0;
- }
- });
+ private static int precedence(Node node) {
+ return precedence.apply(node);
}
}
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 504288d..be3b81f 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
@@ -4,10 +4,11 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
+import net.bytebuddy.description.type.TypeDescription;
import org.zwobble.couscous.ast.*;
import org.zwobble.couscous.ast.structure.NodeStructure;
+import org.zwobble.couscous.ast.visitors.DynamicNodeMapper;
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.naming.Names;
import org.zwobble.couscous.backends.python.ast.*;
@@ -19,6 +20,7 @@ import org.zwobble.couscous.values.PrimitiveValue;
import org.zwobble.couscous.values.TypeValue;
import java.util.*;
+import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -112,36 +114,44 @@ public class PythonCodeGenerator {
private static Set<ScalarType> findReferencedClasses(TypeNode classNode) {
return NodeStructure.descendantNodes(classNode)
- .flatMap(node -> node.accept(new NodeMapperWithDefault<Stream<ScalarType>>(Stream.empty()) {
- @Override
- public Stream<ScalarType> visit(StaticReceiver receiver) {
- return Stream.of(receiver.getType());
- }
+ .flatMap(findDirectlyReferencedClasses)
+ .collect(Collectors.toSet());
+ }
- @Override
- public Stream<ScalarType> visit(ConstructorCallNode call) {
- return Stream.of(erasure(call.getType()));
- }
+ private static final Function<Node, Stream<ScalarType>> findDirectlyReferencedClasses =
+ DynamicNodeMapper.<FindDirectlyReferencedClasses, Stream<ScalarType>>build(
+ FindDirectlyReferencedClasses.class,
+ new TypeDescription.ForLoadedType(Stream.class),
+ "visit"
+ ).instantiate(new FindDirectlyReferencedClasses());
+ public static class FindDirectlyReferencedClasses {
+ public Stream<ScalarType> visit(Node node) {
+ return Stream.empty();
+ }
- @Override
- public Stream<ScalarType> visit(TypeCoercionNode typeCoercion) {
- if (isIntegerBox(typeCoercion)) {
- return Stream.of(Types.BOXED_INT);
- } else {
- return Stream.empty();
- }
- }
+ public Stream<ScalarType> visit(StaticReceiver receiver) {
+ return Stream.of(receiver.getType());
+ }
- @Override
- public Stream<ScalarType> visit(LiteralNode literal) {
- if (literal.getValue() instanceof TypeValue) {
- return Stream.of(((TypeValue)literal.getValue()).getValue());
- } else {
- return Stream.empty();
- }
- }
- }))
- .collect(Collectors.toSet());
+ public Stream<ScalarType> visit(ConstructorCallNode call) {
+ return Stream.of(erasure(call.getType()));
+ }
+
+ public Stream<ScalarType> visit(TypeCoercionNode typeCoercion) {
+ if (isIntegerBox(typeCoercion)) {
+ return Stream.of(Types.BOXED_INT);
+ } else {
+ return Stream.empty();
+ }
+ }
+
+ public Stream<ScalarType> visit(LiteralNode literal) {
+ if (literal.getValue() instanceof TypeValue) {
+ return Stream.of(((TypeValue)literal.getValue()).getValue());
+ } else {
+ return Stream.empty();
+ }
+ }
}
public static PythonExpressionNode generateCode(PrimitiveValue value) {
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
index 9fcec11..623179d 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
@@ -1,12 +1,14 @@
package org.zwobble.couscous.frontends.java;
import com.google.common.collect.ImmutableSet;
+import net.bytebuddy.description.type.TypeDescription;
import org.zwobble.couscous.ast.*;
-import org.zwobble.couscous.ast.visitors.NodeMapperWithDefault;
+import org.zwobble.couscous.ast.visitors.DynamicNodeMapper;
import org.zwobble.couscous.types.*;
import java.util.List;
import java.util.Set;
+import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -18,37 +20,45 @@ import static org.zwobble.couscous.util.ExtraLists.list;
import static org.zwobble.couscous.util.ExtraStreams.toStream;
public class FreeVariables {
+ private static final Function<Node, Stream<Type>> findFreeTypeParameters =
+ DynamicNodeMapper.<FindReferencedTypes, Stream<Type>>build(
+ FindReferencedTypes.class,
+ new TypeDescription.ForLoadedType(Stream.class),
+ "visit"
+ ).instantiate(new FindReferencedTypes());
+
+ public static class FindReferencedTypes {
+ public Stream<Type> visit(Node node) {
+ return Stream.empty();
+ }
+
+ public Stream<Type> visit(FieldDeclarationNode declaration) {
+ return Stream.of(declaration.getType());
+ }
+
+ public Stream<Type> visit(LocalVariableDeclarationNode localVariableDeclaration) {
+ return Stream.of(localVariableDeclaration.getType());
+ }
+
+ public Stream<Type> visit(MethodNode methodNode) {
+ return Stream.concat(
+ methodNode.getArguments().stream().map(argument -> argument.getType()),
+ Stream.of(methodNode.getReturnType()));
+ }
+
+ public Stream<Type> visit(ConstructorCallNode call) {
+ return Stream.of(call.getType());
+ }
+
+ public Stream<Type> visit(MethodCallNode methodCall) {
+ return methodCall.getTypeParameters().stream();
+ }
+ }
+
public static Set<TypeParameter> findFreeTypeParameters(Node root) {
// TODO: this assumes that *all* type parameters are free, which is often but not always true in inner types
Iterable<Type> types = iterable(() -> descendantNodesAndSelf(root)
- .flatMap(node -> node.accept(new NodeMapperWithDefault<Stream<Type>>(Stream.empty()) {
- @Override
- public Stream<Type> visit(FieldDeclarationNode declaration) {
- return Stream.of(declaration.getType());
- }
-
- @Override
- public Stream<Type> visit(LocalVariableDeclarationNode localVariableDeclaration) {
- return Stream.of(localVariableDeclaration.getType());
- }
-
- @Override
- public Stream<Type> visit(MethodNode methodNode) {
- return Stream.concat(
- methodNode.getArguments().stream().map(argument -> argument.getType()),
- Stream.of(methodNode.getReturnType()));
- }
-
- @Override
- public Stream<Type> visit(ConstructorCallNode call) {
- return Stream.of(call.getType());
- }
-
- @Override
- public Stream<Type> visit(MethodCallNode methodCall) {
- return methodCall.getTypeParameters().stream();
- }
- })));
+ .flatMap(findFreeTypeParameters));
return ImmutableSet.copyOf(lazyFlatMap(types, type -> type.accept(new Type.Visitor<Iterable<TypeParameter>>() {
@Override
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Executor.java b/src/main/java/org/zwobble/couscous/interpreter/Executor.java
index 9641c5e..50fdcff 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Executor.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java
@@ -1,13 +1,15 @@
package org.zwobble.couscous.interpreter;
+import net.bytebuddy.description.type.TypeDescription;
import org.zwobble.couscous.ast.*;
-import org.zwobble.couscous.ast.visitors.NodeMapperWithDefault;
+import org.zwobble.couscous.ast.visitors.DynamicNodeMapper;
import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
import org.zwobble.couscous.interpreter.values.InterpreterValue;
import org.zwobble.couscous.interpreter.values.UnitInterpreterValue;
import java.util.List;
import java.util.Optional;
+import java.util.function.Function;
import java.util.stream.Stream;
import static org.zwobble.couscous.ast.structure.NodeStructure.descendantNodesAndSelf;
@@ -63,12 +65,24 @@ public class Executor implements StatementNodeMapper<Optional<InterpreterValue>>
private static Stream<VariableNode> findDeclarations(List<StatementNode> body) {
return body.stream()
.flatMap(statement -> descendantNodesAndSelf(statement, node -> node instanceof StatementNode))
- .flatMap(node -> node.accept(new NodeMapperWithDefault<Stream<VariableNode>>(Stream.empty()) {
- @Override
- public Stream<VariableNode> visit(LocalVariableDeclarationNode localVariableDeclaration) {
- return Stream.of(localVariableDeclaration);
- }
- }));
+ .flatMap(findDirectDeclarations);
+ }
+
+ private static final Function<Node, Stream<VariableNode>> findDirectDeclarations =
+ DynamicNodeMapper.<FindDirectDeclarations, Stream<VariableNode>>build(
+ FindDirectDeclarations.class,
+ new TypeDescription.ForLoadedType(Stream.class),
+ "visit"
+ ).instantiate(new FindDirectDeclarations());
+
+ public static class FindDirectDeclarations {
+ public Stream<VariableNode> visit(Node node) {
+ return Stream.empty();
+ }
+
+ public Stream<VariableNode> visit(LocalVariableDeclarationNode localVariableDeclaration) {
+ return Stream.of(localVariableDeclaration);
+ }
}
public static Optional<InterpreterValue> exec(Environment environment, Iterable<StatementNode> statements) {
diff --git a/src/main/java/org/zwobble/couscous/util/ExtraIterables.java b/src/main/java/org/zwobble/couscous/util/ExtraIterables.java
index d8635c9..1140462 100644
--- a/src/main/java/org/zwobble/couscous/util/ExtraIterables.java
+++ b/src/main/java/org/zwobble/couscous/util/ExtraIterables.java
@@ -4,8 +4,10 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.util.Iterator;
+import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -96,6 +98,15 @@ public class ExtraIterables {
};
}
+ public static <T> Optional<T> find(Iterable<T> iterable, Predicate<T> predicate) {
+ for (T element : iterable) {
+ if (predicate.test(element)) {
+ return Optional.of(element);
+ }
+ }
+ return Optional.empty();
+ }
+
public static <T, R> Iterable<R> lazyMap(Iterable<T> iterable, Function<T, R> function) {
return new Iterable<R>() {
@Override