/*
* Copyright (c) 2012-2015, Microsoft Mobile
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.juniversal.translator.csharp;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.juniversal.translator.core.JUniversalException;
import java.util.HashMap;
import static org.juniversal.translator.core.ASTUtil.forEach;
public class InfixExpressionWriter extends CSharpASTNodeWriter<InfixExpression> {
private HashMap<InfixExpression.Operator, String> equivalentOperators; // Operators that have the same token in both Java & C#
public InfixExpressionWriter(CSharpSourceFileWriter cSharpASTWriters) {
super(cSharpASTWriters);
/*
Java binary operator precedence, from: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
postfix expr++ expr--
unary ++expr --expr +expr -expr ~ !
multiplicative * / %
additive + -
shift << >> >>>
relational < > <= >= instanceof
equality == !=
bitwise AND &
bitwise exclusive OR ^
bitwise inclusive OR |
logical AND &&
logical OR ||
ternary ? :
assignment = += -= *= /= %= &= ^= |= <<= >>= >>>=
C# operator precendence, from C# 5.0 language spec
Primary x.y f(x) a[x] x++ x-- new
typeof default checked unchecked delegate
7.7
Unary + - ! ~ ++x --x (T)x
7.8
Multiplicative * / %
7.8
Additive + -
7.9
Shift << >>
7.10
Relational and type testing < > <= >= is as
7.10
Equality == !=
7.11
Logical AND &
7.11
Logical XOR ^
7.11
Logical OR |
7.12
Conditional AND &&
7.12
Conditional OR ||
7.13
Null coalescing ??
7.14
Conditional ?:
7.17, 7.15
Assignment and lambda expression = *= /= %= += -= <<= >>= &= ^= |=
=>
*/
equivalentOperators = new HashMap<>();
equivalentOperators.put(InfixExpression.Operator.TIMES, "*");
equivalentOperators.put(InfixExpression.Operator.DIVIDE, "/");
equivalentOperators.put(InfixExpression.Operator.REMAINDER, "%");
equivalentOperators.put(InfixExpression.Operator.PLUS, "+");
equivalentOperators.put(InfixExpression.Operator.MINUS, "-");
// TODO: Test signed / unsigned semantics here
equivalentOperators.put(InfixExpression.Operator.LEFT_SHIFT, "<<");
equivalentOperators.put(InfixExpression.Operator.RIGHT_SHIFT_SIGNED, ">>");
//cppOperators.put(InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED, "==");
equivalentOperators.put(InfixExpression.Operator.LESS, "<");
equivalentOperators.put(InfixExpression.Operator.GREATER, ">");
equivalentOperators.put(InfixExpression.Operator.LESS_EQUALS, "<=");
equivalentOperators.put(InfixExpression.Operator.GREATER_EQUALS, ">=");
equivalentOperators.put(InfixExpression.Operator.EQUALS, "==");
equivalentOperators.put(InfixExpression.Operator.NOT_EQUALS, "!=");
equivalentOperators.put(InfixExpression.Operator.XOR, "^");
equivalentOperators.put(InfixExpression.Operator.AND, "&");
equivalentOperators.put(InfixExpression.Operator.OR, "|");
equivalentOperators.put(InfixExpression.Operator.CONDITIONAL_AND, "&&");
equivalentOperators.put(InfixExpression.Operator.CONDITIONAL_OR, "||");
}
@Override
public void write(InfixExpression infixExpression) {
InfixExpression.Operator operator = infixExpression.getOperator();
if (operator == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED) {
writeRightShiftUnsigned(infixExpression);
} else {
writeNode(infixExpression.getLeftOperand());
copySpaceAndComments();
String operatorToken = this.equivalentOperators.get(operator);
matchAndWrite(operatorToken);
copySpaceAndComments();
writeNode(infixExpression.getRightOperand());
if (infixExpression.hasExtendedOperands()) {
forEach(infixExpression.extendedOperands(), (Expression extendedOperand) -> {
copySpaceAndComments();
matchAndWrite(operatorToken);
copySpaceAndComments();
writeNode(extendedOperand);
});
}
}
}
private void writeRightShiftUnsigned(InfixExpression infixExpression) {
ITypeBinding typeBinding = infixExpression.getLeftOperand().resolveTypeBinding();
String typeName = typeBinding.getName();
//TODO: Remove inner parens for left operand if it's a simple (single elmt) expression, not needing them
String cSharpTypeName;
String cSharpUnsignedTypeName;
if (typeBinding.getName().equals("long")) {
cSharpTypeName = "long";
cSharpUnsignedTypeName = "ulong";
} else if (typeBinding.getName().equals("int")) {
cSharpTypeName = "int";
cSharpUnsignedTypeName = "uint";
} else if (typeBinding.getName().equals("short")) {
cSharpTypeName = "short";
cSharpUnsignedTypeName = "ushort";
} else if (typeBinding.getName().equals("byte")) {
cSharpTypeName = "sbyte";
cSharpUnsignedTypeName = "byte";
}
else throw new JUniversalException("Unexpected >>> left operand type: " + typeName);
write("(" + cSharpTypeName + ")((" + cSharpUnsignedTypeName + ")(");
writeNode(infixExpression.getLeftOperand());
write(")");
copySpaceAndComments();
matchAndWrite(">>>", ">>");
copySpaceAndComments();
writeNode(infixExpression.getRightOperand());
write(")");
if (infixExpression.hasExtendedOperands())
throw sourceNotSupported(">>> extended operands (with multiple >>> operators in a row, like 'a >>> b >>> c') not currently supported");
}
}