diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-04-28 21:33:45 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-04-28 21:33:45 +0100 |
| commit | 7a7512ba6e9e428e82efee057fa1aa3056bf231d (patch) | |
| tree | 4d33a0a3aeb3b9cdcb38cdd5e76aa8b8318de4c2 /src/main/java/org/zwobble/couscous/backends | |
| parent | 5f852c33a8a57bd8fad58747b339961ac6c835ef (diff) | |
Parenthesize expressions in C# serializer
Diffstat (limited to 'src/main/java/org/zwobble/couscous/backends')
| -rw-r--r-- | src/main/java/org/zwobble/couscous/backends/csharp/CsharpSerializer.java | 210 |
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; + } + }); + } } |
