aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/org/zwobble/couscous/ast/MethodCallNode.java10
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java11
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java8
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/ast/PythonNotNode.java24
-rw-r--r--src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java2
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java19
-rw-r--r--src/main/java/org/zwobble/couscous/interpreter/values/BooleanInterpreterValue.java8
-rw-r--r--src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java11
-rw-r--r--src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java2
-rw-r--r--src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java6
-rw-r--r--src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java4
11 files changed, 98 insertions, 7 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
index a9b8795..c2e0897 100644
--- a/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/MethodCallNode.java
@@ -1,10 +1,20 @@
package org.zwobble.couscous.ast;
+import java.util.Collections;
import java.util.List;
import org.zwobble.couscous.ast.visitors.ExpressionNodeMapper;
+import org.zwobble.couscous.values.BooleanValue;
public class MethodCallNode implements ExpressionNode {
+ public static ExpressionNode not(ExpressionNode value) {
+ if (value.getType().equals(BooleanValue.REF)) {
+ return methodCall(value, "negate", Collections.emptyList(), BooleanValue.REF);
+ } else {
+ throw new IllegalArgumentException("Can only negate booleans");
+ }
+ }
+
public static MethodCallNode methodCall(
ExpressionNode receiver,
String methodName,
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java b/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java
index 9639c72..c6aa62d 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java
@@ -6,6 +6,8 @@ import java.util.Optional;
import org.zwobble.couscous.ast.TypeName;
import org.zwobble.couscous.backends.python.ast.PythonExpressionNode;
+import org.zwobble.couscous.backends.python.ast.PythonNotNode;
+import org.zwobble.couscous.values.BooleanValue;
import org.zwobble.couscous.values.IntegerValue;
import org.zwobble.couscous.values.StringValue;
@@ -32,6 +34,14 @@ public class PrimitiveMethods {
.build();
+ private static final Map<String, PrimitiveMethodGenerator> BOOLEAN_METHODS =
+ ImmutableMap.<String, PrimitiveMethodGenerator>builder()
+
+ .put("negate", (receiver, arguments) ->
+ PythonNotNode.pythonNot(receiver))
+
+ .build();
+
private static final Map<String, PrimitiveMethodGenerator> INT_METHODS;
static {
@@ -76,6 +86,7 @@ public class PrimitiveMethods {
private static final Map<TypeName, Map<String, PrimitiveMethodGenerator>> METHODS =
ImmutableMap.<TypeName, Map<String, PrimitiveMethodGenerator>>builder()
.put(StringValue.REF, STRING_METHODS)
+ .put(BooleanValue.REF, BOOLEAN_METHODS)
.put(IntegerValue.REF, INT_METHODS)
.build();
diff --git a/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java b/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java
index 1674e1f..eadb545 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java
@@ -16,6 +16,7 @@ import org.zwobble.couscous.backends.python.ast.PythonImportNode;
import org.zwobble.couscous.backends.python.ast.PythonIntegerLiteralNode;
import org.zwobble.couscous.backends.python.ast.PythonModuleNode;
import org.zwobble.couscous.backends.python.ast.PythonNode;
+import org.zwobble.couscous.backends.python.ast.PythonNotNode;
import org.zwobble.couscous.backends.python.ast.PythonPassNode;
import org.zwobble.couscous.backends.python.ast.PythonReturnNode;
import org.zwobble.couscous.backends.python.ast.PythonStatementNode;
@@ -103,6 +104,13 @@ public class PythonSerializer implements PythonNodeVisitor {
});
writer.writeSymbol("]");
}
+
+ @Override
+ public void visit(PythonNotNode notOperation) {
+ writer.writeKeyword("not");
+ writer.writeSpace();
+ writeParenthesised(notOperation.getOperand());
+ }
@Override
public void visit(PythonReturnNode pythonReturn) {
diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonNotNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonNotNode.java
new file mode 100644
index 0000000..6fe7dc6
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonNotNode.java
@@ -0,0 +1,24 @@
+package org.zwobble.couscous.backends.python.ast;
+
+import org.zwobble.couscous.backends.python.ast.visitors.PythonNodeVisitor;
+
+public class PythonNotNode implements PythonExpressionNode {
+ public static PythonExpressionNode pythonNot(PythonExpressionNode operand) {
+ return new PythonNotNode(operand);
+ }
+
+ private final PythonExpressionNode operand;
+
+ private PythonNotNode(PythonExpressionNode operand) {
+ this.operand = operand;
+ }
+
+ public PythonExpressionNode getOperand() {
+ return operand;
+ }
+
+ @Override
+ public void accept(PythonNodeVisitor visitor) {
+ visitor.visit(this);
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java b/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java
index 7632342..59a1fe9 100644
--- a/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java
+++ b/src/main/java/org/zwobble/couscous/backends/python/ast/visitors/PythonNodeVisitor.java
@@ -11,6 +11,7 @@ import org.zwobble.couscous.backends.python.ast.PythonGetSliceNode;
import org.zwobble.couscous.backends.python.ast.PythonImportNode;
import org.zwobble.couscous.backends.python.ast.PythonIntegerLiteralNode;
import org.zwobble.couscous.backends.python.ast.PythonModuleNode;
+import org.zwobble.couscous.backends.python.ast.PythonNotNode;
import org.zwobble.couscous.backends.python.ast.PythonPassNode;
import org.zwobble.couscous.backends.python.ast.PythonReturnNode;
import org.zwobble.couscous.backends.python.ast.PythonStringLiteralNode;
@@ -25,6 +26,7 @@ public interface PythonNodeVisitor {
void visit(PythonAttributeAccessNode attributeAccess);
void visit(PythonCallNode call);
void visit(PythonGetSliceNode getSlice);
+ void visit(PythonNotNode notOperation);
void visit(PythonReturnNode pythonReturn);
void visit(PythonPassNode pass);
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
index 99d6a7a..6c4c0c8 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
@@ -57,6 +57,7 @@ import com.google.common.collect.Lists;
import static java.util.Arrays.asList;
import static org.zwobble.couscous.ast.ExpressionStatementNode.expressionStatement;
import static org.zwobble.couscous.ast.LocalVariableDeclarationNode.localVariableDeclaration;
+import static org.zwobble.couscous.ast.MethodCallNode.methodCall;
import static org.zwobble.couscous.ast.VariableDeclaration.var;
import static org.zwobble.couscous.ast.VariableReferenceNode.reference;
@@ -261,12 +262,18 @@ public class JavaReader {
}
private static ExpressionNode readInfixExpression(InfixExpression expression) {
- JavaOperator operator = readOperator(expression.getOperator());
- return MethodCallNode.methodCall(
- readExpression(expression.getLeftOperand()),
- operator.methodName,
- asList(readExpression(expression.getRightOperand())),
- operator.returnValue);
+ final ExpressionNode left = readExpression(expression.getLeftOperand());
+ final ExpressionNode right = readExpression(expression.getRightOperand());
+ if (expression.getOperator() == Operator.NOT_EQUALS) {
+ return MethodCallNode.not(methodCall(left, "equals", asList(right), BooleanValue.REF));
+ } else {
+ JavaOperator operator = readOperator(expression.getOperator());
+ return MethodCallNode.methodCall(
+ left,
+ operator.methodName,
+ asList(right),
+ operator.returnValue);
+ }
}
private static JavaOperator readOperator(Operator operator) {
diff --git a/src/main/java/org/zwobble/couscous/interpreter/values/BooleanInterpreterValue.java b/src/main/java/org/zwobble/couscous/interpreter/values/BooleanInterpreterValue.java
index 8245f87..820c2b1 100644
--- a/src/main/java/org/zwobble/couscous/interpreter/values/BooleanInterpreterValue.java
+++ b/src/main/java/org/zwobble/couscous/interpreter/values/BooleanInterpreterValue.java
@@ -1,12 +1,18 @@
package org.zwobble.couscous.interpreter.values;
+import java.util.Collections;
import java.util.Optional;
import org.zwobble.couscous.interpreter.NoSuchField;
import org.zwobble.couscous.values.PrimitiveValue;
import org.zwobble.couscous.values.PrimitiveValues;
public final class BooleanInterpreterValue implements InterpreterValue {
- private static final ConcreteType TYPE = ConcreteType.builder(BooleanInterpreterValue.class, "Boolean").build();
+ private static final ConcreteType TYPE = ConcreteType.builder(BooleanInterpreterValue.class, "boolean")
+
+ .method("negate", Collections.emptyList(), (environment, arguments) ->
+ new BooleanInterpreterValue(!arguments.getReceiver().getValue()))
+
+ .build();
private final boolean value;
public boolean getValue() {
diff --git a/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java b/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java
index 89a06af..63ac1a9 100644
--- a/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/BackendEvalTests.java
@@ -22,6 +22,7 @@ import static org.zwobble.couscous.ast.FieldAccessNode.fieldAccess;
import static org.zwobble.couscous.ast.FormalArgumentNode.formalArg;
import static org.zwobble.couscous.ast.LiteralNode.literal;
import static org.zwobble.couscous.ast.MethodCallNode.methodCall;
+import static org.zwobble.couscous.ast.MethodCallNode.not;
import static org.zwobble.couscous.ast.ReturnNode.returns;
import static org.zwobble.couscous.ast.StaticMethodCallNode.staticMethodCall;
import static org.zwobble.couscous.ast.TernaryConditionalNode.ternaryConditional;
@@ -40,6 +41,16 @@ public abstract class BackendEvalTests {
}
@Test
+ public void canEvaluateOperationsOnBooleans() {
+ assertEquals(
+ value(true),
+ evalExpression(not(literal(false))));
+ assertEquals(
+ value(false),
+ evalExpression(not(literal(true))));
+ }
+
+ @Test
public void canEvaluateOperationsOnIntegers() {
assertEquals(
value(3),
diff --git a/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java b/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java
index 2568e55..29a5e2a 100644
--- a/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/JavaToPythonTests.java
@@ -26,6 +26,8 @@ public class JavaToPythonTests {
public void canUseOperatorsOnPrimitives() {
assertEquals(value(3), evalExpression("1 + 2"));
assertEquals(value(false), evalExpression("1 > 2"));
+ assertEquals(value(true), evalExpression("1 == 1"));
+ assertEquals(value(false), evalExpression("1 != 1"));
}
private PrimitiveValue evalExpression(String expressionSource) {
diff --git a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java
index 24b2e9a..f8956e5 100644
--- a/src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/backends/python/PythonSerializerTests.java
@@ -18,6 +18,7 @@ import static org.zwobble.couscous.backends.python.ast.PythonImportAliasNode.pyt
import static org.zwobble.couscous.backends.python.ast.PythonImportNode.pythonImport;
import static org.zwobble.couscous.backends.python.ast.PythonIntegerLiteralNode.pythonIntegerLiteral;
import static org.zwobble.couscous.backends.python.ast.PythonModuleNode.pythonModule;
+import static org.zwobble.couscous.backends.python.ast.PythonNotNode.pythonNot;
import static org.zwobble.couscous.backends.python.ast.PythonPassNode.PASS;
import static org.zwobble.couscous.backends.python.ast.PythonReturnNode.pythonReturn;
import static org.zwobble.couscous.backends.python.ast.PythonStringLiteralNode.pythonStringLiteral;
@@ -69,6 +70,11 @@ public class PythonSerializerTests {
}
@Test
+ public void notOperationIsSerializedUsingParenthesisedSubExpression() {
+ assertEquals("not (x)", serialize(pythonNot(pythonVariableReference("x"))));
+ }
+
+ @Test
public void returnKeywordIsUsedForReturns() {
String output = serialize(pythonReturn(pythonIntegerLiteral(42)));
assertEquals("return 42\n", output);
diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
index 9c75e90..c4e3791 100644
--- a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
@@ -31,6 +31,7 @@ import static org.zwobble.couscous.ast.FieldAccessNode.fieldAccess;
import static org.zwobble.couscous.ast.FieldDeclarationNode.field;
import static org.zwobble.couscous.ast.LiteralNode.literal;
import static org.zwobble.couscous.ast.MethodCallNode.methodCall;
+import static org.zwobble.couscous.ast.MethodCallNode.not;
import static org.zwobble.couscous.ast.StaticMethodCallNode.staticMethodCall;
import static org.zwobble.couscous.ast.TernaryConditionalNode.ternaryConditional;
import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
@@ -165,6 +166,9 @@ public class JavaReaderTests {
methodCall(literal(1), "equals", asList(literal(2)), BooleanValue.REF),
readExpression("1 == 2"));
assertEquals(
+ not(methodCall(literal(1), "equals", asList(literal(2)), BooleanValue.REF)),
+ readExpression("1 != 2"));
+ assertEquals(
methodCall(literal(1), "greaterThan", asList(literal(2)), BooleanValue.REF),
readExpression("1 > 2"));
assertEquals(