/*
* 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.*;
import org.jetbrains.annotations.Nullable;
import org.juniversal.translator.core.Var;
import static org.juniversal.translator.core.ASTUtil.forEach;
public class SwitchStatementWriter extends CSharpASTNodeWriter<SwitchStatement> {
public SwitchStatementWriter(CSharpSourceFileWriter cSharpASTWriters) {
super(cSharpASTWriters);
}
@Override
public void write(SwitchStatement switchStatement) {
// TODO: Handle string switch statements
// TODO: Check for fall through of cases (disallowed in C#)
matchAndWrite("switch");
copySpaceAndComments();
matchAndWrite("(");
writeNode(switchStatement.getExpression());
copySpaceAndComments();
matchAndWrite(")");
copySpaceAndComments();
matchAndWrite("{");
Var<Statement> previousStatement = new Var<>();
Var<Integer> previousStatementIndent = new Var<>();
forEach(switchStatement.statements(), (Statement statement, boolean first) -> {
if (statement instanceof SwitchCase) {
SwitchCase switchCase = (SwitchCase) statement;
if (previousStatement.isSet() && !isSwitchExitStatement(previousStatement.value())) {
copySpaceAndCommentsUntilEOL();
writeln();
indentToColumn(previousStatementIndent.value());
write("goto case ");
writeCaseLabelAtOtherPosition(switchCase.getExpression());
write(";");
}
copySpaceAndComments();
writeSwitchCase(switchCase);
previousStatement.clear();
} else {
copySpaceAndComments();
previousStatement.set(statement);
previousStatementIndent.set(getTargetColumn());
writeNode(statement);
}
});
// In C#, unlike Java, the final case statement / default in the switch must end in an explicit break (assuming
// it doesn't exit the scope in some other way)
if (previousStatement.isSet() && !isSwitchExitStatement(previousStatement.value())) {
copySpaceAndCommentsUntilEOL();
writeln();
indentToColumn(previousStatementIndent.value());
write("break;");
}
copySpaceAndComments();
matchAndWrite("}");
}
private boolean isSwitchExitStatement(Statement previousStatement) {
return previousStatement instanceof BreakStatement ||
previousStatement instanceof ContinueStatement ||
previousStatement instanceof ReturnStatement ||
previousStatement instanceof ThrowStatement;
}
private void writeSwitchCase(SwitchCase switchCase) {
if (switchCase.isDefault()) {
matchAndWrite("default");
copySpaceAndComments();
matchAndWrite(":");
} else {
matchAndWrite("case");
copySpaceAndComments();
writeCaseLabel(switchCase.getExpression());
copySpaceAndComments();
matchAndWrite(":");
}
}
private void writeCaseLabelAtOtherPosition(Expression expression) {
int savedPosition = getPosition();
setPositionToStartOfNode(expression);
writeCaseLabel(expression);
setPosition(savedPosition);
}
/**
* Write the case label if it's an enum constant. Enum constant switch labels in Java don't need to use a qualified
* name, including the enum type. That is FOO is valid for a case label; you don't have to say EnumType.FOO.
* However, that's not the case in C#. So map accordingly, writing the fully qualified name for enum constants.
*
* @param expression case label expression
*/
private void writeCaseLabel(Expression expression) {
if (expression instanceof SimpleName) {
SimpleName simpleName = (SimpleName) expression;
@Nullable ITypeBinding typeBinding = simpleName.resolveTypeBinding();
if (typeBinding != null && typeBinding.isEnum()) {
// TODO: Add using statement if needed (test to verify this case exists)
write(typeBinding.getName() + ".");
writeNode(expression);
return;
}
}
writeNode(expression);
}
}