From 4ea4f22e89e38775fb0436d2c34bf5e0cf1ecfb4 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 14 Jan 2016 20:41:16 +0000 Subject: Remove some unnecessary parens from Python output --- .../couscous/backends/python/PrimitiveMethods.java | 41 +++++++-------- .../couscous/backends/python/PythonSerializer.java | 36 +++++++------ .../python/ast/PythonAttributeAccessNode.java | 5 ++ .../backends/python/ast/PythonBinaryOperation.java | 61 +++++++++++++++++++--- .../python/ast/PythonBooleanLiteralNode.java | 5 ++ .../backends/python/ast/PythonCallNode.java | 8 ++- .../ast/PythonConditionalExpressionNode.java | 5 ++ .../backends/python/ast/PythonExpressionNode.java | 2 +- .../backends/python/ast/PythonGetSliceNode.java | 8 ++- .../python/ast/PythonIntegerLiteralNode.java | 5 ++ .../backends/python/ast/PythonNotNode.java | 5 ++ .../python/ast/PythonStringLiteralNode.java | 5 ++ .../python/ast/PythonVariableReferenceNode.java | 5 ++ 13 files changed, 144 insertions(+), 47 deletions(-) (limited to 'src/main') 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 403e7ac..78624b0 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PrimitiveMethods.java @@ -12,6 +12,7 @@ import org.zwobble.couscous.values.*; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.BiFunction; import static org.zwobble.couscous.backends.python.ast.PythonAttributeAccessNode.pythonAttributeAccess; import static org.zwobble.couscous.backends.python.ast.PythonBinaryOperation.pythonIs; @@ -39,7 +40,7 @@ public class PrimitiveMethods { pythonCall(pythonAttributeAccess(receiver, "lower"), list())) .put("equals", (receiver, arguments) -> - PythonBinaryOperation.pythonEq(receiver, arguments.get(0))) + PythonBinaryOperation.pythonEqual(receiver, arguments.get(0))) .build(); @@ -51,8 +52,8 @@ public class PrimitiveMethods { methods.put("negate", (receiver, arguments) -> PythonNotNode.pythonNot(receiver)); - addOperation(methods, Operator.BOOLEAN_AND, "and"); - addOperation(methods, Operator.BOOLEAN_OR, "or"); + addOperation(methods, Operator.BOOLEAN_AND, PythonBinaryOperation::pythonAnd); + addOperation(methods, Operator.BOOLEAN_OR, PythonBinaryOperation::pythonOr); BOOLEAN_METHODS = methods.build(); } @@ -65,9 +66,9 @@ public class PrimitiveMethods { methods.put("toString", (receiver, arguments) -> pythonCall(pythonVariableReference("str"), list(receiver))); - addOperation(methods, Operator.ADD, "+"); - addOperation(methods, Operator.SUBTRACT, "-"); - addOperation(methods, Operator.MULTIPLY, "*"); + addOperation(methods, Operator.ADD, PythonBinaryOperation::pythonAdd); + addOperation(methods, Operator.SUBTRACT, PythonBinaryOperation::pythonSubtract); + addOperation(methods, Operator.MULTIPLY, PythonBinaryOperation::pythonMultiply); methods.put(Operator.DIVIDE.getMethodName(), (receiver, arguments) -> pythonCall( @@ -78,12 +79,12 @@ public class PrimitiveMethods { internalReference("_mod_round_to_zero"), list(receiver, arguments.get(0)))); - addOperation(methods, Operator.EQUALS, "=="); - addOperation(methods, Operator.NOT_EQUALS, "!="); - addOperation(methods, Operator.GREATER_THAN, ">"); - addOperation(methods, Operator.GREATER_THAN_OR_EQUAL, ">="); - addOperation(methods, Operator.LESS_THAN, "<"); - addOperation(methods, Operator.LESS_THAN_OR_EQUAL, "<="); + addOperation(methods, Operator.EQUALS, PythonBinaryOperation::pythonEqual); + addOperation(methods, Operator.NOT_EQUALS, PythonBinaryOperation::pythonNotEqual); + addOperation(methods, Operator.GREATER_THAN, PythonBinaryOperation::pythonGreaterThan); + addOperation(methods, Operator.GREATER_THAN_OR_EQUAL, PythonBinaryOperation::pythonGreatThanOrEqual); + addOperation(methods, Operator.LESS_THAN, PythonBinaryOperation::pythonLessThan); + addOperation(methods, Operator.LESS_THAN_OR_EQUAL, PythonBinaryOperation::pythonLessThanOrEqual); INT_METHODS = methods.build(); } @@ -95,20 +96,18 @@ public class PrimitiveMethods { private static void addOperation( Builder methods, Operator operator, - String operatorSymbol) + BiFunction build) { - addOperation(methods, operator.getMethodName(), operatorSymbol); + addOperation(methods, operator.getMethodName(), build); } private static void addOperation( - Builder methods, - String methodName, - String operatorSymbol) { + Builder methods, + String methodName, + BiFunction build) + { methods.put(methodName, (receiver, arguments) -> - new PythonBinaryOperation( - operatorSymbol, - receiver, - arguments.get(0))); + build.apply(receiver, arguments.get(0))); } private static final Map> METHODS = 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 6501d1b..45739da 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java +++ b/src/main/java/org/zwobble/couscous/backends/python/PythonSerializer.java @@ -1,11 +1,12 @@ package org.zwobble.couscous.backends.python; -import java.util.List; -import java.util.function.Consumer; - import org.zwobble.couscous.backends.python.ast.*; import org.zwobble.couscous.backends.python.ast.visitors.PythonNodeVisitor; import org.zwobble.couscous.util.Action; + +import java.util.List; +import java.util.function.Consumer; + import static com.google.common.collect.Iterables.skip; public class PythonSerializer implements PythonNodeVisitor { @@ -48,27 +49,27 @@ public class PythonSerializer implements PythonNodeVisitor { @Override public void visit(PythonConditionalExpressionNode conditional) { - writeParenthesised(conditional.getTrueValue()); + writeParenthesised(conditional.getTrueValue(), conditional); writer.writeSpace(); writer.writeKeyword("if"); writer.writeSpace(); - writeParenthesised(conditional.getCondition()); + writeParenthesised(conditional.getCondition(), conditional); writer.writeSpace(); writer.writeKeyword("else"); writer.writeSpace(); - writeParenthesised(conditional.getFalseValue()); + writeParenthesised(conditional.getFalseValue(), conditional); } @Override public void visit(PythonAttributeAccessNode attributeAccess) { - writeParenthesised(attributeAccess.getLeft()); + writeParenthesised(attributeAccess.getLeft(), attributeAccess); writer.writeSymbol("."); writer.writeIdentifier(attributeAccess.getAttributeName()); } @Override public void visit(PythonCallNode call) { - writeParenthesised(call.getCallee()); + writeParenthesised(call.getCallee(), call); writer.writeSymbol("("); writeWithSeparator(call.getArguments(), this::write, () -> { writer.writeSymbol(","); @@ -79,7 +80,7 @@ public class PythonSerializer implements PythonNodeVisitor { @Override public void visit(PythonGetSliceNode getSlice) { - writeParenthesised(getSlice.getReceiver()); + writeParenthesised(getSlice.getReceiver(), getSlice); writer.writeSymbol("["); writeWithSeparator(getSlice.getArguments(), this::write, () -> { writer.writeSymbol(":"); @@ -91,16 +92,16 @@ public class PythonSerializer implements PythonNodeVisitor { public void visit(PythonNotNode notOperation) { writer.writeKeyword("not"); writer.writeSpace(); - writeParenthesised(notOperation.getOperand()); + writeParenthesised(notOperation.getOperand(), notOperation); } @Override public void visit(PythonBinaryOperation operation) { - writeParenthesised(operation.getLeft()); + writeParenthesised(operation.getLeft(), operation); writer.writeSpace(); writer.writeKeyword(operation.getOperator()); writer.writeSpace(); - writeParenthesised(operation.getRight()); + writeParenthesised(operation.getRight(), operation); } @Override @@ -198,10 +199,15 @@ public class PythonSerializer implements PythonNodeVisitor { }); } - private void writeParenthesised(PythonExpressionNode expression) { - writer.writeSymbol("("); + private void writeParenthesised(PythonExpressionNode expression, PythonExpressionNode parent) { + boolean requiresParens = parent.precedence() >= expression.precedence(); + if (requiresParens) { + writer.writeSymbol("("); + } write(expression); - writer.writeSymbol(")"); + if (requiresParens) { + writer.writeSymbol(")"); + } } private void writeArgumentNames(PythonFunctionDefinitionNode functionDefinition) { diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonAttributeAccessNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonAttributeAccessNode.java index 95e6cf0..e2b8d8b 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonAttributeAccessNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonAttributeAccessNode.java @@ -32,4 +32,9 @@ public final class PythonAttributeAccessNode implements PythonExpressionNode { public java.lang.String toString() { return "PythonAttributeAccessNode(left=" + this.getLeft() + ", attributeName=" + this.getAttributeName() + ")"; } + + @Override + public int precedence() { + return 160; + } } \ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBinaryOperation.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBinaryOperation.java index 8d6b9ce..ecaf038 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBinaryOperation.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBinaryOperation.java @@ -4,26 +4,66 @@ import org.zwobble.couscous.backends.python.ast.visitors.PythonNodeVisitor; public class PythonBinaryOperation implements PythonExpressionNode { public static PythonExpressionNode pythonIs(PythonExpressionNode left, PythonExpressionNode right) { - return new PythonBinaryOperation("is", left, right); + return new PythonBinaryOperation("is", 50, left, right); + } + + public static PythonExpressionNode pythonAnd(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("and", 20, left, right); + } + + public static PythonExpressionNode pythonOr(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("or", 20, left, right); } public static PythonExpressionNode pythonAdd(PythonExpressionNode left, PythonExpressionNode right) { - return new PythonBinaryOperation("+", left, right); + return new PythonBinaryOperation("+", 100, left, right); + } + + public static PythonExpressionNode pythonSubtract(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("-", 100, left, right); } - public static PythonExpressionNode pythonEq(PythonExpressionNode left, PythonExpressionNode right) { - return new PythonBinaryOperation("==", left, right); + public static PythonExpressionNode pythonMultiply(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("*", 110, left, right); + } + + public static PythonExpressionNode pythonEqual(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("==", 50, left, right); + } + + public static PythonExpressionNode pythonNotEqual(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("!=", 50, left, right); + } + + public static PythonExpressionNode pythonLessThan(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("<", 50, left, right); + } + + public static PythonExpressionNode pythonLessThanOrEqual(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation("<=", 50, left, right); + } + + public static PythonExpressionNode pythonGreaterThan(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation(">", 50, left, right); + } + + public static PythonExpressionNode pythonGreatThanOrEqual(PythonExpressionNode left, PythonExpressionNode right) { + return new PythonBinaryOperation(">=", 50, left, right); } private final String operator; + private final int precedence; private final PythonExpressionNode left; private final PythonExpressionNode right; - public PythonBinaryOperation( - String operator, - PythonExpressionNode left, - PythonExpressionNode right) { + private PythonBinaryOperation( + String operator, + int precedence, + PythonExpressionNode left, + PythonExpressionNode right) + { this.operator = operator; + this.precedence = precedence; this.left = left; this.right = right; } @@ -44,4 +84,9 @@ public class PythonBinaryOperation implements PythonExpressionNode { public void accept(PythonNodeVisitor visitor) { visitor.visit(this); } + + @Override + public int precedence() { + return precedence; + } } diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBooleanLiteralNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBooleanLiteralNode.java index 893f2e1..fd902ee 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBooleanLiteralNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonBooleanLiteralNode.java @@ -26,4 +26,9 @@ public final class PythonBooleanLiteralNode implements PythonExpressionNode { public java.lang.String toString() { return "PythonBooleanLiteralNode(value=" + this.getValue() + ")"; } + + @Override + public int precedence() { + return Integer.MAX_VALUE; + } } \ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonCallNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonCallNode.java index ae3761b..3adb4fb 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonCallNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonCallNode.java @@ -1,8 +1,9 @@ package org.zwobble.couscous.backends.python.ast; -import java.util.List; import org.zwobble.couscous.backends.python.ast.visitors.PythonNodeVisitor; +import java.util.List; + public final class PythonCallNode implements PythonExpressionNode { private final PythonExpressionNode callee; private final List arguments; @@ -33,4 +34,9 @@ public final class PythonCallNode implements PythonExpressionNode { public java.lang.String toString() { return "PythonCallNode(callee=" + this.getCallee() + ", arguments=" + this.getArguments() + ")"; } + + @Override + public int precedence() { + return 150; + } } \ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonConditionalExpressionNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonConditionalExpressionNode.java index a320cd2..75f9e15 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonConditionalExpressionNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonConditionalExpressionNode.java @@ -38,4 +38,9 @@ public final class PythonConditionalExpressionNode implements PythonExpressionNo public java.lang.String toString() { return "PythonConditionalExpressionNode(condition=" + this.getCondition() + ", trueValue=" + this.getTrueValue() + ", falseValue=" + this.getFalseValue() + ")"; } + + @Override + public int precedence() { + return 10; + } } \ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonExpressionNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonExpressionNode.java index 9c8a259..8105271 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonExpressionNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonExpressionNode.java @@ -1,5 +1,5 @@ package org.zwobble.couscous.backends.python.ast; public interface PythonExpressionNode extends PythonNode { - + int precedence(); } diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonGetSliceNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonGetSliceNode.java index 70343d8..1a245cd 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonGetSliceNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonGetSliceNode.java @@ -1,8 +1,9 @@ package org.zwobble.couscous.backends.python.ast; -import java.util.List; import org.zwobble.couscous.backends.python.ast.visitors.PythonNodeVisitor; +import java.util.List; + public final class PythonGetSliceNode implements PythonExpressionNode { private final PythonExpressionNode receiver; private final List arguments; @@ -33,4 +34,9 @@ public final class PythonGetSliceNode implements PythonExpressionNode { public java.lang.String toString() { return "PythonGetSliceNode(receiver=" + this.getReceiver() + ", arguments=" + this.getArguments() + ")"; } + + @Override + public int precedence() { + return 150; + } } \ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonIntegerLiteralNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonIntegerLiteralNode.java index ce09767..18156ad 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonIntegerLiteralNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonIntegerLiteralNode.java @@ -26,4 +26,9 @@ public final class PythonIntegerLiteralNode implements PythonExpressionNode { public java.lang.String toString() { return "PythonIntegerLiteralNode(value=" + this.getValue() + ")"; } + + @Override + public int precedence() { + return Integer.MAX_VALUE; + } } \ No newline at end of file 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 index 6fe7dc6..e24d0d8 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonNotNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonNotNode.java @@ -21,4 +21,9 @@ public class PythonNotNode implements PythonExpressionNode { public void accept(PythonNodeVisitor visitor) { visitor.visit(this); } + + @Override + public int precedence() { + return 40; + } } diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonStringLiteralNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonStringLiteralNode.java index d64be5f..f3ee201 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonStringLiteralNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonStringLiteralNode.java @@ -26,4 +26,9 @@ public final class PythonStringLiteralNode implements PythonExpressionNode { public java.lang.String toString() { return "PythonStringLiteralNode(value=" + this.getValue() + ")"; } + + @Override + public int precedence() { + return Integer.MAX_VALUE; + } } \ No newline at end of file diff --git a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonVariableReferenceNode.java b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonVariableReferenceNode.java index 876ac14..f8c2b4a 100644 --- a/src/main/java/org/zwobble/couscous/backends/python/ast/PythonVariableReferenceNode.java +++ b/src/main/java/org/zwobble/couscous/backends/python/ast/PythonVariableReferenceNode.java @@ -26,4 +26,9 @@ public final class PythonVariableReferenceNode implements PythonExpressionNode { public java.lang.String toString() { return "PythonVariableReferenceNode(name=" + this.getName() + ")"; } + + @Override + public int precedence() { + return Integer.MAX_VALUE; + } } \ No newline at end of file -- cgit v1.2.3