aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-04-28 21:33:45 +0100
committerMichael Williamson <mike@zwobble.org>2016-04-28 21:33:45 +0100
commit7a7512ba6e9e428e82efee057fa1aa3056bf231d (patch)
tree4d33a0a3aeb3b9cdcb38cdd5e76aa8b8318de4c2 /src/main/java
parent5f852c33a8a57bd8fad58747b339961ac6c835ef (diff)
Parenthesize expressions in C# serializer
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java210
1 files changed, 200 insertions, 10 deletions
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 f635519..15751e9 100644
--- a/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
+++ b/src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java
@@ -2,6 +2,7 @@ package org.zwobble.couscous.backends.csharp;
import com.google.common.collect.ImmutableSet;
import org.zwobble.couscous.ast.*;
+import org.zwobble.couscous.ast.visitors.NodeMapper;
import org.zwobble.couscous.ast.visitors.NodeVisitor;
import org.zwobble.couscous.backends.SourceCodeWriter;
import org.zwobble.couscous.types.*;
@@ -200,25 +201,25 @@ public class CsharpSerializer implements NodeVisitor {
writer.writeSpace();
writer.writeSymbol("=");
writer.writeSpace();
- write(assignment.getValue());
+ writeParenthesized(assignment.getValue(), assignment);
}
@Override
public void visit(TernaryConditionalNode ternaryConditional) {
- write(ternaryConditional.getCondition());
+ writeParenthesized(ternaryConditional.getCondition(), ternaryConditional);
writer.writeSpace();
writer.writeSymbol("?");
writer.writeSpace();
- write(ternaryConditional.getIfTrue());
+ writeParenthesized(ternaryConditional.getIfTrue(), ternaryConditional);
writer.writeSpace();
writer.writeSymbol(":");
writer.writeSpace();
- write(ternaryConditional.getIfFalse());
+ writeParenthesized(ternaryConditional.getIfFalse(), ternaryConditional);
}
@Override
public void visit(MethodCallNode methodCall) {
- write(methodCall.getReceiver());
+ writeParenthesized(methodCall.getReceiver(), methodCall);
writer.writeSymbol(".");
writer.writeIdentifier(methodCall.getMethodName());
writeTypeParameters(methodCall.getTypeParameters());
@@ -246,14 +247,14 @@ public class CsharpSerializer implements NodeVisitor {
switch (operation.getOperatorType()) {
case PREFIX:
writer.writeSymbol(operation.getOperator().getSymbol());
- write(operation.getArguments().get(0));
+ writeParenthesized(operation.getArguments().get(0), operation);
return;
case INFIX:
- write(operation.getArguments().get(0));
+ writeParenthesized(operation.getArguments().get(0), operation);
writer.writeSpace();
writer.writeSymbol(operation.getOperator().getSymbol());
writer.writeSpace();
- write(operation.getArguments().get(1));
+ writeParenthesized(operation.getArguments().get(1), operation);
return;
default:
throw new RuntimeException("Unhandled operator type: " + operation.getOperatorType());
@@ -268,7 +269,7 @@ public class CsharpSerializer implements NodeVisitor {
@Override
public void visit(FieldAccessNode fieldAccess) {
- write(fieldAccess.getLeft());
+ writeParenthesized(fieldAccess.getLeft(), fieldAccess);
writer.writeSymbol(".");
writer.writeIdentifier(fieldAccess.getFieldName());
}
@@ -284,7 +285,7 @@ public class CsharpSerializer implements NodeVisitor {
writeTypeReference(cast.getType());
writer.writeSymbol(")");
writer.writeSpace();
- write(cast.getExpression());
+ writeParenthesized(cast.getExpression(), cast);
}
@Override
@@ -676,4 +677,193 @@ public class CsharpSerializer implements NodeVisitor {
writer.writeSymbol(".");
});
}
+
+ private void writeParenthesized(Node node, Node parent) {
+ boolean requiresParens = precedence(parent) >= precedence(node);
+ if (requiresParens) {
+ writer.writeSymbol("(");
+ }
+ write(node);
+ if (requiresParens) {
+ writer.writeSymbol(")");
+ }
+ }
+
+ private int precedence(Node node) {
+ return node.accept(new NodeMapper<Integer>() {
+ @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;
+ }
+
+ @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(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;
+ }
+
+ @Override
+ public Integer visit(ReturnNode returnNode) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(ThrowNode throwNode) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(ExpressionStatementNode expressionStatement) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(LocalVariableDeclarationNode localVariableDeclaration) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(IfStatementNode ifStatement) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(WhileNode whileLoop) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(TryNode tryStatement) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(FormalTypeParameterNode parameter) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(FormalArgumentNode formalArgumentNode) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(AnnotationNode annotation) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(MethodNode methodNode) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(ConstructorNode constructorNode) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(FieldDeclarationNode declaration) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(ClassNode classNode) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(InterfaceNode interfaceNode) {
+ return 0;
+ }
+
+ @Override
+ public Integer visit(EnumNode enumNode) {
+ return 0;
+ }
+ });
+ }
}