From 39556c29e0913bdb4e597d4fc629fa101c555959 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Fri, 15 Jul 2016 16:21:12 +0100 Subject: Transform subnodes in NodeTransformer --- .../java/org/zwobble/couscous/ast/NodeTypes.java | 5 + .../couscous/ast/visitors/NodeTransformer.java | 8 +- .../backends/csharp/CsharpCodeGenerator.java | 33 +--- .../couscous/backends/csharp/CsharpNodeTypes.java | 6 + .../backends/csharp/CsharpPrimitiveMethods.java | 140 --------------- .../couscous/backends/csharp/CsharpSerializer.java | 10 ++ .../csharp/primitives/CsharpPrimitiveMethods.java | 195 +++++++++++++++++++++ .../csharp/primitives/PrimitiveInstanceMethod.java | 25 +++ .../primitives/PrimitiveInstanceMethodCall.java | 51 ++++++ .../PrimitiveInstanceMethodGenerator.java | 10 ++ .../csharp/primitives/PrimitiveStaticMethod.java | 25 +++ .../primitives/PrimitiveStaticMethodCall.java | 46 +++++ .../primitives/PrimitiveStaticMethodGenerator.java | 10 ++ .../tests/ast/visitors/NodeTransformerTests.java | 57 ++++++ 14 files changed, 446 insertions(+), 175 deletions(-) create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/CsharpNodeTypes.java delete mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/primitives/CsharpPrimitiveMethods.java create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethod.java create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodCall.java create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodGenerator.java create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethod.java create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodCall.java create mode 100644 src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodGenerator.java create mode 100644 src/test/java/org/zwobble/couscous/tests/ast/visitors/NodeTransformerTests.java (limited to 'src') diff --git a/src/main/java/org/zwobble/couscous/ast/NodeTypes.java b/src/main/java/org/zwobble/couscous/ast/NodeTypes.java index 41ba8af..9a9a244 100644 --- a/src/main/java/org/zwobble/couscous/ast/NodeTypes.java +++ b/src/main/java/org/zwobble/couscous/ast/NodeTypes.java @@ -3,6 +3,9 @@ package org.zwobble.couscous.ast; import com.google.common.collect.ImmutableMap; import org.zwobble.couscous.ast.sugar.SwitchCaseNode; import org.zwobble.couscous.ast.sugar.SwitchNode; +import org.zwobble.couscous.backends.csharp.CsharpNodeTypes; +import org.zwobble.couscous.backends.csharp.primitives.PrimitiveInstanceMethodCall; +import org.zwobble.couscous.backends.csharp.primitives.PrimitiveStaticMethodCall; import java.util.Map; @@ -80,6 +83,8 @@ public class NodeTypes { .put(TypeCoercionNode.class, TYPE_COERCION) .put(VariableReferenceNode.class, VARIABLE_REFERENCE) .put(WhileNode.class, WHILE) + .put(PrimitiveInstanceMethodCall.class, CsharpNodeTypes.PRIMITIVE_INSTANCE_METHOD_CALL) + .put(PrimitiveStaticMethodCall.class, CsharpNodeTypes.PRIMITIVE_STATIC_METHOD_CALL) .build(); public static int forClass(Class nodeClass) { diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java index 78bd6ef..296e5c7 100644 --- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java +++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java @@ -126,8 +126,8 @@ public class NodeTransformer { } public ExpressionNode transformExpression(ExpressionNode expression) { - return transformExpression.apply(expression) - .orElseGet(() -> expression.transform(this)); + ExpressionNode transformed = expression.transform(this); + return transformExpression.apply(transformed).orElse(transformed); } public Receiver transformReceiver(Receiver receiver) { @@ -139,8 +139,8 @@ public class NodeTransformer { } public final Iterable transformStatement(StatementNode statement) { - return transformStatement.apply(statement) - .orElseGet(() -> list(statement.transform(this))); + StatementNode transformed = statement.transform(this); + return transformStatement.apply(transformed).orElseGet(() -> list(transformed)); } public FormalTypeParameterNode transformFormalTypeParameter(FormalTypeParameterNode typeParameter) { diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java index 537184c..4dba10e 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpCodeGenerator.java @@ -1,19 +1,14 @@ package org.zwobble.couscous.backends.csharp; import com.google.common.collect.ImmutableMap; -import org.zwobble.couscous.ast.ExpressionNode; -import org.zwobble.couscous.ast.MethodCallNode; import org.zwobble.couscous.ast.Node; -import org.zwobble.couscous.ast.Receiver; import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.backends.csharp.primitives.CsharpPrimitiveMethods; import org.zwobble.couscous.backends.naming.Naming; import org.zwobble.couscous.types.*; import java.util.Map; -import java.util.Optional; -import static org.zwobble.couscous.types.Types.erasure; -import static org.zwobble.couscous.util.Casts.tryCast; import static org.zwobble.couscous.util.ExtraLists.eagerMap; public class CsharpCodeGenerator { @@ -41,14 +36,13 @@ public class CsharpCodeGenerator { this.namespace = namespace; nodeTransformer = NodeTransformer.builder() .transformType(this::transformType) - .transformExpression(this::transformExpression) .transformMethodName(naming::methodName) .transformFieldName(name -> "_" + name) .build(); } private Node generateCode(Node node) { - return node.transform(nodeTransformer); + return node.transform(CsharpPrimitiveMethods.TRANSFORMER).transform(nodeTransformer); } private Type transformType(Type type) { @@ -87,29 +81,6 @@ public class CsharpCodeGenerator { }); } - private Optional transformExpression(ExpressionNode expression) { - return tryCast(MethodCallNode.class, expression) - .flatMap(this::transformMethodCall); - } - - private Optional transformMethodCall(MethodCallNode call) { - return call.getReceiver().accept(new Receiver.Mapper>() { - @Override - public Optional visit(ExpressionNode receiver) { - return CsharpPrimitiveMethods.getPrimitiveMethod(erasure(receiver.getType()), call.getMethodName()) - .map(generator -> generator.generate( - nodeTransformer.transformExpression(receiver), - nodeTransformer.transformExpressions(call.getArguments()))); - } - - @Override - public Optional visit(ScalarType receiver) { - return CsharpPrimitiveMethods.getPrimitiveStaticMethod(receiver, call.getMethodName()) - .map(generator -> generator.generate(nodeTransformer.transformExpressions(call.getArguments()))); - } - }); - } - private Type addPrefix(Type type, String namespace) { return type.accept(new Type.Visitor() { @Override diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpNodeTypes.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpNodeTypes.java new file mode 100644 index 0000000..11be7e5 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpNodeTypes.java @@ -0,0 +1,6 @@ +package org.zwobble.couscous.backends.csharp; + +public class CsharpNodeTypes { + public static final int PRIMITIVE_INSTANCE_METHOD_CALL = 20000; + public static final int PRIMITIVE_STATIC_METHOD_CALL = 20001; +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java deleted file mode 100644 index e5c9260..0000000 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpPrimitiveMethods.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.zwobble.couscous.backends.csharp; - -import com.google.common.collect.ImmutableMap; -import org.zwobble.couscous.ast.ExpressionNode; -import org.zwobble.couscous.ast.Operator; -import org.zwobble.couscous.types.ScalarType; -import org.zwobble.couscous.types.Types; -import org.zwobble.couscous.values.InternalCouscousValue; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static org.zwobble.couscous.ast.FieldAccessNode.fieldAccess; -import static org.zwobble.couscous.ast.MethodCallNode.methodCall; -import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall; -import static org.zwobble.couscous.ast.OperationNode.operation; -import static org.zwobble.couscous.ast.Operations.integerSubtract; -import static org.zwobble.couscous.util.ExtraLists.list; - -public class CsharpPrimitiveMethods { - private static final Map BOOLEAN_METHODS; - - static { - ImmutableMap.Builder methods = ImmutableMap.builder(); - BOOLEAN_METHODS = methods.build(); - } - - private static final Map BOXED_INT_METHODS; - - static { - ImmutableMap.Builder methods = ImmutableMap.builder(); - methods.put("toString", ((receiver, arguments) -> methodCall( - receiver, - "ToString", - list(), - Types.STRING))); - BOXED_INT_METHODS = methods.build(); - } - - private static final Map STRING_METHODS; - - static { - ImmutableMap.Builder methods = ImmutableMap.builder(); - methods.put("length", (receiver, arguments) -> fieldAccess(receiver, "Length", Types.INT)); - methods.put("substring", (receiver, arguments) -> { - ExpressionNode startIndex = arguments.get(0); - ExpressionNode endIndex = arguments.get(1); - ExpressionNode length = integerSubtract(endIndex, startIndex); - // TODO: handle length going beyond end-of-string - return methodCall( - receiver, - "Substring", - list(startIndex, length), - Types.STRING); - }); - methods.put("toLowerCase", (receiver, arguments) -> methodCall( - receiver, - "ToLower", - list(), - Types.STRING)); - methods.put("equals", (receiver, arguments) -> methodCall( - receiver, - "Equals", - arguments, - Types.STRING)); - STRING_METHODS = methods.build(); - } - - private static final Map> METHODS = - ImmutableMap.>builder() - .put(Types.BOOLEAN, BOOLEAN_METHODS) - .put(Types.STRING, STRING_METHODS) - .put(Types.BOXED_INT, BOXED_INT_METHODS) - .build(); - - private static final Map STATIC_INT_METHODS = - ImmutableMap.builder() - - .put("toString", arguments -> methodCall( - arguments.get(0), - "ToString", - list(), - Types.STRING)) - - .put("parseInt", arguments -> staticMethodCall( - ScalarType.of("int"), - "Parse", - list(arguments.get(0)), - ScalarType.of("int"))) - - .put("valueOf", arguments -> arguments.get(0)) - - .build(); - - private static final Map STATIC_STRING_METHODS = - ImmutableMap.builder() - - .put("join", arguments -> staticMethodCall( - ScalarType.of("java.lang.String"), - "join", - arguments, - Types.STRING)) - - .build(); - - private static final Map STATIC_INTERNAL_METHODS = - ImmutableMap.builder() - - .put("same", arguments -> operation(Operator.EQUALS, arguments, Types.BOOLEAN)) - - .build(); - - private static final Map> STATIC_METHODS = - ImmutableMap.>builder() - .put(Types.BOXED_INT, STATIC_INT_METHODS) - .put(Types.STRING, STATIC_STRING_METHODS) - .put(InternalCouscousValue.REF, STATIC_INTERNAL_METHODS) - .build(); - - public static Optional getPrimitiveMethod(ScalarType type, String methodName) { - return Optional.ofNullable(METHODS.get(type)) - .flatMap(methodsForType -> Optional.ofNullable(methodsForType.get(methodName))); - } - - @FunctionalInterface - public interface PrimitiveMethodGenerator { - ExpressionNode generate(ExpressionNode receiver, List arguments); - } - - public static Optional getPrimitiveStaticMethod(ScalarType type, String methodName) { - return Optional.ofNullable(STATIC_METHODS.get(type)) - .flatMap(methodsForType -> Optional.ofNullable(methodsForType.get(methodName))); - } - - @FunctionalInterface - public interface PrimitiveStaticMethodGenerator { - ExpressionNode generate(List arguments); - } -} 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 6164d04..e343071 100644 --- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java +++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java @@ -7,6 +7,8 @@ import org.zwobble.couscous.ast.sugar.SwitchNode; import org.zwobble.couscous.ast.visitors.DynamicNodeMapper; import org.zwobble.couscous.ast.visitors.DynamicNodeVisitor; import org.zwobble.couscous.backends.SourceCodeWriter; +import org.zwobble.couscous.backends.csharp.primitives.PrimitiveInstanceMethodCall; +import org.zwobble.couscous.backends.csharp.primitives.PrimitiveStaticMethodCall; import org.zwobble.couscous.types.*; import org.zwobble.couscous.util.Action; import org.zwobble.couscous.values.PrimitiveValue; @@ -141,6 +143,14 @@ public class CsharpSerializer { write.accept(node); } + public void visit(PrimitiveStaticMethodCall expression) { + write(expression.generate()); + } + + public void visit(PrimitiveInstanceMethodCall expression) { + write(expression.generate()); + } + public void visit(LiteralNode literal) { literal.getValue().accept(new PrimitiveValue.Visitor() { @Override diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/primitives/CsharpPrimitiveMethods.java b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/CsharpPrimitiveMethods.java new file mode 100644 index 0000000..6a5c084 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/CsharpPrimitiveMethods.java @@ -0,0 +1,195 @@ +package org.zwobble.couscous.backends.csharp.primitives; + +import com.google.common.collect.ImmutableMap; +import org.zwobble.couscous.ast.*; +import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.types.ScalarType; +import org.zwobble.couscous.types.Types; +import org.zwobble.couscous.values.InternalCouscousValue; + +import java.util.Map; +import java.util.Optional; + +import static org.zwobble.couscous.ast.FieldAccessNode.fieldAccess; +import static org.zwobble.couscous.ast.MethodCallNode.methodCall; +import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall; +import static org.zwobble.couscous.ast.OperationNode.operation; +import static org.zwobble.couscous.ast.Operations.boxInt; +import static org.zwobble.couscous.ast.Operations.integerSubtract; +import static org.zwobble.couscous.types.Types.erasure; +import static org.zwobble.couscous.util.Casts.tryCast; +import static org.zwobble.couscous.util.ExtraLists.list; + +public class CsharpPrimitiveMethods { + public static final NodeTransformer TRANSFORMER = NodeTransformer.builder() + .transformExpression(CsharpPrimitiveMethods::transformExpression) + .build(); + + + private static Optional transformExpression(ExpressionNode expression) { + return tryCast(MethodCallNode.class, expression) + .flatMap(CsharpPrimitiveMethods::transformMethodCall); + } + + private static Optional transformMethodCall(MethodCallNode call) { + return call.getReceiver().accept(new Receiver.Mapper>() { + @Override + public Optional visit(ExpressionNode receiver) { + return CsharpPrimitiveMethods.getPrimitiveMethod(erasure(receiver.getType()), call.getMethodName()) + .map(method -> new PrimitiveInstanceMethodCall(method, receiver, call.getArguments())); + } + + @Override + public Optional visit(ScalarType receiver) { + return CsharpPrimitiveMethods.getPrimitiveStaticMethod(receiver, call.getMethodName()) + .map(method -> new PrimitiveStaticMethodCall(method, call.getArguments())); + } + }); + } + + private static final Map BOOLEAN_METHODS; + + static { + ImmutableMap.Builder methods = ImmutableMap.builder(); + BOOLEAN_METHODS = methods.build(); + } + + private static final Map BOXED_INT_METHODS; + + static { + ImmutableMap.Builder methods = ImmutableMap.builder(); + methods.put("toString", new PrimitiveInstanceMethod( + (receiver, arguments) -> methodCall( + receiver, + "ToString", + list(), + Types.STRING + ), + Types.STRING + )); + BOXED_INT_METHODS = methods.build(); + } + + private static final Map STRING_METHODS; + + static { + ImmutableMap.Builder methods = ImmutableMap.builder(); + methods.put("length", new PrimitiveInstanceMethod( + (receiver, arguments) -> fieldAccess(receiver, "Length", Types.INT), + Types.INT + )); + methods.put("substring", new PrimitiveInstanceMethod( + (receiver, arguments) -> { + ExpressionNode startIndex = arguments.get(0); + ExpressionNode endIndex = arguments.get(1); + ExpressionNode length = integerSubtract(endIndex, startIndex); + // TODO: handle length going beyond end-of-string + return methodCall( + receiver, + "Substring", + list(startIndex, length), + Types.STRING); + }, + Types.STRING + )); + methods.put("toLowerCase", new PrimitiveInstanceMethod( + (receiver, arguments) -> methodCall( + receiver, + "ToLower", + list(), + Types.STRING + ), + Types.STRING + )); + methods.put("equals", new PrimitiveInstanceMethod( + (receiver, arguments) -> methodCall( + receiver, + "Equals", + arguments, + Types.STRING + ), + Types.STRING + )); + STRING_METHODS = methods.build(); + } + + private static final Map> METHODS = + ImmutableMap.>builder() + .put(Types.BOOLEAN, BOOLEAN_METHODS) + .put(Types.STRING, STRING_METHODS) + .put(Types.BOXED_INT, BOXED_INT_METHODS) + .build(); + + private static final Map STATIC_INT_METHODS = + ImmutableMap.builder() + + .put("toString", new PrimitiveStaticMethod( + arguments -> methodCall( + arguments.get(0), + "ToString", + list(), + Types.STRING + ), + Types.STRING + )) + + .put("parseInt", new PrimitiveStaticMethod( + arguments -> staticMethodCall( + ScalarType.of("int"), + "Parse", + list(arguments.get(0)), + ScalarType.of("int") + ), + Types.INT + )) + + .put("valueOf", new PrimitiveStaticMethod( + arguments -> boxInt(arguments.get(0)), + Types.BOXED_INT + )) + + .build(); + + private static final Map STATIC_STRING_METHODS = + ImmutableMap.builder() + + .put("join", new PrimitiveStaticMethod( + arguments -> staticMethodCall( + ScalarType.of("java.lang.String"), + "join", + arguments, + Types.STRING + ), + Types.STRING + )) + + .build(); + + private static final Map STATIC_INTERNAL_METHODS = + ImmutableMap.builder() + + .put("same", new PrimitiveStaticMethod( + arguments -> operation(Operator.EQUALS, arguments, Types.BOOLEAN), + Types.BOOLEAN + )) + + .build(); + + private static final Map> STATIC_METHODS = + ImmutableMap.>builder() + .put(Types.BOXED_INT, STATIC_INT_METHODS) + .put(Types.STRING, STATIC_STRING_METHODS) + .put(InternalCouscousValue.REF, STATIC_INTERNAL_METHODS) + .build(); + + private static Optional getPrimitiveMethod(ScalarType type, String methodName) { + return Optional.ofNullable(METHODS.get(type)) + .flatMap(methodsForType -> Optional.ofNullable(methodsForType.get(methodName))); + } + + private static Optional getPrimitiveStaticMethod(ScalarType type, String methodName) { + return Optional.ofNullable(STATIC_METHODS.get(type)) + .flatMap(methodsForType -> Optional.ofNullable(methodsForType.get(methodName))); + } + +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethod.java b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethod.java new file mode 100644 index 0000000..bb94145 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethod.java @@ -0,0 +1,25 @@ +package org.zwobble.couscous.backends.csharp.primitives; + +import org.zwobble.couscous.ast.ExpressionNode; +import org.zwobble.couscous.ast.Node; +import org.zwobble.couscous.types.Type; + +import java.util.List; + +class PrimitiveInstanceMethod { + private final PrimitiveInstanceMethodGenerator generate; + private final Type returnType; + + PrimitiveInstanceMethod(PrimitiveInstanceMethodGenerator generate, Type returnType) { + this.generate = generate; + this.returnType = returnType; + } + + public Type getReturnType() { + return returnType; + } + + public Node generate(ExpressionNode receiver, List arguments) { + return generate.generate(receiver, arguments); + } +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodCall.java b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodCall.java new file mode 100644 index 0000000..daa6de8 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodCall.java @@ -0,0 +1,51 @@ +package org.zwobble.couscous.backends.csharp.primitives; + +import org.zwobble.couscous.ast.ExpressionNode; +import org.zwobble.couscous.ast.Node; +import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.backends.csharp.CsharpNodeTypes; +import org.zwobble.couscous.types.Type; + +import java.util.List; + +import static org.zwobble.couscous.util.ExtraIterables.lazyCons; + +public class PrimitiveInstanceMethodCall implements ExpressionNode { + private final PrimitiveInstanceMethod method; + private final ExpressionNode receiver; + private final List arguments; + + public PrimitiveInstanceMethodCall(PrimitiveInstanceMethod method, ExpressionNode receiver, List arguments) { + this.method = method; + this.receiver = receiver; + this.arguments = arguments; + } + + @Override + public Type getType() { + return method.getReturnType(); + } + + @Override + public int type() { + return CsharpNodeTypes.PRIMITIVE_INSTANCE_METHOD_CALL; + } + + @Override + public Iterable childNodes() { + return lazyCons(receiver, arguments); + } + + @Override + public ExpressionNode transform(NodeTransformer transformer) { + return new PrimitiveInstanceMethodCall( + method, + transformer.transformExpression(receiver), + transformer.transformExpressions(arguments) + ); + } + + public Node generate() { + return method.generate(receiver, arguments); + } +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodGenerator.java b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodGenerator.java new file mode 100644 index 0000000..99e3a46 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveInstanceMethodGenerator.java @@ -0,0 +1,10 @@ +package org.zwobble.couscous.backends.csharp.primitives; + +import org.zwobble.couscous.ast.ExpressionNode; + +import java.util.List; + +@FunctionalInterface +interface PrimitiveInstanceMethodGenerator { + ExpressionNode generate(ExpressionNode receiver, List arguments); +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethod.java b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethod.java new file mode 100644 index 0000000..23cceb0 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethod.java @@ -0,0 +1,25 @@ +package org.zwobble.couscous.backends.csharp.primitives; + +import org.zwobble.couscous.ast.ExpressionNode; +import org.zwobble.couscous.ast.Node; +import org.zwobble.couscous.types.Type; + +import java.util.List; + +class PrimitiveStaticMethod { + private final PrimitiveStaticMethodGenerator generate; + private final Type returnType; + + PrimitiveStaticMethod(PrimitiveStaticMethodGenerator generate, Type returnType) { + this.generate = generate; + this.returnType = returnType; + } + + public Type getReturnType() { + return returnType; + } + + public Node generate(List arguments) { + return generate.generate(arguments); + } +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodCall.java b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodCall.java new file mode 100644 index 0000000..d7953ce --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodCall.java @@ -0,0 +1,46 @@ +package org.zwobble.couscous.backends.csharp.primitives; + +import org.zwobble.couscous.ast.ExpressionNode; +import org.zwobble.couscous.ast.Node; +import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.backends.csharp.CsharpNodeTypes; +import org.zwobble.couscous.types.Type; + +import java.util.List; + +public class PrimitiveStaticMethodCall implements ExpressionNode { + private final PrimitiveStaticMethod method; + private final List arguments; + + public PrimitiveStaticMethodCall(PrimitiveStaticMethod method, List arguments) { + this.method = method; + this.arguments = arguments; + } + + @Override + public Type getType() { + return method.getReturnType(); + } + + @Override + public int type() { + return CsharpNodeTypes.PRIMITIVE_STATIC_METHOD_CALL; + } + + @Override + public Iterable childNodes() { + return arguments; + } + + @Override + public ExpressionNode transform(NodeTransformer transformer) { + return new PrimitiveStaticMethodCall( + method, + transformer.transformExpressions(arguments) + ); + } + + public Node generate() { + return method.generate(arguments); + } +} diff --git a/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodGenerator.java b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodGenerator.java new file mode 100644 index 0000000..1a2e2e0 --- /dev/null +++ b/src/main/java/org/zwobble/couscous/backends/csharp/primitives/PrimitiveStaticMethodGenerator.java @@ -0,0 +1,10 @@ +package org.zwobble.couscous.backends.csharp.primitives; + +import org.zwobble.couscous.ast.ExpressionNode; + +import java.util.List; + +@FunctionalInterface +interface PrimitiveStaticMethodGenerator { + ExpressionNode generate(List arguments); +} diff --git a/src/test/java/org/zwobble/couscous/tests/ast/visitors/NodeTransformerTests.java b/src/test/java/org/zwobble/couscous/tests/ast/visitors/NodeTransformerTests.java new file mode 100644 index 0000000..7e42580 --- /dev/null +++ b/src/test/java/org/zwobble/couscous/tests/ast/visitors/NodeTransformerTests.java @@ -0,0 +1,57 @@ +package org.zwobble.couscous.tests.ast.visitors; + +import org.junit.Test; +import org.zwobble.couscous.ast.OperationNode; +import org.zwobble.couscous.ast.Operations; +import org.zwobble.couscous.ast.Operator; +import org.zwobble.couscous.ast.ReturnNode; +import org.zwobble.couscous.ast.visitors.NodeTransformer; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.zwobble.couscous.ast.ExpressionStatementNode.expressionStatement; +import static org.zwobble.couscous.ast.LiteralNode.literal; +import static org.zwobble.couscous.ast.OperationNode.operation; +import static org.zwobble.couscous.ast.ReturnNode.returns; +import static org.zwobble.couscous.util.ExtraLists.list; + +public class NodeTransformerTests { + @Test + public void subNodesAreTransformedBeforeExpression() { + NodeTransformer transformer = NodeTransformer.builder() + .transformExpression(node -> { + if (node.equals(literal(1))) { + return Optional.of(literal(2)); + } else if (node instanceof OperationNode) { + return Optional.of(operation(Operator.ADD, ((OperationNode) node).getArguments(), node.getType())); + } else { + return Optional.empty(); + } + }) + .build(); + + assertEquals( + Operations.integerAdd(literal(2), literal(3)), + transformer.transformExpression(Operations.integerMultiply(literal(1), literal(3))) + ); + } + @Test + public void subNodesAreTransformedBeforeStatement() { + NodeTransformer transformer = NodeTransformer.builder() + .transformExpression(node -> Optional.of(literal(1))) + .transformStatement(node -> { + if (node instanceof ReturnNode) { + return Optional.of(list(expressionStatement(((ReturnNode) node).getValue()))); + } else { + return Optional.empty(); + } + }) + .build(); + + assertEquals( + list(expressionStatement(literal(1))), + transformer.transformStatement(returns(literal(0))) + ); + } +} -- cgit v1.2.3