aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-06-17 21:36:44 +0100
committerMichael Williamson <mike@zwobble.org>2016-06-17 21:36:54 +0100
commit54cff9ee73eadd200c6793c5d2a520f76e1aba4f (patch)
treeecf80cb2b239c351673d35ba7a727efaa9ee9b85
parent65371fd16808d9c8f34d0e0cd2ba030bcc6a7128 (diff)
Support instanceof in C# backend
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ExpressionNode.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/InstanceOfNode.java69
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Node.java6
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Operations.java3
-rw-r--r--src/main/java/org/zwobble/couscous/ast/Operator.java4
-rw-r--r--src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java1
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java1
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java5
-rw-r--r--src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java1
-rw-r--r--src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java14
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java6
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/Evaluator.java8
-rw-r--r--src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java1
-rw-r--r--src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java12
16 files changed, 137 insertions, 9 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
index 37bd436..4c104f3 100644
--- a/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ExpressionNode.java
@@ -58,6 +58,11 @@ public interface ExpressionNode extends Node {
}
@Override
+ public T visit(InstanceOfNode instanceOf) {
+ return visitor.visit(instanceOf);
+ }
+
+ @Override
public T visit(FieldAccessNode fieldAccess) {
return visitor.visit(fieldAccess);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/InstanceOfNode.java b/src/main/java/org/zwobble/couscous/ast/InstanceOfNode.java
new file mode 100644
index 0000000..21f823b
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/InstanceOfNode.java
@@ -0,0 +1,69 @@
+package org.zwobble.couscous.ast;
+
+import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
+import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.types.ScalarType;
+import org.zwobble.couscous.types.Type;
+import org.zwobble.couscous.types.Types;
+
+public class InstanceOfNode implements ExpressionNode {
+ private final ExpressionNode left;
+ private final ScalarType right;
+
+ public InstanceOfNode(ExpressionNode left, ScalarType right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ public ExpressionNode getLeft() {
+ return left;
+ }
+
+ public ScalarType getRight() {
+ return right;
+ }
+
+ @Override
+ public Type getType() {
+ return Types.BOOLEAN;
+ }
+
+ @Override
+ public <T> T accept(ExpressionNodeMapper<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public ExpressionNode transform(NodeTransformer transformer) {
+ return new InstanceOfNode(
+ transformer.transformExpression(left),
+ transformer.transform(right));
+ }
+
+ @Override
+ public String toString() {
+ return "InstanceOfNode(" +
+ "left=" + left +
+ ", right=" + right +
+ ')';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ InstanceOfNode that = (InstanceOfNode) o;
+
+ if (!left.equals(that.left)) return false;
+ return right.equals(that.right);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = left.hashCode();
+ result = 31 * result + right.hashCode();
+ return result;
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/Node.java b/src/main/java/org/zwobble/couscous/ast/Node.java
index 240afa4..7bea8b9 100644
--- a/src/main/java/org/zwobble/couscous/ast/Node.java
+++ b/src/main/java/org/zwobble/couscous/ast/Node.java
@@ -61,6 +61,12 @@ public interface Node {
}
@Override
+ public Void visit(InstanceOfNode instanceOf) {
+ visitor.visit(instanceOf);
+ return null;
+ }
+
+ @Override
public Void visit(FieldAccessNode fieldAccess) {
visitor.visit(fieldAccess);
return null;
diff --git a/src/main/java/org/zwobble/couscous/ast/Operations.java b/src/main/java/org/zwobble/couscous/ast/Operations.java
index ca7483f..0ef9b88 100644
--- a/src/main/java/org/zwobble/couscous/ast/Operations.java
+++ b/src/main/java/org/zwobble/couscous/ast/Operations.java
@@ -4,7 +4,6 @@ import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.types.Types;
import org.zwobble.couscous.values.InternalCouscousValue;
-import static org.zwobble.couscous.ast.LiteralNode.literal;
import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall;
import static org.zwobble.couscous.ast.TypeCoercionNode.typeCoercion;
import static org.zwobble.couscous.util.ExtraLists.list;
@@ -93,6 +92,6 @@ public class Operations {
}
public static ExpressionNode instanceOf(ExpressionNode value, ScalarType type) {
- return booleanOperation(Operator.INSTANCE_OF, value, literal(type));
+ return new InstanceOfNode(value, type);
}
}
diff --git a/src/main/java/org/zwobble/couscous/ast/Operator.java b/src/main/java/org/zwobble/couscous/ast/Operator.java
index 9dc197b..a77a135 100644
--- a/src/main/java/org/zwobble/couscous/ast/Operator.java
+++ b/src/main/java/org/zwobble/couscous/ast/Operator.java
@@ -16,9 +16,7 @@ public enum Operator {
GREATER_THAN(">", true, OperatorType.INFIX),
GREATER_THAN_OR_EQUAL(">=", true, OperatorType.INFIX),
LESS_THAN("<", true, OperatorType.INFIX),
- LESS_THAN_OR_EQUAL("<=", true, OperatorType.INFIX),
-
- INSTANCE_OF("instanceof", true, OperatorType.INFIX);
+ LESS_THAN_OR_EQUAL("<=", true, OperatorType.INFIX);
private final String symbol;
private final boolean isBoolean;
diff --git a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
index a98728b..a31e438 100644
--- a/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
+++ b/src/main/java/org/zwobble/couscous/ast/structure/NodeStructure.java
@@ -82,6 +82,11 @@ public class NodeStructure {
}
@Override
+ public Stream<? extends Node> visit(InstanceOfNode instanceOf) {
+ return Stream.of(instanceOf.getLeft());
+ }
+
+ @Override
public Stream<Node> visit(FieldAccessNode fieldAccess) {
return Stream.of(fieldAccess.getLeft());
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
index 2c8ed24..acc972a 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/ExpressionNodeMapper.java
@@ -12,6 +12,7 @@ public interface ExpressionNodeMapper<T> {
T visit(MethodCallNode methodCall);
T visit(ConstructorCallNode call);
T visit(OperationNode operation);
+ T visit(InstanceOfNode instanceOf);
T visit(FieldAccessNode fieldAccess);
T visit(TypeCoercionNode typeCoercion);
T visit(CastNode cast);
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
index 50855d8..7ceef06 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapper.java
@@ -12,6 +12,7 @@ public interface NodeMapper<T> {
T visit(MethodCallNode methodCall);
T visit(ConstructorCallNode call);
T visit(OperationNode operation);
+ T visit(InstanceOfNode instanceOf);
T visit(FieldAccessNode fieldAccess);
T visit(TypeCoercionNode typeCoercion);
T visit(CastNode cast);
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
index 9fd2617..f98fb1b 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeMapperWithDefault.java
@@ -55,6 +55,11 @@ public class NodeMapperWithDefault<T> implements NodeMapper<T> {
}
@Override
+ public T visit(InstanceOfNode instanceOf) {
+ return defaultValue;
+ }
+
+ @Override
public T visit(FieldAccessNode fieldAccess) {
return defaultValue;
}
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 0edbad9..27116ae 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeTransformer.java
@@ -76,6 +76,11 @@ public class NodeTransformer {
}
@Override
+ public Node visit(InstanceOfNode instanceOf) {
+ return transformExpression(instanceOf);
+ }
+
+ @Override
public Node visit(FieldAccessNode fieldAccess) {
return transformExpression(fieldAccess);
}
diff --git a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
index 9ac4a16..648fb5f 100644
--- a/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/ast/visitors/NodeVisitor.java
@@ -12,6 +12,7 @@ public interface NodeVisitor {
void visit(MethodCallNode methodCall);
void visit(ConstructorCallNode call);
void visit(OperationNode operation);
+ void visit(InstanceOfNode instanceOf);
void visit(FieldAccessNode fieldAccess);
void visit(TypeCoercionNode typeCoercion);
void visit(CastNode cast);
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 13a4efa..4ec0790 100644
--- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
+++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
@@ -261,6 +261,15 @@ public class CsharpSerializer implements NodeVisitor {
}
}
+ @Override
+ public void visit(InstanceOfNode instanceOf) {
+ writeParenthesized(instanceOf.getLeft(), instanceOf);
+ writer.writeSpace();
+ writer.writeKeyword("is");
+ writer.writeSpace();
+ writeTypeReference(instanceOf.getRight());
+ }
+
private void writeArguments(List<? extends ExpressionNode> arguments) {
writer.writeSymbol("(");
writer.writeCommaSeparated(arguments, this::write);
@@ -763,6 +772,11 @@ public class CsharpSerializer implements NodeVisitor {
}
@Override
+ public Integer visit(InstanceOfNode instanceOf) {
+ return 9;
+ }
+
+ @Override
public Integer visit(FieldAccessNode fieldAccess) {
return 15;
}
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 8e99347..504288d 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonCodeGenerator.java
@@ -369,6 +369,12 @@ public class PythonCodeGenerator {
}
@Override
+ public PythonExpressionNode visit(InstanceOfNode instanceOf) {
+ // TODO:
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public PythonExpressionNode visit(FieldAccessNode fieldAccess) {
return pythonAttributeAccess(generateReceiver(fieldAccess.getLeft()), fieldAccess.getFieldName());
}
diff --git a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
index 4c2a8c3..d7da3b4 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/Evaluator.java
@@ -121,6 +121,12 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
}
@Override
+ public InterpreterValue visit(InstanceOfNode instanceOf) {
+ // TODO:
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public InterpreterValue visit(FieldAccessNode fieldAccess) {
ReceiverValue left = evalReceiver(fieldAccess.getLeft());
return left.getField(fieldAccess.getFieldName());
@@ -188,4 +194,4 @@ public class Evaluator implements ExpressionNodeMapper<InterpreterValue> {
}
});
}
-} \ No newline at end of file
+}
diff --git a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
index f6096f8..dbdd483 100644
--- a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
@@ -57,6 +57,7 @@ public class ValueObjectTests {
{FormalArgumentNode.class},
{FormalTypeParameterNode.class},
{IfStatementNode.class},
+ {InstanceOfNode.class},
{InstanceReceiver.class},
{InterfaceNode.class},
{LiteralNode.class},
diff --git a/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java b/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java
index fda3980..3cb723e 100644
--- a/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java
@@ -26,9 +26,7 @@ import static org.zwobble.couscous.ast.LocalVariableDeclarationNode.localVariabl
import static org.zwobble.couscous.ast.MethodCallNode.methodCall;
import static org.zwobble.couscous.ast.MethodCallNode.staticMethodCall;
import static org.zwobble.couscous.ast.MethodSignature.signature;
-import static org.zwobble.couscous.ast.Operations.integerAdd;
-import static org.zwobble.couscous.ast.Operations.integerMultiply;
-import static org.zwobble.couscous.ast.Operations.not;
+import static org.zwobble.couscous.ast.Operations.*;
import static org.zwobble.couscous.ast.ReturnNode.returns;
import static org.zwobble.couscous.ast.TernaryConditionalNode.ternaryConditional;
import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
@@ -196,6 +194,14 @@ public class CsharpSerializerTests {
}
@Test
+ public void instanceOfIsWrittenUsingIsOperator() {
+ String output = serialize(instanceOf(
+ reference(var(TestIds.ANY_ID, "x", Types.OBJECT)),
+ ScalarType.of("X")));
+ assertEquals("x is X", output);
+ }
+
+ @Test
public void infixOperationIsBracketedWhenNecessary() {
assertEquals("1 + 2 * 3", serialize(integerAdd(literal(1), integerMultiply(literal(2), literal(3)))));
assertEquals("(1 + 2) * 3", serialize(integerMultiply(integerAdd(literal(1), literal(2)), literal(3))));