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> 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> 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 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