From dc601f2d7cdec8cc9c366f70be59fc0666f132cb Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 14 Jul 2016 19:06:56 +0100 Subject: Make it easier to construct visitors that close over locals --- .../couscous/ast/visitors/DynamicNodeVisitor.java | 14 +++++++++ .../zwobble/couscous/interpreter/Evaluator.java | 36 ++++++++++------------ .../java/org/zwobble/couscous/util/ExtraSets.java | 4 +++ 3 files changed, 35 insertions(+), 19 deletions(-) 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 a64b7bc..aed1253 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeVisitor.java @@ -19,6 +19,7 @@ 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.ExtraSets; import org.zwobble.couscous.util.asm.Implementations; import org.zwobble.couscous.util.asm.StackManipulationSwitch; import org.zwobble.couscous.util.asm.TypeDescriptions; @@ -26,10 +27,13 @@ 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.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; 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; @@ -84,6 +88,16 @@ public class DynamicNodeVisitor { return new DynamicNodeVisitor<>(builder); } + public static BiConsumer visitor(Class clazz) { + Set methodNames = ExtraSets.copyOf(lazyMap(asList(clazz.getDeclaredMethods()), Method::getName)); + if (methodNames.size() != 1) { + throw new UnsupportedOperationException("Multiple method names"); + } + String methodName = methodNames.iterator().next(); + Function classSupplier = buildClassSupplier(clazz, Consumer.class, methodName, MethodReturn.VOID); + return (node, visitor) -> classSupplier.apply(visitor).accept(node); + } + public static Function buildClassSupplier(Class clazz, Class function, String methodName, MethodReturn methodReturn) { Class visitorClass = buildClass(clazz, function, methodName, methodReturn); diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java index afcea8b..75eeb76 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java @@ -12,6 +12,7 @@ import org.zwobble.couscous.types.Type; import org.zwobble.couscous.types.Types; import java.util.List; +import java.util.function.BiConsumer; import java.util.stream.Collectors; import static org.zwobble.couscous.types.Types.erasure; @@ -66,29 +67,26 @@ public class Evaluator implements ExpressionNodeMapper { @Override public InterpreterValue visit(AssignmentNode assignment) { InterpreterValue value = eval(assignment.getValue()); - assignVisitor.instantiate(new Assign(value)).accept(assignment.getTarget()); + AssignableExpressionVisitor.visit.accept(assignment.getTarget(), new AssignableExpressionVisitor() { + @Override + public void visit(FieldAccessNode fieldAccess) { + ReceiverValue left = evalReceiver(fieldAccess.getLeft()); + left.setField(fieldAccess.getFieldName(), value); + } + + @Override + public void visit(VariableReferenceNode reference) { + environment.put(reference.getReferentId(), value); + } + }); return value; } - private static final DynamicNodeVisitor assignVisitor = DynamicNodeVisitor.build( - Assign.class, "visit" - ); + public interface AssignableExpressionVisitor { + BiConsumer visit = DynamicNodeVisitor.visitor(AssignableExpressionVisitor.class); - public class Assign { - private final InterpreterValue value; - - private Assign(InterpreterValue value) { - this.value = value; - } - - public void visit(FieldAccessNode fieldAccess) { - ReceiverValue left = evalReceiver(fieldAccess.getLeft()); - left.setField(fieldAccess.getFieldName(), value); - } - - public void visit(VariableReferenceNode reference) { - environment.put(reference.getReferentId(), value); - } + void visit(VariableReferenceNode node); + void visit(FieldAccessNode node); } @Override diff --git a/src/main/java/org/zwobble/couscous/util/ExtraSets.java b/src/main/java/org/zwobble/couscous/util/ExtraSets.java index 6e807c6..f1df962 100644 --- a/src/main/java/org/zwobble/couscous/util/ExtraSets.java +++ b/src/main/java/org/zwobble/couscous/util/ExtraSets.java @@ -18,4 +18,8 @@ public class ExtraSets { public static Set set(T... values) { return ImmutableSet.copyOf(values); } + + public static Set copyOf(Iterable iterable) { + return ImmutableSet.copyOf(iterable); + } } -- cgit v1.2.3