aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java33
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java33
-rw-r--r--src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java19
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java12
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java13
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Executor.java13
6 files changed, 49 insertions, 74 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java
index 243dde1..0637c44 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java
@@ -1,29 +1,26 @@
package org.zwobble.couscous.ast.visitors;
-import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
import org.zwobble.couscous.ast.Node;
+import java.util.HashMap;
+import java.util.Map;
import java.util.function.Function;
-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) {
- return new DynamicNodeMapper<>(
- DynamicNodeVisitor.buildClassSupplier(clazz, Function.class, methodName, MethodReturn.REFERENCE)
- );
- }
+import static org.zwobble.couscous.util.ExtraMaps.entry;
- private final Function<T, Function> visitor;
-
- public DynamicNodeMapper(Function<T, Function> visitor) {
- this.visitor = visitor;
- }
+public class DynamicNodeMapper {
+ private static final Map<Map.Entry<Class<?>, String>, Function<?, Function>> VISITOR_BUILDERS
+ = new HashMap<>();
- public Function<Node, R> instantiate(T instance) {
- return visitor.apply(instance);
+ // TODO: check return type -- at the very least, check the methods are consistent.
+ public static <T, R> Function<Node, R> instantiate(T visitor, String methodName) {
+ Map.Entry<Class<?>, String> key = entry(visitor.getClass(), methodName);
+ Function builder = VISITOR_BUILDERS.get(key);
+ if (builder == null) {
+ builder = DynamicNodeVisitor.buildClassSupplier(visitor.getClass(), Function.class, methodName, MethodReturn.REFERENCE);
+ VISITOR_BUILDERS.put(key, builder);
+ }
+ return (Function<Node, R>) builder.apply(visitor);
}
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java
index aed1253..438bcea 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java
@@ -25,9 +25,7 @@ import org.zwobble.couscous.util.asm.StackManipulationSwitch;
import org.zwobble.couscous.util.asm.TypeDescriptions;
import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -36,6 +34,7 @@ import static java.util.Arrays.asList;
import static org.zwobble.couscous.util.ExtraIterables.lazyMap;
import static org.zwobble.couscous.util.ExtraLists.eagerFilter;
import static org.zwobble.couscous.util.ExtraLists.eagerMap;
+import static org.zwobble.couscous.util.ExtraMaps.entry;
/**
* Dynamically generate a method to dispatch methods based on node type.
@@ -82,10 +81,18 @@ import static org.zwobble.couscous.util.ExtraLists.eagerMap;
* (which affects which node types later stages are required to handle).
* </p>
*/
-public class DynamicNodeVisitor<T> {
- public static <T> DynamicNodeVisitor<T> build(Class<T> clazz, String methodName) {
- Function<T, Consumer> builder = buildClassSupplier(clazz, Consumer.class, methodName, MethodReturn.VOID);
- return new DynamicNodeVisitor<>(builder);
+public class DynamicNodeVisitor {
+ private static final Map<Map.Entry<Class<?>, String>, Function<?, Consumer>> VISITOR_BUILDERS
+ = new HashMap<>();
+
+ public static <T> Consumer<Node> instantiate(T visitor, String methodName) {
+ Map.Entry<Class<?>, String> key = entry(visitor.getClass(), methodName);
+ Function builder = VISITOR_BUILDERS.get(key);
+ if (builder == null) {
+ builder = buildClassSupplier(visitor.getClass(), Consumer.class, methodName, MethodReturn.VOID);
+ VISITOR_BUILDERS.put(key, builder);
+ }
+ return (Consumer<Node>) builder.apply(visitor);
}
public static <T> BiConsumer<Node, T> visitor(Class<T> clazz) {
@@ -98,7 +105,7 @@ public class DynamicNodeVisitor<T> {
return (node, visitor) -> classSupplier.apply(visitor).accept(node);
}
- public static <T, F> Function<T, F> buildClassSupplier(Class<T> clazz, Class<F> function, String methodName, MethodReturn methodReturn) {
+ static <T, F> Function<T, F> buildClassSupplier(Class<T> clazz, Class<F> function, String methodName, MethodReturn methodReturn) {
Class<? extends F> visitorClass = buildClass(clazz, function, methodName, methodReturn);
try {
@@ -208,14 +215,4 @@ public class DynamicNodeVisitor<T> {
Node.class.isAssignableFrom(method.getParameterTypes()[0]) &&
!method.getParameterTypes()[0].equals(Node.class);
}
-
- private final Function<T, Consumer> visitor;
-
- private DynamicNodeVisitor(Function<T, Consumer> visitor) {
- this.visitor = visitor;
- }
-
- public Consumer<Node> instantiate(T instance) {
- return visitor.apply(instance);
- }
}
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 8765b9b..91a4400 100644
--- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
+++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
@@ -132,11 +132,9 @@ public class CsharpSerializer {
private CsharpSerializer(SourceCodeWriter writer) {
this.writer = writer;
- this.write = WRITE_BUILDER.instantiate(this);
+ this.write = DynamicNodeVisitor.instantiate(this, "visit");
}
- private static final DynamicNodeVisitor<CsharpSerializer> WRITE_BUILDER = DynamicNodeVisitor.build(CsharpSerializer.class, "visit");
-
private void write(Node node) {
write.accept(node);
}
@@ -675,13 +673,14 @@ public class CsharpSerializer {
}
}
- private static final Function<Node, Integer> precedence = DynamicNodeMapper.build(
- Precedence.class,
- Integer.class,
- "visit"
- ).instantiate(new Precedence());
+ private static int precedence(Node node) {
+ return Precedence.OF.apply(node);
+ }
public static class Precedence {
+ private final static Function<Node, Integer> OF =
+ DynamicNodeMapper.instantiate(new Precedence(), "visit");
+
public Integer visit(LiteralNode literal) {
return Integer.MAX_VALUE;
}
@@ -770,8 +769,4 @@ public class CsharpSerializer {
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 be3b81f..993b6aa 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
@@ -4,7 +4,6 @@ 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;
@@ -114,17 +113,14 @@ public class PythonCodeGenerator {
private static Set<ScalarType> findReferencedClasses(TypeNode classNode) {
return NodeStructure.descendantNodes(classNode)
- .flatMap(findDirectlyReferencedClasses)
+ .flatMap(FindDirectlyReferencedClasses.VISITOR)
.collect(Collectors.toSet());
}
- 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 {
+ private static final Function<Node, Stream<ScalarType>> VISITOR =
+ DynamicNodeMapper.instantiate(new FindDirectlyReferencedClasses(), "visit");
+
public Stream<ScalarType> visit(Node node) {
return Stream.empty();
}
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 623179d..b904f0d 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
@@ -1,7 +1,6 @@
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.DynamicNodeMapper;
import org.zwobble.couscous.types.*;
@@ -20,14 +19,10 @@ 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 {
+ private static final Function<Node, Stream<Type>> VISITOR =
+ DynamicNodeMapper.instantiate(new FindReferencedTypes(), "visit");
+
public Stream<Type> visit(Node node) {
return Stream.empty();
}
@@ -58,7 +53,7 @@ public class FreeVariables {
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(findFreeTypeParameters));
+ .flatMap(FindReferencedTypes.VISITOR));
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 50fdcff..eba214b 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Executor.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java
@@ -1,6 +1,5 @@
package org.zwobble.couscous.interpreter;
-import net.bytebuddy.description.type.TypeDescription;
import org.zwobble.couscous.ast.*;
import org.zwobble.couscous.ast.visitors.DynamicNodeMapper;
import org.zwobble.couscous.ast.visitors.StatementNodeMapper;
@@ -65,17 +64,13 @@ 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(findDirectDeclarations);
+ .flatMap(FindDirectDeclarations.VISITOR);
}
- 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 {
+ private static final Function<Node, Stream<VariableNode>> VISITOR =
+ DynamicNodeMapper.instantiate(new FindDirectDeclarations(), "visit");
+
public Stream<VariableNode> visit(Node node) {
return Stream.empty();
}