/******************************************************************************* * Copyright (c) 2008, 2010 Institute for Software, HSR Hochschule fuer Technik * Rapperswil, University of applied sciences and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Institute for Software - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.rewrite.astwriter; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTBreakStatement; import org.eclipse.cdt.core.dom.ast.IASTCaseStatement; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTContinueStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarationStatement; import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement; import org.eclipse.cdt.core.dom.ast.IASTDoStatement; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTGotoStatement; import org.eclipse.cdt.core.dom.ast.IASTIfStatement; import org.eclipse.cdt.core.dom.ast.IASTLabelStatement; import org.eclipse.cdt.core.dom.ast.IASTNullStatement; import org.eclipse.cdt.core.dom.ast.IASTProblemStatement; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousStatement; import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap; /** * Generates source code of statement nodes. The actual string operations are delegated * to the Scribe class. * * @see Scribe * @see IASTStatement * @author Emanuel Graf IFS */ public class StatementWriter extends NodeWriter { private static final String DEFAULT = "default:"; //$NON-NLS-1$ private static final String CASE = "case "; //$NON-NLS-1$ private static final String WHILE = "while ("; //$NON-NLS-1$ private static final String TRY = "try "; //$NON-NLS-1$ private static final String CATCH = "catch ("; //$NON-NLS-1$ private static final String RETURN = "return"; //$NON-NLS-1$ private static final String GOTO = "goto "; //$NON-NLS-1$ private static final String CONTINUE = "continue"; //$NON-NLS-1$ private static final String BREAK = "break"; //$NON-NLS-1$ private static final String ELSE = "else"; //$NON-NLS-1$ private static final String IF = "if ("; //$NON-NLS-1$ private static final String FOR = "for ("; //$NON-NLS-1$ private static final String DO_WHILE = " while ("; //$NON-NLS-1$ private static final String DO = "do"; //$NON-NLS-1$ private static final String SWITCH_BRACKET = "switch ("; //$NON-NLS-1$ private boolean compoundNoNewLine = false; private boolean switchIsNew; private boolean decrementIndentationLevelOneMore = false; private final DeclarationWriter declWriter; public StatementWriter(Scribe scribe, ASTWriterVisitor visitor, NodeCommentMap commentMap) { super(scribe, visitor, commentMap); declWriter = new DeclarationWriter(scribe, visitor, commentMap); } /** * Prints a statement. * * @param statement the statement * @param newLine if true print a newline if statement usually have one. * @return {@link ASTVisitor#PROCESS_SKIP} */ protected int writeStatement(IASTStatement statement, boolean newLine) { if (statement instanceof IASTAmbiguousStatement) { //TODO HSR Leo test statement.accept(visitor); newLine = false; } else if (statement instanceof IASTExpressionStatement) { writeExpressionStatement((IASTExpressionStatement) statement); //usually newLine } else if (statement instanceof IASTDeclarationStatement) { writeDeclarationStatement((IASTDeclarationStatement) statement); newLine = false; } else if (statement instanceof IASTNullStatement) { writeNullStatement((IASTNullStatement)statement); // usually newLine } else if (statement instanceof IASTReturnStatement) { writeReturnStatement((IASTReturnStatement)statement); // usually newLine } else if (statement instanceof IASTGotoStatement) { writeGotoStatement((IASTGotoStatement) statement); // usually newLine } else if (statement instanceof IASTLabelStatement) { writeLabelStatement((IASTLabelStatement) statement); newLine = false; } else if (statement instanceof IASTCaseStatement) { writeCaseStatement((IASTCaseStatement) statement); // usually newLine } else if (statement instanceof IASTDefaultStatement) { writeDefaultStatement((IASTDefaultStatement)statement); } else if (statement instanceof IASTContinueStatement) { writeContinueStatement((IASTContinueStatement)statement); // usually newLine } else if (statement instanceof IASTCompoundStatement) { if (compoundNoNewLine) { newLine = false; compoundNoNewLine = false; } writeCompoundStatement((IASTCompoundStatement) statement); } else if (statement instanceof IASTBreakStatement) { writeBreakStatement((IASTBreakStatement) statement); // usually newLine } else if (statement instanceof IASTSwitchStatement) { writeSwitchStatement((IASTSwitchStatement) statement); newLine = false; } else if (statement instanceof IASTIfStatement) { writeIfStatement((IASTIfStatement) statement); newLine = false; } else if (statement instanceof IASTWhileStatement) { writeWhileStatement((IASTWhileStatement) statement); newLine = false; } else if (statement instanceof IASTForStatement) { writeForStatement((IASTForStatement) statement); newLine = false; } else if (statement instanceof ICPPASTRangeBasedForStatement) { writeForStatement((ICPPASTRangeBasedForStatement) statement); newLine = false; } else if (statement instanceof IASTDoStatement) { writeDoStatement((IASTDoStatement) statement); newLine = true; } else if (statement instanceof ICPPASTTryBlockStatement) { writeTryBlockStatement((ICPPASTTryBlockStatement) statement); newLine = false; } else if (statement instanceof ICPPASTCatchHandler) { writeCatchHandler((ICPPASTCatchHandler) statement); newLine = false; } else if (statement instanceof IASTProblemStatement) { throw new ProblemRuntimeException((IASTProblemStatement)statement); } writeTrailingComments(statement, newLine); return ASTVisitor.PROCESS_SKIP; } private void writeDoStatement(IASTDoStatement doStatement) { nextCompoundNoNewLine(); scribe.print(DO); writeBodyStatement(doStatement.getBody(), true); scribe.print(DO_WHILE); doStatement.getCondition().accept(visitor); scribe.print(')'); scribe.printSemicolon(); } private void writeForStatement(IASTForStatement forStatement) { scribe.noNewLines(); scribe.print(FOR); writeStatement(forStatement.getInitializerStatement(),false); if (forStatement instanceof ICPPASTForStatement) { ICPPASTForStatement cppForStatment = (ICPPASTForStatement) forStatement; IASTDeclaration cppConditionDeclaration = cppForStatment.getConditionDeclaration(); if (cppConditionDeclaration == null) { visitNodeIfNotNull(cppForStatment.getConditionExpression()); scribe.printSemicolon(); } else { cppConditionDeclaration.accept(visitor); } } else { if (forStatement.getConditionExpression() != null) { forStatement.getConditionExpression().accept(visitor); scribe.printSemicolon(); } } visitNodeIfNotNull(forStatement.getIterationExpression()); scribe.print(')'); scribe.newLines(); nextCompoundNoNewLine(); writeBodyStatement(forStatement.getBody(), false); } private void writeForStatement(ICPPASTRangeBasedForStatement forStatment) { scribe.noNewLines(); scribe.print(FOR); writeDeclarationWithoutSemicolon(forStatment.getDeclaration()); scribe.print(COLON_SPACE); visitNodeIfNotNull(forStatment.getInitializerClause()); scribe.print(')'); scribe.newLines(); nextCompoundNoNewLine(); writeBodyStatement(forStatment.getBody(), false); } private void writeIfStatement(IASTIfStatement ifStatement) { scribe.print(IF); scribe.noNewLines(); if (ifStatement instanceof ICPPASTIfStatement) { ICPPASTIfStatement cppIfStatment = (ICPPASTIfStatement) ifStatement; if (cppIfStatment.getConditionDeclaration() == null) { cppIfStatment.getConditionExpression().accept(visitor); } else { writeDeclarationWithoutSemicolon(cppIfStatment.getConditionDeclaration()); } } else { ifStatement.getConditionExpression().accept(visitor); } scribe.print(')'); scribe.newLines(); nextCompoundNoNewLine(); IASTStatement elseClause = ifStatement.getElseClause(); writeBodyStatement(ifStatement.getThenClause(), elseClause != null); if (elseClause != null) { scribe.print(ELSE); nextCompoundNoNewLine(); writeBodyStatement(elseClause, false); } } protected void writeDeclarationWithoutSemicolon(IASTDeclaration declaration) { declWriter.writeDeclaration(declaration, false); } private void writeBreakStatement(IASTBreakStatement statement) { scribe.print(BREAK); scribe.printSemicolon(); } private void writeContinueStatement(IASTContinueStatement statement) { scribe.print(CONTINUE); scribe.printSemicolon(); } private void writeLabelStatement(IASTLabelStatement labelStatement) { labelStatement.getName().accept(visitor); scribe.print(':'); scribe.newLine(); labelStatement.getNestedStatement().accept(visitor); } private void writeGotoStatement(IASTGotoStatement gotoStatement) { scribe.print(GOTO); gotoStatement.getName().accept(visitor); scribe.printSemicolon(); } private void writeReturnStatement(IASTReturnStatement returnStatement) { scribe.noNewLines(); scribe.print(RETURN); IASTExpression returnValue = returnStatement.getReturnValue(); if (returnValue != null) { scribe.printSpaces(1); returnValue.accept(visitor); } scribe.newLines(); scribe.printSemicolon(); } private void writeNullStatement(IASTNullStatement nullStmt) { scribe.printSemicolon(); } private void writeDeclarationStatement(IASTDeclarationStatement decStmt) { decStmt.getDeclaration().accept(visitor); } private void writeExpressionStatement(IASTExpressionStatement expStmt) { expStmt.getExpression().accept(visitor); scribe.printSemicolon(); } private void writeCatchHandler(ICPPASTCatchHandler catchStatement) { scribe.print(CATCH); if (catchStatement.isCatchAll()) { scribe.print(VAR_ARGS); } else { scribe.noSemicolon(); scribe.noNewLines(); catchStatement.getDeclaration().accept(visitor); scribe.newLines(); } scribe.print(')'); writeBodyStatement(catchStatement.getCatchBody(), true); } private void writeTryBlockStatement(ICPPASTTryBlockStatement tryStatement) { scribe.print(TRY); tryStatement.getTryBody().accept(visitor); for (ICPPASTCatchHandler catchStatement : tryStatement.getCatchHandlers()) { writeStatement(catchStatement, false); } } private void writeWhileStatement(IASTWhileStatement whileStatment) { scribe.print(WHILE); scribe.noNewLines(); if (whileStatment instanceof ICPPASTWhileStatement) { ICPPASTWhileStatement cppWhileStatment = (ICPPASTWhileStatement) whileStatment; if (cppWhileStatment.getConditionDeclaration() == null) { cppWhileStatment.getCondition().accept(visitor); } else { writeDeclarationWithoutSemicolon(cppWhileStatment.getConditionDeclaration()); } } else { whileStatment.getCondition().accept(visitor); } scribe.print(')'); scribe.newLines(); nextCompoundNoNewLine(); writeBodyStatement(whileStatment.getBody(), false); } private void writeCaseStatement(IASTCaseStatement caseStatement) { nextCompoundIndentationLevelOneMore(); if (!switchIsNew) { scribe.decrementIndentationLevel(); } scribe.print(CASE); caseStatement.getExpression().accept(visitor); scribe.print(':'); scribe.incrementIndentationLevel(); switchIsNew = false; } private void writeSwitchStatement(IASTSwitchStatement switchStatement) { switchIsNew = true; scribe.print(SWITCH_BRACKET); scribe.noNewLines(); if (switchStatement instanceof ICPPASTSwitchStatement) { ICPPASTSwitchStatement cppSwitchStatement = (ICPPASTSwitchStatement) switchStatement; if (cppSwitchStatement.getControllerDeclaration() == null) { cppSwitchStatement.getControllerExpression().accept(visitor); } else { declWriter.writeDeclaration(cppSwitchStatement.getControllerDeclaration(), false); } } else { switchStatement.getControllerExpression().accept(visitor); } scribe.print(')'); scribe.newLines(); nextCompoundNoNewLine(); writeBodyStatement(switchStatement.getBody(), false); switchIsNew = false; } private void writeDefaultStatement(IASTDefaultStatement defaultStatement) { nextCompoundIndentationLevelOneMore(); if (!switchIsNew) { scribe.decrementIndentationLevel(); } scribe.print(DEFAULT); scribe.incrementIndentationLevel(); switchIsNew = false; } private void writeCompoundStatement(IASTCompoundStatement compoundStatement) { scribe.printLBrace(); scribe.newLine(); for (IASTStatement statements : getNestedStatements(compoundStatement)) { statements.accept(visitor); } if (hasFreestandingComments(compoundStatement)) { writeFreestandingComments(compoundStatement); } if (decrementIndentationLevelOneMore) { scribe.decrementIndentationLevel(); decrementIndentationLevelOneMore = false; } scribe.printRBrace(); } protected IASTStatement[] getNestedStatements(IASTCompoundStatement compoundStatement) { return compoundStatement.getStatements(); } // TODO(sprigogin): Invert and rename second parameter protected void writeBodyStatement(IASTStatement statement, boolean isDoStatement) { if (statement instanceof IASTCompoundStatement) { //TODO hsr existiert noch eine methode statement.accept(visitor); if (!isDoStatement) { scribe.newLine(); } compoundNoNewLine = false; } else if (statement instanceof IASTNullStatement) { statement.accept(visitor); scribe.newLine(); } else { scribe.incrementIndentationLevel(); scribe.newLine(); statement.accept(visitor); scribe.decrementIndentationLevel(); } } /** * Write no new line after the next compound statement */ protected void nextCompoundNoNewLine() { compoundNoNewLine = true; } /** * Indent one time more at the end (before the closing brackets) * of a compound statement */ protected void nextCompoundIndentationLevelOneMore() { decrementIndentationLevelOneMore = true; } protected int writeMixedStatement(IASTStatement statement) { String code = statement.getRawSignature(); scribe.println(code); return ASTVisitor.PROCESS_SKIP; } }