diff options
Diffstat (limited to 'src/main')
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(); } |
