From 284d439f4db00be49de12862b2610a40d84cfc81 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 14 Jul 2016 16:35:31 +0100 Subject: Remove NodeMapper in favour of a DynamicNodeMapper --- .../org/zwobble/couscous/ast/AnnotationNode.java | 8 +- .../java/org/zwobble/couscous/ast/ClassNode.java | 6 - .../org/zwobble/couscous/ast/ConstructorNode.java | 6 - .../java/org/zwobble/couscous/ast/EnumNode.java | 6 - .../org/zwobble/couscous/ast/ExpressionNode.java | 72 +----- .../zwobble/couscous/ast/FieldDeclarationNode.java | 8 +- .../zwobble/couscous/ast/FormalArgumentNode.java | 8 +- .../couscous/ast/FormalTypeParameterNode.java | 6 - .../org/zwobble/couscous/ast/InstanceReceiver.java | 6 - .../org/zwobble/couscous/ast/InterfaceNode.java | 8 +- .../java/org/zwobble/couscous/ast/MethodNode.java | 6 - src/main/java/org/zwobble/couscous/ast/Node.java | 2 - .../org/zwobble/couscous/ast/StatementNode.java | 42 ---- .../org/zwobble/couscous/ast/StaticReceiver.java | 8 +- .../couscous/ast/visitors/DynamicNodeMapper.java | 145 ++++++++++++ .../couscous/backends/csharp/CsharpSerializer.java | 246 +++++++-------------- .../backends/python/PythonCodeGenerator.java | 66 +++--- .../couscous/frontends/java/FreeVariables.java | 68 +++--- .../org/zwobble/couscous/interpreter/Executor.java | 28 ++- .../org/zwobble/couscous/util/ExtraIterables.java | 11 + 20 files changed, 342 insertions(+), 414 deletions(-) create mode 100644 src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java (limited to 'src/main') diff --git a/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java b/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java index 1d4b8ce..7cba234 100644 --- a/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java +++ b/src/main/java/org/zwobble/couscous/ast/AnnotationNode.java @@ -1,8 +1,7 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.types.Type; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.types.Type; import org.zwobble.couscous.util.ExtraIterables; public class AnnotationNode implements Node { @@ -20,11 +19,6 @@ public class AnnotationNode implements Node { return type; } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public int type() { return NodeTypes.ANNOTATION; diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java index 4664bc0..80f3d38 100644 --- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java @@ -1,7 +1,6 @@ package org.zwobble.couscous.ast; import com.google.common.collect.Iterables; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.types.ScalarType; import org.zwobble.couscous.types.Type; @@ -92,11 +91,6 @@ public class ClassNode implements TypeNode { return name.getSimpleName(); } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public int type() { return NodeTypes.CLASS; diff --git a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java index cca7a31..5b49659 100644 --- a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java @@ -1,7 +1,6 @@ package org.zwobble.couscous.ast; import com.google.common.collect.Iterables; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.Collections; @@ -34,11 +33,6 @@ public class ConstructorNode implements Node { return body; } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public int type() { return NodeTypes.CONSTRUCTOR; diff --git a/src/main/java/org/zwobble/couscous/ast/EnumNode.java b/src/main/java/org/zwobble/couscous/ast/EnumNode.java index c1db294..f207618 100644 --- a/src/main/java/org/zwobble/couscous/ast/EnumNode.java +++ b/src/main/java/org/zwobble/couscous/ast/EnumNode.java @@ -1,6 +1,5 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.types.ScalarType; import org.zwobble.couscous.types.Type; @@ -67,11 +66,6 @@ public class EnumNode implements TypeNode { eagerMap(values, transformer::transformFieldName)); } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public String toString() { return "EnumNode(" + diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java index 4c104f3..16a47e8 100644 --- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java +++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java @@ -1,83 +1,13 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.types.Type; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.types.Type; public interface ExpressionNode extends Node { Type getType(); T accept(ExpressionNodeMapper visitor); - - @Override - default T accept(NodeMapper visitor) { - return accept(new ExpressionNodeMapper() { - @Override - public T visit(LiteralNode literal) { - return visitor.visit(literal); - } - - @Override - public T visit(VariableReferenceNode variableReference) { - return visitor.visit(variableReference); - } - - @Override - public T visit(ThisReferenceNode reference) { - return visitor.visit(reference); - } - - @Override - public T visit(ArrayNode array) { - return visitor.visit(array); - } - - @Override - public T visit(AssignmentNode assignment) { - return visitor.visit(assignment); - } - - @Override - public T visit(TernaryConditionalNode ternaryConditional) { - return visitor.visit(ternaryConditional); - } - - @Override - public T visit(MethodCallNode methodCall) { - return visitor.visit(methodCall); - } - - @Override - public T visit(ConstructorCallNode call) { - return visitor.visit(call); - } - - @Override - public T visit(OperationNode operation) { - return visitor.visit(operation); - } - - @Override - public T visit(InstanceOfNode instanceOf) { - return visitor.visit(instanceOf); - } - - @Override - public T visit(FieldAccessNode fieldAccess) { - return visitor.visit(fieldAccess); - } - - @Override - public T visit(TypeCoercionNode typeCoercion) { - return visitor.visit(typeCoercion); - } - @Override - public T visit(CastNode cast) { - return visitor.visit(cast); - } - }); - } ExpressionNode transform(NodeTransformer transformer); } diff --git a/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java b/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java index 59fcab8..3e23ec9 100644 --- a/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java +++ b/src/main/java/org/zwobble/couscous/ast/FieldDeclarationNode.java @@ -1,8 +1,7 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.types.Type; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.types.Type; import org.zwobble.couscous.util.ExtraIterables; public class FieldDeclarationNode implements Node { @@ -40,11 +39,6 @@ public class FieldDeclarationNode implements Node { return type; } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public int type() { return NodeTypes.FIELD_DECLARATION; diff --git a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java index 9c20aff..f1d28c1 100644 --- a/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java +++ b/src/main/java/org/zwobble/couscous/ast/FormalArgumentNode.java @@ -1,8 +1,7 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.types.Type; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.types.Type; import org.zwobble.couscous.util.ExtraIterables; public class FormalArgumentNode implements VariableNode, Node { @@ -28,11 +27,6 @@ public class FormalArgumentNode implements VariableNode, Node { return declaration.getName(); } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public int type() { return NodeTypes.FORMAL_ARGUMENT; diff --git a/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java b/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java index d51a4a4..f7d1609 100644 --- a/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java +++ b/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java @@ -1,7 +1,6 @@ package org.zwobble.couscous.ast; import org.zwobble.couscous.ast.identifiers.Identifier; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.types.TypeParameter; import org.zwobble.couscous.util.ExtraIterables; @@ -43,11 +42,6 @@ public class FormalTypeParameterNode implements Node { return new FormalTypeParameterNode(transformer.transform(type)); } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public String toString() { return "FormalTypeParameterNode(" + diff --git a/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java index d86d5d1..413c06c 100644 --- a/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java +++ b/src/main/java/org/zwobble/couscous/ast/InstanceReceiver.java @@ -1,6 +1,5 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.util.ExtraIterables; @@ -39,11 +38,6 @@ public class InstanceReceiver implements Receiver { return new InstanceReceiver(transformer.transformExpression(expression)); } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public String toString() { return "InstanceReceiver(" + diff --git a/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java index c01df04..cba6d38 100644 --- a/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java +++ b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java @@ -1,9 +1,8 @@ package org.zwobble.couscous.ast; +import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.types.ScalarType; import org.zwobble.couscous.types.Type; -import org.zwobble.couscous.ast.visitors.NodeMapper; -import org.zwobble.couscous.ast.visitors.NodeTransformer; import java.util.List; import java.util.Set; @@ -55,11 +54,6 @@ public class InterfaceNode implements TypeNode { return methods; } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public String toString() { return "InterfaceNode(" + diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java index 143158a..5497995 100644 --- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java +++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java @@ -2,7 +2,6 @@ package org.zwobble.couscous.ast; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.types.Type; import org.zwobble.couscous.types.Types; @@ -189,11 +188,6 @@ public class MethodNode implements Node { return new MethodNode(annotations, isStatic, name, typeParameters, arguments, returnType, body.map(function), overrides); } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public int type() { return NodeTypes.METHOD; diff --git a/src/main/java/org/zwobble/couscous/ast/Node.java b/src/main/java/org/zwobble/couscous/ast/Node.java index 32cd4d8..4039e31 100644 --- a/src/main/java/org/zwobble/couscous/ast/Node.java +++ b/src/main/java/org/zwobble/couscous/ast/Node.java @@ -1,11 +1,9 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; public interface Node { int type(); Iterable childNodes(); - T accept(NodeMapper visitor); Node transform(NodeTransformer transformer); } diff --git a/src/main/java/org/zwobble/couscous/ast/StatementNode.java b/src/main/java/org/zwobble/couscous/ast/StatementNode.java index 4755de7..cdcd636 100644 --- a/src/main/java/org/zwobble/couscous/ast/StatementNode.java +++ b/src/main/java/org/zwobble/couscous/ast/StatementNode.java @@ -1,51 +1,9 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; public interface StatementNode extends Node { T accept(StatementNodeMapper visitor); - - @Override - default T accept(NodeMapper visitor) { - return accept(new StatementNodeMapper() { - @Override - public T visit(ReturnNode returnNode) { - return visitor.visit(returnNode); - } - - @Override - public T visit(ThrowNode throwNode) { - return visitor.visit(throwNode); - } - - @Override - public T visit(ExpressionStatementNode expressionStatement) { - return visitor.visit(expressionStatement); - } - - @Override - public T visit(LocalVariableDeclarationNode localVariableDeclaration) { - return visitor.visit(localVariableDeclaration); - } - - @Override - public T visit(IfStatementNode ifStatement) { - return visitor.visit(ifStatement); - } - - @Override - public T visit(WhileNode whileLoop) { - return visitor.visit(whileLoop); - } - - @Override - public T visit(TryNode tryStatement) { - return visitor.visit(tryStatement); - } - }); - } - StatementNode transform(NodeTransformer transformer); } diff --git a/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java index 34f9e13..cbef8c5 100644 --- a/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java +++ b/src/main/java/org/zwobble/couscous/ast/StaticReceiver.java @@ -1,8 +1,7 @@ package org.zwobble.couscous.ast; -import org.zwobble.couscous.types.ScalarType; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.types.ScalarType; import org.zwobble.couscous.util.ExtraIterables; public class StaticReceiver implements Receiver { @@ -29,11 +28,6 @@ public class StaticReceiver implements Receiver { return mapper.visit(type); } - @Override - public T accept(NodeMapper visitor) { - return visitor.visit(this); - } - @Override public int type() { return NodeTypes.STATIC_RECEIVER; diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java new file mode 100644 index 0000000..29fb4dd --- /dev/null +++ b/src/main/java/org/zwobble/couscous/ast/visitors/DynamicNodeMapper.java @@ -0,0 +1,145 @@ +package org.zwobble.couscous.ast.visitors; + +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.modifier.FieldManifestation; +import net.bytebuddy.description.modifier.Visibility; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.bytecode.Duplication; +import net.bytebuddy.implementation.bytecode.StackManipulation; +import net.bytebuddy.implementation.bytecode.Throw; +import net.bytebuddy.implementation.bytecode.TypeCreation; +import net.bytebuddy.implementation.bytecode.assign.TypeCasting; +import net.bytebuddy.implementation.bytecode.member.FieldAccess; +import net.bytebuddy.implementation.bytecode.member.MethodInvocation; +import net.bytebuddy.implementation.bytecode.member.MethodReturn; +import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess; +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.asm.Implementations; +import org.zwobble.couscous.util.asm.StackManipulationSwitch; +import org.zwobble.couscous.util.asm.TypeDescriptions; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +import static java.util.Arrays.asList; +import static org.zwobble.couscous.util.ExtraLists.eagerFilter; +import static org.zwobble.couscous.util.ExtraLists.eagerMap; + +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) { + List visitMethods = eagerFilter( + asList(clazz.getMethods()), + method -> isVisitMethod(methodName, method) + ); + + Optional defaultMethod = ExtraIterables.find( + asList(clazz.getMethods()), + method -> + method.getName().equals(methodName) && + method.getParameterCount() == 1 && + method.getParameterTypes()[0].equals(Node.class) + ); + + Class visitor = new ByteBuddy() + .subclass(Function.class) + + .defineField("visitor", clazz, Visibility.PRIVATE, FieldManifestation.FINAL) + + .defineConstructor(Visibility.PUBLIC) + .withParameters(clazz) + .intercept(Implementations.stackManipulation(target -> new StackManipulation.Compound( + // this() + MethodVariableAccess.REFERENCE.loadOffset(0), + MethodInvocation.invoke(TypeDescriptions.findConstructor(Object.class)), + + // this.visitor = visitor + MethodVariableAccess.REFERENCE.loadOffset(0), + MethodVariableAccess.REFERENCE.loadOffset(1), + FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).putter(), + + // return + MethodReturn.VOID + ))) + + .method(ElementMatchers.named("apply")) + .intercept(Implementations.stackManipulation(target -> { + MethodDescription typeMethod = TypeDescriptions.findMethod(Node.class, "type"); + return new StackManipulation.Compound( + MethodVariableAccess.REFERENCE.loadOffset(1), + MethodInvocation.invoke(typeMethod), + new StackManipulationSwitch( + defaultMethod + .map(defaultMethodValue -> + new StackManipulation.Compound( + MethodVariableAccess.REFERENCE.loadOffset(0), + FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).getter(), + MethodVariableAccess.REFERENCE.loadOffset(1), + TypeCasting.to(new TypeDescription.ForLoadedType(Node.class)), + MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(defaultMethodValue)), + MethodReturn.REFERENCE + )) + .orElseGet(() -> new StackManipulation.Compound( + TypeCreation.of(new TypeDescription.ForLoadedType(UnsupportedOperationException.class)), + Duplication.SINGLE, + MethodInvocation.invoke(TypeDescriptions.findConstructor(UnsupportedOperationException.class)), + Throw.INSTANCE + )), + eagerMap(visitMethods, method -> { + Class nodeClass = method.getParameterTypes()[0]; + return StackManipulationSwitch.switchCase( + NodeTypes.forClass(nodeClass), + new StackManipulation.Compound( + MethodVariableAccess.REFERENCE.loadOffset(0), + FieldAccess.forField(TypeDescriptions.findField(target, "visitor")).getter(), + MethodVariableAccess.REFERENCE.loadOffset(1), + TypeCasting.to(new TypeDescription.ForLoadedType(nodeClass)), + MethodInvocation.invoke(new MethodDescription.ForLoadedMethod(method)), + MethodReturn.REFERENCE + ) + ); + }) + ) + ); + })) + .make() + .load(DynamicNodeMapper.class.getClassLoader()) + .getLoaded(); + + return new DynamicNodeMapper(clazz, visitor); + } + + private static boolean isVisitMethod(String methodName, Method method) { + return + method.getName().equals(methodName) && + method.getParameterCount() == 1 && + Node.class.isAssignableFrom(method.getParameterTypes()[0]) && + !method.getParameterTypes()[0].equals(Node.class); + } + + private final Class clazz; + private final Class visitor; + + public DynamicNodeMapper(Class clazz, Class visitor) { + this.clazz = clazz; + this.visitor = visitor; + } + + public Function instantiate(T instance) { + try { + return visitor.getConstructor(clazz).newInstance(instance); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) { + throw new RuntimeException(exception); + } + } +} 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 6c8a3ab..8765b9b 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java @@ -2,8 +2,8 @@ package org.zwobble.couscous.backends.csharp; import com.google.common.collect.ImmutableSet; import org.zwobble.couscous.ast.*; +import org.zwobble.couscous.ast.visitors.DynamicNodeMapper; import org.zwobble.couscous.ast.visitors.DynamicNodeVisitor; -import org.zwobble.couscous.ast.visitors.NodeMapper; import org.zwobble.couscous.backends.SourceCodeWriter; import org.zwobble.couscous.types.*; import org.zwobble.couscous.util.Action; @@ -12,6 +12,7 @@ import org.zwobble.couscous.values.PrimitiveValue; import java.util.List; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; import static java.util.Arrays.asList; import static org.zwobble.couscous.util.ExtraIterables.lazyFilter; @@ -674,186 +675,103 @@ public class CsharpSerializer { } } - private int precedence(Node node) { - return node.accept(new NodeMapper() { - @Override - public Integer visit(LiteralNode literal) { - return Integer.MAX_VALUE; - } - - @Override - public Integer visit(VariableReferenceNode variableReference) { - return Integer.MAX_VALUE; - } - - @Override - public Integer visit(ThisReferenceNode reference) { - return Integer.MAX_VALUE; - } - - @Override - public Integer visit(ArrayNode array) { - return Integer.MAX_VALUE; - } - - @Override - public Integer visit(AssignmentNode assignment) { - return 1; - } - - @Override - public Integer visit(TernaryConditionalNode ternaryConditional) { - return 2; - } - - @Override - public Integer visit(MethodCallNode methodCall) { - return 15; - } - - @Override - public Integer visit(ConstructorCallNode call) { - return 13; - } + private static final Function precedence = DynamicNodeMapper.build( + Precedence.class, + Integer.class, + "visit" + ).instantiate(new Precedence()); - @Override - public Integer visit(OperationNode operation) { - switch (operation.getOperator()) { - case BOOLEAN_NOT: - return 14; - case MULTIPLY: - case DIVIDE: - case MOD: - return 12; - case ADD: - case SUBTRACT: - return 11; - case LESS_THAN: - case LESS_THAN_OR_EQUAL: - case GREATER_THAN: - case GREATER_THAN_OR_EQUAL: - return 9; - case EQUALS: - case NOT_EQUALS: - return 8; - case BOOLEAN_AND: - return 4; - case BOOLEAN_OR: - return 3; - default: - throw new UnsupportedOperationException(); - } - } - - @Override - public Integer visit(InstanceOfNode instanceOf) { - return 9; - } - - @Override - public Integer visit(FieldAccessNode fieldAccess) { - return 15; - } - - @Override - public Integer visit(TypeCoercionNode typeCoercion) { - return precedence(typeCoercion.getExpression()); - } - - @Override - public Integer visit(CastNode cast) { - return 13; - } - - @Override - public Integer visit(InstanceReceiver receiver) { - return precedence(receiver.getExpression()); - } - - @Override - public Integer visit(StaticReceiver receiver) { - return Integer.MAX_VALUE; - } + public static class Precedence { + public Integer visit(LiteralNode literal) { + return Integer.MAX_VALUE; + } - @Override - public Integer visit(ReturnNode returnNode) { - return 0; - } + public Integer visit(VariableReferenceNode variableReference) { + return Integer.MAX_VALUE; + } - @Override - public Integer visit(ThrowNode throwNode) { - return 0; - } + public Integer visit(ThisReferenceNode reference) { + return Integer.MAX_VALUE; + } - @Override - public Integer visit(ExpressionStatementNode expressionStatement) { - return 0; - } + public Integer visit(ArrayNode array) { + return Integer.MAX_VALUE; + } - @Override - public Integer visit(LocalVariableDeclarationNode localVariableDeclaration) { - return 0; - } + public Integer visit(AssignmentNode assignment) { + return 1; + } - @Override - public Integer visit(IfStatementNode ifStatement) { - return 0; - } + public Integer visit(TernaryConditionalNode ternaryConditional) { + return 2; + } - @Override - public Integer visit(WhileNode whileLoop) { - return 0; - } + public Integer visit(MethodCallNode methodCall) { + return 15; + } - @Override - public Integer visit(TryNode tryStatement) { - return 0; - } + public Integer visit(ConstructorCallNode call) { + return 13; + } - @Override - public Integer visit(FormalTypeParameterNode parameter) { - return 0; + public Integer visit(OperationNode operation) { + switch (operation.getOperator()) { + case BOOLEAN_NOT: + return 14; + case MULTIPLY: + case DIVIDE: + case MOD: + return 12; + case ADD: + case SUBTRACT: + return 11; + case LESS_THAN: + case LESS_THAN_OR_EQUAL: + case GREATER_THAN: + case GREATER_THAN_OR_EQUAL: + return 9; + case EQUALS: + case NOT_EQUALS: + return 8; + case BOOLEAN_AND: + return 4; + case BOOLEAN_OR: + return 3; + default: + throw new UnsupportedOperationException(); } + } - @Override - public Integer visit(FormalArgumentNode formalArgumentNode) { - return 0; - } + public Integer visit(InstanceOfNode instanceOf) { + return 9; + } - @Override - public Integer visit(AnnotationNode annotation) { - return 0; - } + public Integer visit(FieldAccessNode fieldAccess) { + return 15; + } - @Override - public Integer visit(MethodNode methodNode) { - return 0; - } + public Integer visit(TypeCoercionNode typeCoercion) { + return precedence(typeCoercion.getExpression()); + } - @Override - public Integer visit(ConstructorNode constructorNode) { - return 0; - } + public Integer visit(CastNode cast) { + return 13; + } - @Override - public Integer visit(FieldDeclarationNode declaration) { - return 0; - } + public Integer visit(InstanceReceiver receiver) { + return precedence(receiver.getExpression()); + } - @Override - public Integer visit(ClassNode classNode) { - return 0; - } + public Integer visit(StaticReceiver receiver) { + return Integer.MAX_VALUE; + } - @Override - public Integer visit(InterfaceNode interfaceNode) { - return 0; - } + public Integer visit(Node node) { + return 0; + } + } - @Override - public Integer visit(EnumNode enumNode) { - 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 504288d..be3b81f 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java @@ -4,10 +4,11 @@ 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; import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper; -import org.zwobble.couscous.ast.visitors.NodeMapperWithDefault; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import org.zwobble.couscous.backends.naming.Names; import org.zwobble.couscous.backends.python.ast.*; @@ -19,6 +20,7 @@ import org.zwobble.couscous.values.PrimitiveValue; import org.zwobble.couscous.values.TypeValue; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -112,36 +114,44 @@ public class PythonCodeGenerator { private static Set findReferencedClasses(TypeNode classNode) { return NodeStructure.descendantNodes(classNode) - .flatMap(node -> node.accept(new NodeMapperWithDefault>(Stream.empty()) { - @Override - public Stream visit(StaticReceiver receiver) { - return Stream.of(receiver.getType()); - } + .flatMap(findDirectlyReferencedClasses) + .collect(Collectors.toSet()); + } - @Override - public Stream visit(ConstructorCallNode call) { - return Stream.of(erasure(call.getType())); - } + private static final Function> findDirectlyReferencedClasses = + DynamicNodeMapper.>build( + FindDirectlyReferencedClasses.class, + new TypeDescription.ForLoadedType(Stream.class), + "visit" + ).instantiate(new FindDirectlyReferencedClasses()); + public static class FindDirectlyReferencedClasses { + public Stream visit(Node node) { + return Stream.empty(); + } - @Override - public Stream visit(TypeCoercionNode typeCoercion) { - if (isIntegerBox(typeCoercion)) { - return Stream.of(Types.BOXED_INT); - } else { - return Stream.empty(); - } - } + public Stream visit(StaticReceiver receiver) { + return Stream.of(receiver.getType()); + } - @Override - public Stream visit(LiteralNode literal) { - if (literal.getValue() instanceof TypeValue) { - return Stream.of(((TypeValue)literal.getValue()).getValue()); - } else { - return Stream.empty(); - } - } - })) - .collect(Collectors.toSet()); + public Stream visit(ConstructorCallNode call) { + return Stream.of(erasure(call.getType())); + } + + public Stream visit(TypeCoercionNode typeCoercion) { + if (isIntegerBox(typeCoercion)) { + return Stream.of(Types.BOXED_INT); + } else { + return Stream.empty(); + } + } + + public Stream visit(LiteralNode literal) { + if (literal.getValue() instanceof TypeValue) { + return Stream.of(((TypeValue)literal.getValue()).getValue()); + } else { + return Stream.empty(); + } + } } public static PythonExpressionNode generateCode(PrimitiveValue value) { 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 9fcec11..623179d 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java @@ -1,12 +1,14 @@ 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.NodeMapperWithDefault; +import org.zwobble.couscous.ast.visitors.DynamicNodeMapper; import org.zwobble.couscous.types.*; import java.util.List; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -18,37 +20,45 @@ 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 { + public Stream visit(Node node) { + return Stream.empty(); + } + + public Stream visit(FieldDeclarationNode declaration) { + return Stream.of(declaration.getType()); + } + + public Stream visit(LocalVariableDeclarationNode localVariableDeclaration) { + return Stream.of(localVariableDeclaration.getType()); + } + + public Stream visit(MethodNode methodNode) { + return Stream.concat( + methodNode.getArguments().stream().map(argument -> argument.getType()), + Stream.of(methodNode.getReturnType())); + } + + public Stream visit(ConstructorCallNode call) { + return Stream.of(call.getType()); + } + + public Stream visit(MethodCallNode methodCall) { + return methodCall.getTypeParameters().stream(); + } + } + 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(node -> node.accept(new NodeMapperWithDefault>(Stream.empty()) { - @Override - public Stream visit(FieldDeclarationNode declaration) { - return Stream.of(declaration.getType()); - } - - @Override - public Stream visit(LocalVariableDeclarationNode localVariableDeclaration) { - return Stream.of(localVariableDeclaration.getType()); - } - - @Override - public Stream visit(MethodNode methodNode) { - return Stream.concat( - methodNode.getArguments().stream().map(argument -> argument.getType()), - Stream.of(methodNode.getReturnType())); - } - - @Override - public Stream visit(ConstructorCallNode call) { - return Stream.of(call.getType()); - } - - @Override - public Stream visit(MethodCallNode methodCall) { - return methodCall.getTypeParameters().stream(); - } - }))); + .flatMap(findFreeTypeParameters)); 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 9641c5e..50fdcff 100644 --- a/src/main/java/org/zwobble/couscous/interpreter/Executor.java +++ b/src/main/java/org/zwobble/couscous/interpreter/Executor.java @@ -1,13 +1,15 @@ package org.zwobble.couscous.interpreter; +import net.bytebuddy.description.type.TypeDescription; import org.zwobble.couscous.ast.*; -import org.zwobble.couscous.ast.visitors.NodeMapperWithDefault; +import org.zwobble.couscous.ast.visitors.DynamicNodeMapper; import org.zwobble.couscous.ast.visitors.StatementNodeMapper; import org.zwobble.couscous.interpreter.values.InterpreterValue; import org.zwobble.couscous.interpreter.values.UnitInterpreterValue; import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Stream; import static org.zwobble.couscous.ast.structure.NodeStructure.descendantNodesAndSelf; @@ -63,12 +65,24 @@ public class Executor implements StatementNodeMapper> private static Stream findDeclarations(List body) { return body.stream() .flatMap(statement -> descendantNodesAndSelf(statement, node -> node instanceof StatementNode)) - .flatMap(node -> node.accept(new NodeMapperWithDefault>(Stream.empty()) { - @Override - public Stream visit(LocalVariableDeclarationNode localVariableDeclaration) { - return Stream.of(localVariableDeclaration); - } - })); + .flatMap(findDirectDeclarations); + } + + private static final Function> findDirectDeclarations = + DynamicNodeMapper.>build( + FindDirectDeclarations.class, + new TypeDescription.ForLoadedType(Stream.class), + "visit" + ).instantiate(new FindDirectDeclarations()); + + public static class FindDirectDeclarations { + public Stream visit(Node node) { + return Stream.empty(); + } + + public Stream visit(LocalVariableDeclarationNode localVariableDeclaration) { + return Stream.of(localVariableDeclaration); + } } public static Optional exec(Environment environment, Iterable statements) { diff --git a/src/main/java/org/zwobble/couscous/util/ExtraIterables.java b/src/main/java/org/zwobble/couscous/util/ExtraIterables.java index d8635c9..1140462 100644 --- a/src/main/java/org/zwobble/couscous/util/ExtraIterables.java +++ b/src/main/java/org/zwobble/couscous/util/ExtraIterables.java @@ -4,8 +4,10 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.util.Iterator; +import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -96,6 +98,15 @@ public class ExtraIterables { }; } + public static Optional find(Iterable iterable, Predicate predicate) { + for (T element : iterable) { + if (predicate.test(element)) { + return Optional.of(element); + } + } + return Optional.empty(); + } + public static Iterable lazyMap(Iterable iterable, Function function) { return new Iterable() { @Override -- cgit v1.2.3