From 0970f5a5074da34fffaea70f3b42d012edb501c5 Mon Sep 17 00:00:00 2001
From: Michael Williamson
Date: Thu, 14 Jul 2016 22:50:55 +0100
Subject: Simplify dynamic visitor creation
---
.../couscous/ast/visitors/DynamicNodeMapper.java | 33 ++++++++++------------
.../couscous/ast/visitors/DynamicNodeVisitor.java | 33 ++++++++++------------
.../couscous/backends/csharp/CsharpSerializer.java | 19 +++++--------
.../backends/python/PythonCodeGenerator.java | 12 +++-----
.../couscous/frontends/java/FreeVariables.java | 13 +++------
.../org/zwobble/couscous/interpreter/Executor.java | 13 +++------
6 files changed, 49 insertions(+), 74 deletions(-)
(limited to 'src')
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 {
- public static DynamicNodeMapper build(Class clazz, Class returnType, String methodName) {
- return build(clazz, new TypeDescription.ForLoadedType(returnType), methodName);
- }
-
- public static DynamicNodeMapper build(Class 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 visitor;
-
- public DynamicNodeMapper(Function visitor) {
- this.visitor = visitor;
- }
+public class DynamicNodeMapper {
+ private static final Map, String>, Function, Function>> VISITOR_BUILDERS
+ = new HashMap<>();
- public Function instantiate(T instance) {
- return visitor.apply(instance);
+ // TODO: check return type -- at the very least, check the methods are consistent.
+ public static Function instantiate(T visitor, String methodName) {
+ Map.Entry, 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) 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).
*
*/
-public class DynamicNodeVisitor {
- public static DynamicNodeVisitor build(Class clazz, String methodName) {
- Function builder = buildClassSupplier(clazz, Consumer.class, methodName, MethodReturn.VOID);
- return new DynamicNodeVisitor<>(builder);
+public class DynamicNodeVisitor {
+ private static final Map, String>, Function, Consumer>> VISITOR_BUILDERS
+ = new HashMap<>();
+
+ public static Consumer instantiate(T visitor, String methodName) {
+ Map.Entry, 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) builder.apply(visitor);
}
public static BiConsumer visitor(Class clazz) {
@@ -98,7 +105,7 @@ public class DynamicNodeVisitor {
return (node, visitor) -> classSupplier.apply(visitor).accept(node);
}
- public static Function buildClassSupplier(Class clazz, Class function, String methodName, MethodReturn methodReturn) {
+ static Function buildClassSupplier(Class clazz, Class function, String methodName, MethodReturn methodReturn) {
Class extends F> visitorClass = buildClass(clazz, function, methodName, methodReturn);
try {
@@ -208,14 +215,4 @@ public class DynamicNodeVisitor {
Node.class.isAssignableFrom(method.getParameterTypes()[0]) &&
!method.getParameterTypes()[0].equals(Node.class);
}
-
- private final Function visitor;
-
- private DynamicNodeVisitor(Function visitor) {
- this.visitor = visitor;
- }
-
- public Consumer 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 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 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 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 findReferencedClasses(TypeNode classNode) {
return NodeStructure.descendantNodes(classNode)
- .flatMap(findDirectlyReferencedClasses)
+ .flatMap(FindDirectlyReferencedClasses.VISITOR)
.collect(Collectors.toSet());
}
- private static final Function> findDirectlyReferencedClasses =
- DynamicNodeMapper.>build(
- FindDirectlyReferencedClasses.class,
- new TypeDescription.ForLoadedType(Stream.class),
- "visit"
- ).instantiate(new FindDirectlyReferencedClasses());
public static class FindDirectlyReferencedClasses {
+ private static final Function> VISITOR =
+ DynamicNodeMapper.instantiate(new FindDirectlyReferencedClasses(), "visit");
+
public Stream 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> findFreeTypeParameters =
- DynamicNodeMapper.>build(
- FindReferencedTypes.class,
- new TypeDescription.ForLoadedType(Stream.class),
- "visit"
- ).instantiate(new FindReferencedTypes());
-
public static class FindReferencedTypes {
+ private static final Function> VISITOR =
+ DynamicNodeMapper.instantiate(new FindReferencedTypes(), "visit");
+
public Stream visit(Node node) {
return Stream.empty();
}
@@ -58,7 +53,7 @@ public class FreeVariables {
public static Set findFreeTypeParameters(Node root) {
// TODO: this assumes that *all* type parameters are free, which is often but not always true in inner types
Iterable types = iterable(() -> descendantNodesAndSelf(root)
- .flatMap(findFreeTypeParameters));
+ .flatMap(FindReferencedTypes.VISITOR));
return ImmutableSet.copyOf(lazyFlatMap(types, type -> type.accept(new Type.Visitor>() {
@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>
private static Stream findDeclarations(List body) {
return body.stream()
.flatMap(statement -> descendantNodesAndSelf(statement, node -> node instanceof StatementNode))
- .flatMap(findDirectDeclarations);
+ .flatMap(FindDirectDeclarations.VISITOR);
}
- private static final Function> findDirectDeclarations =
- DynamicNodeMapper.>build(
- FindDirectDeclarations.class,
- new TypeDescription.ForLoadedType(Stream.class),
- "visit"
- ).instantiate(new FindDirectDeclarations());
-
public static class FindDirectDeclarations {
+ private static final Function> VISITOR =
+ DynamicNodeMapper.instantiate(new FindDirectDeclarations(), "visit");
+
public Stream visit(Node node) {
return Stream.empty();
}
--
cgit v1.2.3