import java.io.IOException;
import java.io.StringReader;
import java.util.Hashtable;
-import java.util.Locale;
+//import java.util.Locale;
import java.util.Map;
+//import javax.swing.text.html.Option;
+
import net.sourceforge.phpdt.core.ICodeFormatter;
import net.sourceforge.phpdt.core.compiler.CharOperation;
import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
* <h2>How to format a piece of code ?</h2>
* <ul>
* <li>Create an instance of <code>CodeFormatter</code>
- * <li>Use the method <code>void format(aString)</code> on this instance to format <code>aString</code>. It will return the
- * formatted string.
+ * <li>Use the method <code>void format(aString)</code> on this instance to
+ * format <code>aString</code>. It will return the formatted string.
* </ul>
*/
public class CodeFormatter implements ITerminalSymbols, ICodeFormatter {
- // IContentFormatterExtension {
- public FormatterOptions options;
+ // IContentFormatterExtension {
+ public FormatterOptions options;
- /**
- * Represents a block in the <code>constructions</code> stack.
- */
- public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE;
-
- /**
- * Represents a block following a control statement in the <code>constructions</code> stack.
- */
- public static final int NONINDENT_BLOCK = -100;
-
- /**
- * Contains the formatted output.
- */
- StringBuffer formattedSource;
-
- /**
- * Contains the current line. <br>
- * Will be dumped at the next "newline"
- */
- StringBuffer currentLineBuffer;
-
- /**
- * Used during the formatting to get each token.
- */
- Scanner scanner;
-
- /**
- * Contains the tokens responsible for the current indentation level and the blocks not closed yet.
- */
- private int[] constructions;
-
- /**
- * Index in the <code>constructions</code> array.
- */
- private int constructionsCount;
-
- /**
- * Level of indentation of the current token (number of tab char put in front of it).
- */
- private int indentationLevel;
-
- /**
- * Regular level of indentation of all the lines
- */
- private int initialIndentationLevel;
-
- /**
- * Used to split a line.
- */
- Scanner splitScanner;
-
- /**
- * To remember the offset between the beginning of the line and the beginning of the comment.
- */
- int currentCommentOffset;
-
- int currentLineIndentationLevel;
-
- int maxLineSize = 30;
-
- private boolean containsOpenCloseBraces;
-
- private int indentationLevelForOpenCloseBraces;
-
- /**
- * Collections of positions to map
- */
- private int[] positionsToMap;
-
- /**
- * Collections of mapped positions
- */
- private int[] mappedPositions;
-
- private int indexToMap;
-
- private int indexInMap;
-
- private int globalDelta;
-
- private int lineDelta;
-
- private int splitDelta;
-
- private int beginningOfLineIndex;
-
- private int multipleLineCommentCounter;
-
- /**
- * Creates a new instance of Code Formatter using the given settings.
- *
- * @deprecated backport 1.0 internal functionality
- */
- public CodeFormatter(ConfigurableOption[] settings) {
- this(convertConfigurableOptions(settings));
- }
-
- /**
- * Creates a new instance of Code Formatter using the FormattingOptions object given as argument
- *
- * @deprecated Use CodeFormatter(ConfigurableOption[]) instead
- */
- public CodeFormatter() {
- this((Map) null);
- }
-
- /**
- * Creates a new instance of Code Formatter using the given settings.
- */
- public CodeFormatter(Map settings) {
- // initialize internal state
- constructionsCount = 0;
- constructions = new int[10];
- currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
- currentCommentOffset = -1;
- // initialize primary and secondary scanners
- scanner = new Scanner(true /* comment */
- , true /* whitespace */
- , false /* nls */
- , false /* assert */
- , true, /* tokenizeStrings */
- null, null, true /*taskCaseSensitive*/); // regular scanner for forming lines
- scanner.recordLineSeparator = true;
- scanner.ignorePHPOneLiner = true;
- // to remind of the position of the beginning of the line.
- splitScanner = new Scanner(true /* comment */
- , true /* whitespace */
- , false /* nls */
- , false /* assert */
- , true, /* tokenizeStrings */
- null, null, true /*taskCaseSensitive*/);
- splitScanner.ignorePHPOneLiner = true;
- // secondary scanner to split long lines formed by primary scanning
- // initialize current line buffer
- currentLineBuffer = new StringBuffer();
- this.options = new FormatterOptions(settings);
- }
-
- /**
- * Returns true if a lineSeparator has to be inserted before <code>operator</code> false otherwise.
- */
- private static boolean breakLineBeforeOperator(int operator) {
- switch (operator) {
- case TokenNameCOMMA:
- case TokenNameSEMICOLON:
- case TokenNameEQUAL:
- return false;
- default:
- return true;
- }
- }
-
- /**
- * @deprecated backport 1.0 internal functionality
- */
- private static Map convertConfigurableOptions(ConfigurableOption[] settings) {
- Hashtable options = new Hashtable(10);
- for (int i = 0; i < settings.length; i++) {
- if (settings[i].getComponentName().equals(CodeFormatter.class.getName())) {
- String optionName = settings[i].getOptionName();
- int valueIndex = settings[i].getCurrentValueIndex();
- if (optionName.equals("newline.openingBrace")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- } else if (optionName.equals("newline.controlStatement")) { //$NON-NLS-1$
- options
- .put("net.sourceforge.phpdt.core.formatter.newline.controlStatement", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- } else if (optionName.equals("newline.clearAll")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.newline.clearAll", valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- } else if (optionName.equals("newline.elseIf")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.newline.elseIf", valueIndex == 0 ? "do not insert" : "insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- } else if (optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.newline.emptyBlock", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- } else if (optionName.equals("lineSplit")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
- } else if (optionName.equals("style.assignment")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.style.assignment", valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- } else if (optionName.equals("tabulation.char")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.tabulation.char", valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- } else if (optionName.equals("tabulation.size")) { //$NON-NLS-1$
- options.put("net.sourceforge.phpdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
- }
- }
- }
- return options;
- }
-
- /**
- * Returns the end of the source code.
- */
- private final String copyRemainingSource() {
- char str[] = scanner.source;
- int startPosition = scanner.startPosition;
- int length = str.length - startPosition;
- StringBuffer bufr = new StringBuffer(length);
- if (startPosition < str.length) {
- bufr.append(str, startPosition, length);
- }
- return (bufr.toString());
- }
-
- /**
- * Inserts <code>tabCount</code> tab character or their equivalent number of spaces.
- */
- private void dumpTab(int tabCount) {
- if (options.indentWithTab) {
- for (int j = 0; j < tabCount; j++) {
- formattedSource.append('\t');
- increaseSplitDelta(1);
- }
- } else {
- for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- }
- }
-
- /**
- * Dumps <code>currentLineBuffer</code> into the formatted string.
- */
- private void flushBuffer() {
- String currentString = currentLineBuffer.toString();
- splitDelta = 0;
- beginningOfLineIndex = formattedSource.length();
- if (containsOpenCloseBraces) {
- containsOpenCloseBraces = false;
- outputLine(currentString, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0);
- indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
- } else {
- outputLine(currentString, false, currentLineIndentationLevel, 0, -1, null, 0);
- }
- int scannerSourceLength = scanner.source.length;
- if ((scannerSourceLength > 2) && (scanner.startPosition < scannerSourceLength)) {
- if (scanner.source[scannerSourceLength - 1] == '\n' && scanner.source[scannerSourceLength - 2] == '\r') {
- formattedSource.append(options.lineSeparatorSequence);
- increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
- } else if (scanner.source[scannerSourceLength - 1] == '\n') {
- formattedSource.append(options.lineSeparatorSequence);
- increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
- } else if (scanner.source[scannerSourceLength - 1] == '\r') {
- formattedSource.append(options.lineSeparatorSequence);
- increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
- }
- }
- updateMappedPositions(scanner.startPosition);
- }
-
- /**
- * Formats the input string.
- */
- private void format() {
- int token = 0;
- int previousToken = 0;
- int previousCompilableToken = 0;
- int indentationOffset = 0;
- int newLinesInWhitespace = 0;
- // number of new lines in the previous whitespace token
- // (used to leave blank lines before comments)
- int pendingNewLines = 0;
- boolean expectingOpenBrace = false;
- boolean clearNonBlockIndents = false;
- // true if all indentations till the 1st { (usefull after } or ;)
- boolean pendingSpace = true;
- boolean pendingNewlineAfterParen = false;
- // true when a cr is to be put after a ) (in conditional statements)
- boolean inAssignment = false;
- boolean inArrayAssignment = false;
- boolean inThrowsClause = false;
- boolean inClassOrInterfaceHeader = false;
- int dollarBraceCount = 0;
- // openBracketCount is used to count the number of open brackets not closed
- // yet.
- int openBracketCount = 0;
- int unarySignModifier = 0;
- // openParenthesis[0] is used to count the parenthesis not belonging to a
- // condition
- // (eg foo();). parenthesis in for (...) are count elsewhere in the array.
- int openParenthesisCount = 1;
- int[] openParenthesis = new int[10];
- // tokenBeforeColon is used to know what token goes along with the current
- // :
- // it can be case or ?
- int tokenBeforeColonCount = 0;
- int[] tokenBeforeColon = new int[10];
- constructionsCount = 0; // initializes the constructions count.
- // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
- int nlicsToken = 0;
- // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and else
- boolean specialElse = false;
- // OPTION (IndentationLevel): initial indentation level may be non-zero.
- currentLineIndentationLevel += constructionsCount;
- // An InvalidInputException exception might cause the termination of this
- // loop.
- int arrayDeclarationCount=0;
- int[] arrayDeclarationParenthesis=new int[10];
- try {
- while (true) {
- // Get the next token. Catch invalid input and output it
- // with minimal formatting, also catch end of input and
- // exit the loop.
- try {
- token = scanner.getNextToken();
- if (Scanner.DEBUG) {
- int currentEndPosition = scanner.getCurrentTokenEndPosition();
- int currentStartPosition = scanner.getCurrentTokenStartPosition();
- System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
- System.out.println(scanner.toStringAction(token));
- }
- // Patch for line comment
- // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=23096
- if (token == ITerminalSymbols.TokenNameCOMMENT_LINE) {
- int length = scanner.currentPosition;
- loop: for (int index = length - 1; index >= 0; index--) {
- switch (scanner.source[index]) {
- case '\r':
- case '\n':
- scanner.currentPosition--;
- break;
- default:
- break loop;
- }
- }
- }
- } catch (InvalidInputException e) {
- if (!handleInvalidToken(e)) {
- throw e;
- }
- token = 0;
- }
- if (token == Scanner.TokenNameEOF) {
- break;
- } else if (token == Scanner.TokenNameHEREDOC) {
- // no indentation for heredocs and HTML !
- outputCurrentTokenWithoutIndent(Scanner.TokenNameHEREDOC, 0);
- continue;
- } else if (token == Scanner.TokenNameINLINE_HTML) {
- // no indentation for heredocs and HTML !
- int newLineCount = 1;
- if (scanner.startPosition==0) {
- newLineCount = 0;
- }
- outputCurrentTokenWithoutIndent(Scanner.TokenNameINLINE_HTML, newLineCount);
- int srcLen = scanner.source.length;
- if (scanner.currentPosition < srcLen-1) {
- newLine(1);
- }
- continue;
- }
- /*
- * ## MODIFYING the indentation level before generating new lines and indentation in the output string
- */
- // Removes all the indentations made by statements not followed by a
- // block
- // except if the current token is ELSE, CATCH or if we are in a
- // switch/case
- if (clearNonBlockIndents && (token != Scanner.TokenNameWHITESPACE)) {
- switch (token) {
- case TokenNameelse:
- if (constructionsCount > 0 && constructions[constructionsCount - 1] == TokenNameelse) {
- pendingNewLines = 1;
- specialElse = true;
- }
- indentationLevel += popInclusiveUntil(TokenNameif);
- break;
- // case TokenNamecatch :
- // indentationLevel += popInclusiveUntil(TokenNamecatch);
- // break;
- // case TokenNamefinally :
- // indentationLevel += popInclusiveUntil(TokenNamecatch);
- // break;
- case TokenNamewhile:
- if (nlicsToken == TokenNamedo) {
- indentationLevel += pop(TokenNamedo);
- break;
- }
- default:
- indentationLevel += popExclusiveUntilBlockOrCase();
- // clear until a CASE, DEFAULT or BLOCK is encountered.
- // Thus, the indentationLevel is correctly cleared either
- // in a switch/case statement or in any other situation.
- }
- clearNonBlockIndents = false;
- }
- // returns to the indentation level created by the SWITCH keyword
- // if the current token is a CASE or a DEFAULT
- if (token == TokenNamecase || token == TokenNamedefault) {
- indentationLevel += pop(TokenNamecase);
- }
- // if (token == Scanner.TokenNamethrows) {
- // inThrowsClause = true;
- // }
- if ((token == Scanner.TokenNameclass || token == Scanner.TokenNameinterface) && previousToken != Scanner.TokenNameDOT) {
- inClassOrInterfaceHeader = true;
- }
- /*
- * ## APPEND newlines and indentations to the output string
- */
- // Do not add a new line between ELSE and IF, if the option
- // elseIfOnSameLine is true.
- // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
- // if (pendingNewlineAfterParen
- // && previousCompilableToken == TokenNameelse
- // && token == TokenNameif
- // && options.compactElseIfMode) {
- // pendingNewlineAfterParen = false;
- // pendingNewLines = 0;
- // indentationLevel += pop(TokenNameelse);
- // // because else if is now one single statement,
- // // the indentation level after it is increased by one and not by 2
- // // (else = 1 indent, if = 1 indent, but else if = 1 indent, not 2).
- // }
- // Add a newline & indent to the formatted source string if
- // a for/if-else/while statement was scanned and there is no block
- // following it.
- pendingNewlineAfterParen = pendingNewlineAfterParen
- || (previousCompilableToken == TokenNameRPAREN && token == TokenNameLBRACE);
- if (pendingNewlineAfterParen && token != Scanner.TokenNameWHITESPACE) {
- pendingNewlineAfterParen = false;
- // Do to add a newline & indent sequence if the current token is an
- // open brace or a period or if the current token is a semi-colon and
- // the
- // previous token is a close paren.
- // add a new line if a parenthesis belonging to a for() statement
- // has been closed and the current token is not an opening brace
- if (token != TokenNameLBRACE && !isComment(token)
- // to avoid adding new line between else and a comment
- && token != TokenNameDOT && !(previousCompilableToken == TokenNameRPAREN && token == TokenNameSEMICOLON)) {
- newLine(1);
- currentLineIndentationLevel = indentationLevel;
- pendingNewLines = 0;
- pendingSpace = false;
- } else {
- if (token == TokenNameLBRACE && options.newLineBeforeOpeningBraceMode) {
- newLine(1);
- if (constructionsCount > 0 && constructions[constructionsCount - 1] != BLOCK
- && constructions[constructionsCount - 1] != NONINDENT_BLOCK) {
- currentLineIndentationLevel = indentationLevel - 1;
- } else {
- currentLineIndentationLevel = indentationLevel;
- }
- pendingNewLines = 0;
- pendingSpace = false;
- }
- }
- }
- if (token == TokenNameLBRACE && options.newLineBeforeOpeningBraceMode && constructionsCount > 0
- && constructions[constructionsCount - 1] == TokenNamedo) {
- newLine(1);
- currentLineIndentationLevel = indentationLevel - 1;
- pendingNewLines = 0;
- pendingSpace = false;
- }
- // see PR 1G5G8EC
- if (token == TokenNameLBRACE && inThrowsClause) {
- inThrowsClause = false;
- if (options.newLineBeforeOpeningBraceMode) {
- newLine(1);
- currentLineIndentationLevel = indentationLevel;
- pendingNewLines = 0;
- pendingSpace = false;
- }
- }
- // see PR 1G5G82G
- if (token == TokenNameLBRACE && inClassOrInterfaceHeader) {
- inClassOrInterfaceHeader = false;
- if (options.newLineBeforeOpeningBraceMode) {
- newLine(1);
- currentLineIndentationLevel = indentationLevel;
- pendingNewLines = 0;
- pendingSpace = false;
- }
- }
- // Add pending new lines to the formatted source string.
- // Note: pending new lines are not added if the current token
- // is a single line comment or whitespace.
- // if the comment is between parenthesis, there is no blank line
- // preservation
- // (if it's a one-line comment, a blank line is added after it).
- if (((pendingNewLines > 0 && (!isComment(token)))
- || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token))) || (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE))
- && token != Scanner.TokenNameWHITESPACE) {
- // Do not add newline & indent between an adjoining close brace and
- // close paren. Anonymous inner classes may use this form.
- boolean closeBraceAndCloseParen = previousToken == TokenNameRBRACE && token == TokenNameRPAREN;
- // OPTION (NewLineInCompoundStatement): do not add newline & indent
- // between close brace and else, (do) while, catch, and finally if
- // newlineInCompoundStatement is true.
- boolean nlicsOption = previousToken == TokenNameRBRACE
- && !options.newlineInControlStatementMode
- && (token == TokenNameelse || (token == TokenNamewhile && nlicsToken == TokenNamedo) || token == TokenNamecatch || token == TokenNamefinally);
- // Do not add a newline & indent between a close brace and
- // semi-colon.
- boolean semiColonAndCloseBrace = previousToken == TokenNameRBRACE && token == TokenNameSEMICOLON;
- // Do not add a new line & indent between a multiline comment and a
- // opening brace
- boolean commentAndOpenBrace = previousToken == Scanner.TokenNameCOMMENT_BLOCK && token == TokenNameLBRACE;
- // Do not add a newline & indent between a close brace and a colon
- // (in array assignments, for example).
- boolean commaAndCloseBrace = previousToken == TokenNameRBRACE && token == TokenNameCOMMA;
- // Add a newline and indent, if appropriate.
- if (specialElse
- || (!commentAndOpenBrace && !closeBraceAndCloseParen && !nlicsOption && !semiColonAndCloseBrace && !commaAndCloseBrace)) {
- // if clearAllBlankLinesMode=false, leaves the blank lines
- // inserted by the user
- // if clearAllBlankLinesMode=true, removes all of then
- // and insert only blank lines required by the formatting.
- if (!options.clearAllBlankLinesMode) {
- // (isComment(token))
- pendingNewLines = (pendingNewLines < newLinesInWhitespace) ? newLinesInWhitespace : pendingNewLines;
- pendingNewLines = (pendingNewLines > 2) ? 2 : pendingNewLines;
- }
- if (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE) {
- containsOpenCloseBraces = true;
- indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
- if (isComment(previousToken)) {
- newLine(pendingNewLines);
- } else {
- /*
- * if (!(constructionsCount > 1 && constructions[constructionsCount-1] == NONINDENT_BLOCK &&
- * (constructions[constructionsCount-2] == TokenNamefor
- */
- if (options.newLineInEmptyBlockMode) {
- if (inArrayAssignment) {
- newLine(1); // array assigment with an empty block
- } else {
- newLine(pendingNewLines);
- }
- }
- // }
- }
- } else {
- // see PR 1FKKC3U: LFCOM:WINNT - Format problem with a comment
- // before the ';'
- if (!((previousToken == Scanner.TokenNameCOMMENT_BLOCK || previousToken == Scanner.TokenNameCOMMENT_PHPDOC) && token == TokenNameSEMICOLON)) {
- newLine(pendingNewLines);
- }
- }
- if (((previousCompilableToken == TokenNameSEMICOLON) || (previousCompilableToken == TokenNameLBRACE)
- || (previousCompilableToken == TokenNameRBRACE) || (isComment(previousToken)))
- && (token == TokenNameRBRACE)) {
- indentationOffset = -1;
- indentationLevel += popExclusiveUntilBlock();
- }
- if (previousToken == Scanner.TokenNameCOMMENT_LINE && inAssignment) {
- // PR 1FI5IPO
- currentLineIndentationLevel++;
- } else {
- currentLineIndentationLevel = indentationLevel + indentationOffset;
- }
- pendingSpace = false;
- indentationOffset = 0;
- }
- pendingNewLines = 0;
- newLinesInWhitespace = 0;
- specialElse = false;
- if (nlicsToken == TokenNamedo && token == TokenNamewhile) {
- nlicsToken = 0;
- }
- }
- boolean phpTagAndWhitespace = previousToken == TokenNameINLINE_HTML && token == TokenNameWHITESPACE;
- switch (token) {
- // case TokenNameDOLLAR :
- // dollarBraceCount++;
- // break;
- case TokenNameelse:
- // case TokenNamefinally :
- expectingOpenBrace = true;
- pendingNewlineAfterParen = true;
- indentationLevel += pushControlStatement(token);
- break;
- case TokenNamecase:
- case TokenNamedefault:
- if (tokenBeforeColonCount == tokenBeforeColon.length) {
- System
- .arraycopy(tokenBeforeColon, 0, (tokenBeforeColon = new int[tokenBeforeColonCount * 2]), 0, tokenBeforeColonCount);
- }
- tokenBeforeColon[tokenBeforeColonCount++] = TokenNamecase;
- indentationLevel += pushControlStatement(TokenNamecase);
- break;
- case TokenNameQUESTION:
- if (tokenBeforeColonCount == tokenBeforeColon.length) {
- System
- .arraycopy(tokenBeforeColon, 0, (tokenBeforeColon = new int[tokenBeforeColonCount * 2]), 0, tokenBeforeColonCount);
- }
- tokenBeforeColon[tokenBeforeColonCount++] = token;
- break;
- case TokenNameswitch:
- case TokenNamefor:
- case TokenNameforeach:
- case TokenNameif:
- case TokenNamewhile:
- if (openParenthesisCount == openParenthesis.length) {
- System.arraycopy(openParenthesis, 0, (openParenthesis = new int[openParenthesisCount * 2]), 0, openParenthesisCount);
- }
- openParenthesis[openParenthesisCount++] = 0;
- expectingOpenBrace = true;
- indentationLevel += pushControlStatement(token);
- break;
- case TokenNametry:
- pendingNewlineAfterParen = true;
- case TokenNamecatch:
- // several CATCH statements can be contiguous.
- // a CATCH is encountered pop until first CATCH (if a CATCH
- // follows a TRY it works the same way,
- // as CATCH and TRY are the same token in the stack).
- expectingOpenBrace = true;
- indentationLevel += pushControlStatement(TokenNamecatch);
- break;
- case TokenNamedo:
- expectingOpenBrace = true;
- indentationLevel += pushControlStatement(token);
- nlicsToken = token;
- break;
- case TokenNamenew:
- break;
- case TokenNameLPAREN:
- // if (previousToken == TokenNamesynchronized) {
- // indentationLevel += pushControlStatement(previousToken);
- // } else {
- // Put a space between the previous and current token if the
- // previous token was not a keyword, open paren, logical
- // compliment (eg: !), semi-colon, open brace, close brace,
- // super, or this.
- if (previousCompilableToken != TokenNameLBRACKET && previousToken != TokenNameIdentifier && previousToken != 0
- && previousToken != TokenNameNOT && previousToken != TokenNameLPAREN && previousToken != TokenNameTWIDDLE
- && previousToken != TokenNameSEMICOLON && previousToken != TokenNameLBRACE && previousToken != TokenNameRBRACE
- && previousToken != TokenNamesuper) {
- // && previousToken != TokenNamethis) {
- space();
- }
- // If in a for/if/while statement, increase the parenthesis count
- // for the current openParenthesisCount
- // else increase the count for stand alone parenthesis.
- if (openParenthesisCount > 0)
- openParenthesis[openParenthesisCount - 1]++;
- else
- openParenthesis[0]++;
- pendingSpace = false;
- // recognize array declaration for nice output
- if (previousCompilableToken == TokenNamearray) {
- arrayDeclarationCount++;
- arrayDeclarationParenthesis[arrayDeclarationCount]=openParenthesis[openParenthesisCount];
- indentationLevel++;
- pendingNewLines=1;
- }
- //S }
- break;
- case TokenNameRPAREN:
- // check for closing array declaration
- if (arrayDeclarationCount>0) {
- if (arrayDeclarationParenthesis[arrayDeclarationCount]==openParenthesis[openParenthesisCount]) {
- newLine(1);
- indentationLevel--;
- currentLineIndentationLevel = indentationLevel;
- pendingNewLines = 0;
- arrayDeclarationCount--;
- }
- }
- // Decrease the parenthesis count
- // if there is no more unclosed parenthesis,
- // a new line and indent may be append (depending on the next
- // token).
- if ((openParenthesisCount > 1) && (openParenthesis[openParenthesisCount - 1] > 0)) {
- openParenthesis[openParenthesisCount - 1]--;
- if (openParenthesis[openParenthesisCount - 1] <= 0) {
- pendingNewlineAfterParen = true;
- inAssignment = false;
- openParenthesisCount--;
- }
- } else {
- openParenthesis[0]--;
- }
- pendingSpace = false;
- break;
- case TokenNameLBRACE:
- if (previousCompilableToken == TokenNameDOLLAR) {
- dollarBraceCount++;
- } else {
- if ((previousCompilableToken == TokenNameRBRACKET) || (previousCompilableToken == TokenNameEQUAL)) {
- // if (previousCompilableToken == TokenNameRBRACKET) {
- inArrayAssignment = true;
- inAssignment = false;
- }
- if (inArrayAssignment) {
- indentationLevel += pushBlock();
- } else {
- // Add new line and increase indentation level after open brace.
- pendingNewLines = 1;
- indentationLevel += pushBlock();
- }
- }
- break;
- case TokenNameRBRACE:
- if (dollarBraceCount > 0) {
- dollarBraceCount--;
- break;
- }
- if (previousCompilableToken == TokenNameRPAREN) {
- pendingSpace = false;
- }
- if (inArrayAssignment) {
- inArrayAssignment = false;
- pendingNewLines = 1;
- indentationLevel += popInclusiveUntilBlock();
- } else {
- pendingNewLines = 1;
- indentationLevel += popInclusiveUntilBlock();
- if (previousCompilableToken == TokenNameRPAREN) {
- // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on message
- // expression
- currentLineBuffer.append(options.lineSeparatorSequence);
- increaseLineDelta(options.lineSeparatorSequence.length);
- }
- if (constructionsCount > 0) {
- switch (constructions[constructionsCount - 1]) {
- case TokenNamefor:
- case TokenNameforeach:
- //indentationLevel += popExclusiveUntilBlock();
- //break;
- case TokenNameswitch:
- case TokenNameif:
- case TokenNameelse:
- case TokenNametry:
- case TokenNamecatch:
- case TokenNamefinally:
- case TokenNamewhile:
- case TokenNamedo:
- // case TokenNamesynchronized :
- clearNonBlockIndents = true;
- default:
- break;
- }
- }
- }
- break;
- case TokenNameLBRACKET:
- openBracketCount++;
- pendingSpace = false;
- break;
- case TokenNameRBRACKET:
- openBracketCount -= (openBracketCount > 0) ? 1 : 0;
- // if there is no left bracket to close, the right bracket is
- // ignored.
- pendingSpace = false;
- break;
- case TokenNameCOMMA:
- pendingSpace = false;
- if (arrayDeclarationCount>0) {
- pendingNewLines=1;
- }
- break;
- case TokenNameDOT:
- pendingSpace = false;
- break;
- case TokenNameSEMICOLON:
- // Do not generate line terminators in the definition of
- // the for statement.
- // if not in this case, jump a line and reduce indentation after
- // the brace
- // if the block it closes belongs to a conditional statement (if,
- // while, do...).
- if (openParenthesisCount <= 1) {
- pendingNewLines = 1;
- if (expectingOpenBrace) {
- clearNonBlockIndents = true;
- expectingOpenBrace = false;
- }
- }
- inAssignment = false;
- pendingSpace = false;
- break;
- case TokenNamePLUS_PLUS:
- case TokenNameMINUS_MINUS:
- // Do not put a space between a post-increment/decrement
- // and the identifier being modified.
- if (previousToken == TokenNameIdentifier || previousToken == TokenNameRBRACKET || previousToken == TokenNameVariable) {
- pendingSpace = false;
- }
- break;
- case TokenNamePLUS:
- // previously ADDITION
- case TokenNameMINUS:
- // Handle the unary operators plus and minus via a flag
- if (!isLiteralToken(previousToken) && previousToken != TokenNameIdentifier && previousToken != TokenNameRPAREN
- && previousToken != TokenNameRBRACKET) {
- unarySignModifier = 1;
- }
- break;
- case TokenNameCOLON:
- // In a switch/case statement, add a newline & indent
- // when a colon is encountered.
- if (tokenBeforeColonCount > 0) {
- if (tokenBeforeColon[tokenBeforeColonCount - 1] == TokenNamecase) {
- pendingNewLines = 1;
- }
- tokenBeforeColonCount--;
- }
- break;
- case TokenNameEQUAL:
- inAssignment = true;
- break;
- case Scanner.TokenNameCOMMENT_LINE:
- pendingNewLines = 1;
- if (inAssignment) {
- currentLineIndentationLevel++;
- }
- break; // a line is always inserted after a one-line comment
- case Scanner.TokenNameCOMMENT_PHPDOC:
- case Scanner.TokenNameCOMMENT_BLOCK:
- currentCommentOffset = getCurrentCommentOffset();
- pendingNewLines = 1;
- break;
- case Scanner.TokenNameWHITESPACE:
- if (!phpTagAndWhitespace) {
- // Count the number of line terminators in the whitespace so
- // line spacing can be preserved near comments.
- char[] source = scanner.source;
- newLinesInWhitespace = 0;
- for (int i = scanner.startPosition, max = scanner.currentPosition; i < max; i++) {
- if (source[i] == '\r') {
- if (i < max - 1) {
- if (source[++i] == '\n') {
- newLinesInWhitespace++;
- } else {
- newLinesInWhitespace++;
- }
- } else {
- newLinesInWhitespace++;
- }
- } else if (source[i] == '\n') {
- newLinesInWhitespace++;
- }
- }
- increaseLineDelta(scanner.startPosition - scanner.currentPosition);
- break;
- }
- // case TokenNameHTML :
- // // Add the next token to the formatted source string.
- // // outputCurrentToken(token);
- // int startPosition = scanner.startPosition;
- // flushBuffer();
- // for (int i = startPosition, max = scanner.currentPosition; i <
- // max; i++) {
- // char currentCharacter = scanner.source[i];
- // updateMappedPositions(i);
- // currentLineBuffer.append(currentCharacter);
- // }
- // break;
- default:
- if ((token == TokenNameIdentifier) || isLiteralToken(token) || token == TokenNamesuper) {
- // || token == TokenNamethis) {
- // Do not put a space between a unary operator
- // (eg: ++, --, +, -) and the identifier being modified.
- if (previousToken == TokenNamePLUS_PLUS || previousToken == TokenNameMINUS_MINUS
- || (previousToken == TokenNameMINUS_GREATER && options.compactDereferencingMode) // ->
- || (previousToken == TokenNamePLUS && unarySignModifier > 0)
- || (previousToken == TokenNameMINUS && unarySignModifier > 0)) {
- pendingSpace = false;
- }
- unarySignModifier = 0;
- }
- break;
- }
- // Do not output whitespace tokens.
- if (token != Scanner.TokenNameWHITESPACE || phpTagAndWhitespace) {
- /*
- * Add pending space to the formatted source string. Do not output a space under the following circumstances: 1) this is
- * the first pass 2) previous token is an open paren 3) previous token is a period 4) previous token is the logical
- * compliment (eg: !) 5) previous token is the bitwise compliment (eg: ~) 6) previous token is the open bracket (eg: [) 7)
- * in an assignment statement, if the previous token is an open brace or the current token is a close brace 8) previous
- * token is a single line comment 9) current token is a '->'
- */
- if (token == TokenNameMINUS_GREATER && options.compactDereferencingMode)
- pendingSpace = false;
-
- boolean openAndCloseBrace = previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE;
- if (pendingSpace && insertSpaceAfter(previousToken)
- && !(inAssignment && (previousToken == TokenNameLBRACE || token == TokenNameRBRACE))
- && previousToken != Scanner.TokenNameCOMMENT_LINE) {
- if ((!(options.compactAssignmentMode && token == TokenNameEQUAL)) && !openAndCloseBrace)
- space();
- }
- // Add the next token to the formatted source string.
- outputCurrentToken(token);
- if (token == Scanner.TokenNameCOMMENT_LINE && openParenthesisCount > 1) {
- pendingNewLines = 0;
- currentLineBuffer.append(options.lineSeparatorSequence);
- increaseLineDelta(options.lineSeparatorSequence.length);
- }
- pendingSpace = true;
- }
- // Whitespace tokens do not need to be remembered.
- if (token != Scanner.TokenNameWHITESPACE || phpTagAndWhitespace) {
- previousToken = token;
- if (token != Scanner.TokenNameCOMMENT_BLOCK && token != Scanner.TokenNameCOMMENT_LINE
- && token != Scanner.TokenNameCOMMENT_PHPDOC) {
- previousCompilableToken = token;
- }
- }
- }
- output(copyRemainingSource());
- flushBuffer();
- // dump the last token of the source in the formatted output.
- } catch (InvalidInputException e) {
- output(copyRemainingSource());
- flushBuffer();
- // dump the last token of the source in the formatted output.
- }
- }
-
- /**
- * Formats the char array <code>sourceString</code>, and returns a string containing the formatted version.
- *
- * @return the formatted ouput.
- */
- public String formatSourceString(String sourceString) {
- char[] sourceChars = sourceString.toCharArray();
- formattedSource = new StringBuffer(sourceChars.length);
- scanner.setSource(sourceChars);
- format();
- return formattedSource.toString();
- }
-
- /**
- * Formats the char array <code>sourceString</code>, and returns a string containing the formatted version.
- *
- * @param string
- * the string to format
- * @param indentationLevel
- * the initial indentation level
- * @return the formatted ouput.
- */
- public String format(String string, int indentationLevel) {
- return format(string, indentationLevel, (int[]) null);
- }
-
- /**
- * Formats the char array <code>sourceString</code>, and returns a string containing the formatted version. The positions array
- * is modified to contain the mapped positions.
- *
- * @param string
- * the string to format
- * @param indentationLevel
- * the initial indentation level
- * @param positions
- * the array of positions to map
- * @return the formatted ouput.
- */
- public String format(String string, int indentationLevel, int[] positions) {
- return this.format(string, indentationLevel, positions, null);
- }
-
- public String format(String string, int indentationLevel, int[] positions, String lineSeparator) {
- if (lineSeparator != null) {
- this.options.setLineSeparator(lineSeparator);
- }
- if (positions != null) {
- this.setPositionsToMap(positions);
- this.setInitialIndentationLevel(indentationLevel);
- String formattedString = this.formatSourceString(string);
- int[] mappedPositions = this.getMappedPositions();
- System.arraycopy(mappedPositions, 0, positions, 0, positions.length);
- return formattedString;
- } else {
- this.setInitialIndentationLevel(indentationLevel);
- return this.formatSourceString(string);
- }
- }
-
- /**
- * Formats the char array <code>sourceString</code>, and returns a string containing the formatted version. The initial
- * indentation level is 0.
- *
- * @param string
- * the string to format
- * @return the formatted ouput.
- */
- public String format(String string) {
- return this.format(string, 0, (int[]) null);
- }
-
- /**
- * Formats a given source string, starting indenting it at a particular depth and using the given options
- *
- * @deprecated backport 1.0 internal functionality
- */
- public static String format(String sourceString, int initialIndentationLevel, ConfigurableOption[] options) {
- CodeFormatter formatter = new CodeFormatter(options);
- formatter.setInitialIndentationLevel(initialIndentationLevel);
- return formatter.formatSourceString(sourceString);
- }
-
- /**
- * Returns the number of characters and tab char between the beginning of the line and the beginning of the comment.
- */
- private int getCurrentCommentOffset() {
- int linePtr = scanner.linePtr;
- // if there is no beginning of line, return 0.
- if (linePtr < 0)
- return 0;
- int offset = 0;
- int beginningOfLine = scanner.lineEnds[linePtr];
- int currentStartPosition = scanner.startPosition;
- char[] source = scanner.source;
- // find the position of the beginning of the line containing the comment
- while (beginningOfLine > currentStartPosition) {
- if (linePtr > 0) {
- beginningOfLine = scanner.lineEnds[--linePtr];
- } else {
- beginningOfLine = 0;
- break;
- }
- }
- for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) {
- char currentCharacter = source[i];
- switch (currentCharacter) {
- case '\t':
- offset += options.tabSize;
- break;
- case ' ':
- offset++;
- break;
- case '\r':
- case '\n':
- break;
- default:
- return offset;
- }
- }
- return offset;
- }
-
- /**
- * Returns an array of descriptions for the configurable options. The descriptions may be changed and passed back to a different
- * compiler.
- *
- * @deprecated backport 1.0 internal functionality
- */
- public static ConfigurableOption[] getDefaultOptions(Locale locale) {
- String componentName = CodeFormatter.class.getName();
- FormatterOptions options = new FormatterOptions();
- return new ConfigurableOption[] {
- new ConfigurableOption(componentName, "newline.openingBrace", locale, options.newLineBeforeOpeningBraceMode ? 0 : 1),
- //$NON-NLS-1$
- new ConfigurableOption(componentName, "newline.controlStatement", locale, options.newlineInControlStatementMode ? 0 : 1),
- //$NON-NLS-1$
- new ConfigurableOption(componentName, "newline.clearAll", locale, options.clearAllBlankLinesMode ? 0 : 1),
- //$NON-NLS-1$
- // new ConfigurableOption(componentName, "newline.elseIf", locale,
- // options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$
- new ConfigurableOption(componentName, "newline.emptyBlock", locale, options.newLineInEmptyBlockMode ? 0 : 1),
- //$NON-NLS-1$
- new ConfigurableOption(componentName, "line.split", locale, options.maxLineLength),
- //$NON-NLS-1$
- new ConfigurableOption(componentName, "style.compactAssignment", locale, options.compactAssignmentMode ? 0 : 1),
- //$NON-NLS-1$
- new ConfigurableOption(componentName, "tabulation.char", locale, options.indentWithTab ? 0 : 1),
- //$NON-NLS-1$
- new ConfigurableOption(componentName, "tabulation.size", locale, options.tabSize) //$NON-NLS-1$
- };
- }
-
- /**
- * Returns the array of mapped positions. Returns null is no positions have been set.
- *
- * @return int[]
- * @deprecated There is no need to retrieve the mapped positions anymore.
- */
- public int[] getMappedPositions() {
- return mappedPositions;
- }
-
- /**
- * Returns the priority of the token given as argument <br>
- * The most prioritary the token is, the smallest the return value is.
- *
- * @return the priority of <code>token</code>
- * @param token
- * the token of which the priority is requested
- */
- private static int getTokenPriority(int token) {
- switch (token) {
- case TokenNameextends:
- // case TokenNameimplements :
- // case TokenNamethrows :
- return 10;
- case TokenNameSEMICOLON:
- // ;
- return 20;
- case TokenNameCOMMA:
- // ,
- return 25;
- case TokenNameEQUAL:
- // =
- return 30;
- case TokenNameAND_AND:
- // &&
- case TokenNameOR_OR:
- // ||
- return 40;
- case TokenNameQUESTION:
- // ?
- case TokenNameCOLON:
- // :
- return 50; // it's better cutting on ?: than on ;
- case TokenNameEQUAL_EQUAL:
- // ==
- case TokenNameEQUAL_EQUAL_EQUAL:
- // ===
- case TokenNameNOT_EQUAL:
- // !=
- case TokenNameNOT_EQUAL_EQUAL:
- // !=
- return 60;
- case TokenNameLESS:
- // <
- case TokenNameLESS_EQUAL:
- // <=
- case TokenNameGREATER:
- // >
- case TokenNameGREATER_EQUAL:
- // >=
- // case TokenNameinstanceof : // instanceof
- return 70;
- case TokenNamePLUS:
- // +
- case TokenNameMINUS:
- // -
- return 80;
- case TokenNameMULTIPLY:
- // *
- case TokenNameDIVIDE:
- // /
- case TokenNameREMAINDER:
- // %
- return 90;
- case TokenNameLEFT_SHIFT:
- // <<
- case TokenNameRIGHT_SHIFT:
- // >>
- // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>>
- return 100;
- case TokenNameAND:
- // &
- case TokenNameOR:
- // |
- case TokenNameXOR:
- // ^
- return 110;
- case TokenNameMULTIPLY_EQUAL:
- // *=
- case TokenNameDIVIDE_EQUAL:
- // /=
- case TokenNameREMAINDER_EQUAL:
- // %=
- case TokenNamePLUS_EQUAL:
- // +=
- case TokenNameMINUS_EQUAL:
- // -=
- case TokenNameLEFT_SHIFT_EQUAL:
- // <<=
- case TokenNameRIGHT_SHIFT_EQUAL:
- // >>=
- // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
- case TokenNameAND_EQUAL:
- // &=
- case TokenNameXOR_EQUAL:
- // ^=
- case TokenNameOR_EQUAL:
- // .=
- case TokenNameDOT_EQUAL:
- // |=
- return 120;
- case TokenNameDOT:
- // .
- return 130;
- default:
- return Integer.MAX_VALUE;
- }
- }
-
- /**
- * Handles the exception raised when an invalid token is encountered. Returns true if the exception has been handled, false
- * otherwise.
- */
- private boolean handleInvalidToken(Exception e) {
- if (e.getMessage().equals(Scanner.INVALID_CHARACTER_CONSTANT) || e.getMessage().equals(Scanner.INVALID_CHAR_IN_STRING)
- || e.getMessage().equals(Scanner.INVALID_ESCAPE)) {
- return true;
- }
- return false;
- }
-
- private final void increaseGlobalDelta(int offset) {
- globalDelta += offset;
- }
-
- private final void increaseLineDelta(int offset) {
- lineDelta += offset;
- }
-
- private final void increaseSplitDelta(int offset) {
- splitDelta += offset;
- }
-
- /**
- * Returns true if a space has to be inserted after <code>operator</code> false otherwise.
- */
- private boolean insertSpaceAfter(int token) {
- switch (token) {
- case TokenNameLPAREN:
- case TokenNameNOT:
- case TokenNameTWIDDLE:
- case TokenNameDOT:
- case 0:
- // no token
- case TokenNameWHITESPACE:
- case TokenNameLBRACKET:
- case TokenNameDOLLAR:
- case Scanner.TokenNameCOMMENT_LINE:
- return false;
- default:
- return true;
- }
- }
-
- /**
- * Returns true if a space has to be inserted before <code>operator</code> false otherwise. <br>
- * Cannot be static as it uses the code formatter options (to know if the compact assignment mode is on).
- */
- private boolean insertSpaceBefore(int token) {
- switch (token) {
- case TokenNameEQUAL:
- return (!options.compactAssignmentMode);
- default:
- return false;
- }
- }
-
- private static boolean isComment(int token) {
- boolean result = token == Scanner.TokenNameCOMMENT_BLOCK || token == Scanner.TokenNameCOMMENT_LINE
- || token == Scanner.TokenNameCOMMENT_PHPDOC;
- return result;
- }
-
- private static boolean isLiteralToken(int token) {
- boolean result = token == TokenNameIntegerLiteral
- // || token == TokenNameLongLiteral
- // || token == TokenNameFloatingPointLiteral
- || token == TokenNameDoubleLiteral
- // || token == TokenNameCharacterLiteral
- || token == TokenNameStringDoubleQuote;
- return result;
- }
-
- /**
- * If the length of <code>oneLineBuffer</code> exceeds <code>maxLineLength</code>, it is split and the result is dumped in
- * <code>formattedSource</code>
- *
- * @param newLineCount
- * the number of new lines to append
- */
- private void newLine(int newLineCount) {
- // format current line
- splitDelta = 0;
- beginningOfLineIndex = formattedSource.length();
- String currentLine = currentLineBuffer.toString();
- if (containsOpenCloseBraces) {
- containsOpenCloseBraces = false;
- outputLine(currentLine, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0);
- indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
- } else {
- outputLine(currentLine, false, currentLineIndentationLevel, 0, -1, null, 0);
- }
- // dump line break(s)
- for (int i = 0; i < newLineCount; i++) {
- formattedSource.append(options.lineSeparatorSequence);
- increaseSplitDelta(options.lineSeparatorSequence.length);
- }
- // reset formatter for next line
- int currentLength = currentLine.length();
- currentLineBuffer = new StringBuffer(currentLength > maxLineSize ? maxLineSize = currentLength : maxLineSize);
- increaseGlobalDelta(splitDelta);
- increaseGlobalDelta(lineDelta);
- lineDelta = 0;
- currentLineIndentationLevel = initialIndentationLevel;
- }
-
- private String operatorString(int operator) {
- switch (operator) {
- case TokenNameextends:
- return "extends"; //$NON-NLS-1$
- // case TokenNameimplements :
- // return "implements"; //$NON-NLS-1$
- //
- // case TokenNamethrows :
- // return "throws"; //$NON-NLS-1$
- case TokenNameSEMICOLON:
- // ;
- return ";"; //$NON-NLS-1$
- case TokenNameCOMMA:
- // ,
- return ","; //$NON-NLS-1$
- case TokenNameEQUAL:
- // =
- return "="; //$NON-NLS-1$
- case TokenNameAND_AND:
- // && (15.22)
- return "&&"; //$NON-NLS-1$
- case TokenNameOR_OR:
- // || (15.23)
- return "||"; //$NON-NLS-1$
- case TokenNameQUESTION:
- // ? (15.24)
- return "?"; //$NON-NLS-1$
- case TokenNameCOLON:
- // : (15.24)
- return ":"; //$NON-NLS-1$
- case TokenNamePAAMAYIM_NEKUDOTAYIM:
- // : (15.24)
- return "::"; //$NON-NLS-1$
- case TokenNameEQUAL_EQUAL:
- // == (15.20, 15.20.1, 15.20.2, 15.20.3)
- return "=="; //$NON-NLS-1$
- case TokenNameEQUAL_EQUAL_EQUAL:
- // == (15.20, 15.20.1, 15.20.2, 15.20.3)
- return "==="; //$NON-NLS-1$
- case TokenNameEQUAL_GREATER:
- // -= (15.25.2)
- return "=>"; //$NON-NLS-1$
- case TokenNameNOT_EQUAL:
- // != (15.20, 15.20.1, 15.20.2, 15.20.3)
- return "!="; //$NON-NLS-1$
- case TokenNameNOT_EQUAL_EQUAL:
- // != (15.20, 15.20.1, 15.20.2, 15.20.3)
- return "!=="; //$NON-NLS-1$
- case TokenNameLESS:
- // < (15.19.1)
- return "<"; //$NON-NLS-1$
- case TokenNameLESS_EQUAL:
- // <= (15.19.1)
- return "<="; //$NON-NLS-1$
- case TokenNameGREATER:
- // > (15.19.1)
- return ">"; //$NON-NLS-1$
- case TokenNameGREATER_EQUAL:
- // >= (15.19.1)
- return ">="; //$NON-NLS-1$
- // case TokenNameinstanceof : // instanceof
- // return "instanceof"; //$NON-NLS-1$
- case TokenNamePLUS:
- // + (15.17, 15.17.2)
- return "+"; //$NON-NLS-1$
- case TokenNameMINUS:
- // - (15.17.2)
- return "-"; //$NON-NLS-1$
- case TokenNameMULTIPLY:
- // * (15.16.1)
- return "*"; //$NON-NLS-1$
- case TokenNameDIVIDE:
- // / (15.16.2)
- return "/"; //$NON-NLS-1$
- case TokenNameREMAINDER:
- // % (15.16.3)
- return "%"; //$NON-NLS-1$
- case TokenNameLEFT_SHIFT:
- // << (15.18)
- return "<<"; //$NON-NLS-1$
- case TokenNameRIGHT_SHIFT:
- // >> (15.18)
- return ">>"; //$NON-NLS-1$
- // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
- // return ">>>"; //$NON-NLS-1$
- case TokenNameAND:
- // & (15.21, 15.21.1, 15.21.2)
- return "&"; //$NON-NLS-1$
- case TokenNameOR:
- // | (15.21, 15.21.1, 15.21.2)
- return "|"; //$NON-NLS-1$
- case TokenNameXOR:
- // ^ (15.21, 15.21.1, 15.21.2)
- return "^"; //$NON-NLS-1$
- case TokenNameMULTIPLY_EQUAL:
- // *= (15.25.2)
- return "*="; //$NON-NLS-1$
- case TokenNameDIVIDE_EQUAL:
- // /= (15.25.2)
- return "/="; //$NON-NLS-1$
- case TokenNameREMAINDER_EQUAL:
- // %= (15.25.2)
- return "%="; //$NON-NLS-1$
- case TokenNamePLUS_EQUAL:
- // += (15.25.2)
- return "+="; //$NON-NLS-1$
- case TokenNameMINUS_EQUAL:
- // -= (15.25.2)
- return "-="; //$NON-NLS-1$
- case TokenNameMINUS_GREATER:
- // -= (15.25.2)
- return "->"; //$NON-NLS-1$
- case TokenNameLEFT_SHIFT_EQUAL:
- // <<= (15.25.2)
- return "<<="; //$NON-NLS-1$
- case TokenNameRIGHT_SHIFT_EQUAL:
- // >>= (15.25.2)
- return ">>="; //$NON-NLS-1$
- // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
- // return ">>>="; //$NON-NLS-1$
- case TokenNameAND_EQUAL:
- // &= (15.25.2)
- return "&="; //$NON-NLS-1$
- case TokenNameXOR_EQUAL:
- // ^= (15.25.2)
- return "^="; //$NON-NLS-1$
- case TokenNameOR_EQUAL:
- // |= (15.25.2)
- return "|="; //$NON-NLS-1$
- case TokenNameDOT_EQUAL:
- // .=
- return ".="; //$NON-NLS-1$
- case TokenNameDOT:
- // .
- return "."; //$NON-NLS-1$
- default:
- return ""; //$NON-NLS-1$
- }
- }
-
- /**
- * Appends <code>stringToOutput</code> to the formatted output. <br>
- * If it contains \n, append a LINE_SEPARATOR and indent after it.
- */
- private void output(String stringToOutput) {
- char currentCharacter;
- for (int i = 0, max = stringToOutput.length(); i < max; i++) {
- currentCharacter = stringToOutput.charAt(i);
- if (currentCharacter != '\t') {
- currentLineBuffer.append(currentCharacter);
- }
- }
- }
-
- private void outputCurrentTokenWithoutIndent(int token, int newLineCount) {
- newLine(newLineCount);
- formattedSource.append(scanner.source, scanner.startPosition, scanner.currentPosition - scanner.startPosition);
- }
-
- /**
- * Appends <code>token</code> to the formatted output. <br>
- * If it contains <code>\n</code>, append a LINE_SEPARATOR and indent after it.
- */
- private void outputCurrentToken(int token) {
- char[] source = scanner.source;
- int startPosition = scanner.startPosition;
- switch (token) {
- case Scanner.TokenNameCOMMENT_PHPDOC:
- case Scanner.TokenNameCOMMENT_BLOCK:
- case Scanner.TokenNameCOMMENT_LINE:
- boolean endOfLine = false;
- int currentCommentOffset = getCurrentCommentOffset();
- int beginningOfLineSpaces = 0;
- endOfLine = false;
- currentCommentOffset = getCurrentCommentOffset();
- beginningOfLineSpaces = 0;
- boolean pendingCarriageReturn = false;
- for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
- char currentCharacter = source[i];
- updateMappedPositions(i);
- switch (currentCharacter) {
- case '\r':
- pendingCarriageReturn = true;
- endOfLine = true;
- break;
- case '\n':
- if (pendingCarriageReturn) {
- increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
- } else {
- increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
- }
- pendingCarriageReturn = false;
- currentLineBuffer.append(options.lineSeparatorSequence);
- beginningOfLineSpaces = 0;
- endOfLine = true;
- break;
- case '\t':
- if (pendingCarriageReturn) {
- pendingCarriageReturn = false;
- increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
- currentLineBuffer.append(options.lineSeparatorSequence);
- beginningOfLineSpaces = 0;
- endOfLine = true;
- }
- if (endOfLine) {
- // we remove a maximum of currentCommentOffset characters (tabs
- // are converted to space numbers).
- beginningOfLineSpaces += options.tabSize;
- if (beginningOfLineSpaces > currentCommentOffset) {
- currentLineBuffer.append(currentCharacter);
- } else {
- increaseGlobalDelta(-1);
- }
- } else {
- currentLineBuffer.append(currentCharacter);
- }
- break;
- case ' ':
- if (pendingCarriageReturn) {
- pendingCarriageReturn = false;
- increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
- currentLineBuffer.append(options.lineSeparatorSequence);
- beginningOfLineSpaces = 0;
- endOfLine = true;
- }
- if (endOfLine) {
- // we remove a maximum of currentCommentOffset characters (tabs
- // are converted to space numbers).
- beginningOfLineSpaces++;
- if (beginningOfLineSpaces > currentCommentOffset) {
- currentLineBuffer.append(currentCharacter);
- } else {
- increaseGlobalDelta(-1);
- }
- } else {
- currentLineBuffer.append(currentCharacter);
- }
- break;
- default:
- if (pendingCarriageReturn) {
- pendingCarriageReturn = false;
- increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
- currentLineBuffer.append(options.lineSeparatorSequence);
- beginningOfLineSpaces = 0;
- endOfLine = true;
- } else {
- beginningOfLineSpaces = 0;
- currentLineBuffer.append(currentCharacter);
- endOfLine = false;
- }
- }
- }
- updateMappedPositions(scanner.currentPosition - 1);
- multipleLineCommentCounter++;
- break;
- default:
- for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
- char currentCharacter = source[i];
- updateMappedPositions(i);
- currentLineBuffer.append(currentCharacter);
- }
- }
- }
-
- /**
- * Outputs <code>currentString</code>:<br>
- * <ul>
- * <li>If its length is < maxLineLength, output
- * <li>Otherwise it is split.
- * </ul>
- *
- * @param currentString
- * string to output
- * @param preIndented
- * whether the string to output was pre-indented
- * @param depth
- * number of indentation to put in front of <code>currentString</code>
- * @param operator
- * value of the operator belonging to <code>currentString</code>.
- */
- private void outputLine(String currentString, boolean preIndented, int depth, int operator, int substringIndex,
- int[] startSubstringIndexes, int offsetInGlobalLine) {
- boolean emptyFirstSubString = false;
- String operatorString = operatorString(operator);
- boolean placeOperatorBehind = !breakLineBeforeOperator(operator);
- boolean placeOperatorAhead = !placeOperatorBehind;
- // dump prefix operator?
- if (placeOperatorAhead) {
- if (!preIndented) {
- dumpTab(depth);
- preIndented = true;
- }
- if (operator != 0) {
- if (insertSpaceBefore(operator)) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- formattedSource.append(operatorString);
- increaseSplitDelta(operatorString.length());
- if (insertSpaceAfter(operator) && operator != TokenNameimplements && operator != TokenNameextends) {
- // && operator != TokenNamethrows) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- }
- }
- SplitLine splitLine = null;
- if (options.maxLineLength == 0 || getLength(currentString, depth) < options.maxLineLength
- || (splitLine = split(currentString, offsetInGlobalLine)) == null) {
- // depending on the type of operator, outputs new line before of after
- // dumping it
- // indent before postfix operator
- // indent also when the line cannot be split
- if (operator == TokenNameextends || operator == TokenNameimplements) {
- // || operator == TokenNamethrows) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- if (placeOperatorBehind) {
- if (!preIndented) {
- dumpTab(depth);
- }
- }
- int max = currentString.length();
- if (multipleLineCommentCounter != 0) {
- try {
- BufferedReader reader = new BufferedReader(new StringReader(currentString));
- String line = reader.readLine();
- while (line != null) {
- updateMappedPositionsWhileSplitting(beginningOfLineIndex, beginningOfLineIndex + line.length()
- + options.lineSeparatorSequence.length);
- formattedSource.append(line);
- beginningOfLineIndex = beginningOfLineIndex + line.length();
- if ((line = reader.readLine()) != null) {
- formattedSource.append(options.lineSeparatorSequence);
- beginningOfLineIndex += options.lineSeparatorSequence.length;
- dumpTab(currentLineIndentationLevel);
- }
- }
- reader.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- } else {
- updateMappedPositionsWhileSplitting(beginningOfLineIndex, beginningOfLineIndex + max);
- for (int i = 0; i < max; i++) {
- char currentChar = currentString.charAt(i);
- switch (currentChar) {
- case '\r':
- break;
- case '\n':
- if (i != max - 1) {
- // fix for 1FFYL5C: LFCOM:ALL - Incorrect indentation when
- // split with a comment inside a condition
- // a substring cannot end with a lineSeparatorSequence,
- // except if it has been added by format() after a one-line
- // comment
- formattedSource.append(options.lineSeparatorSequence);
- // 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression
- dumpTab(depth - 1);
- }
- break;
- default:
- formattedSource.append(currentChar);
- }
- }
- }
- // update positions inside the mappedPositions table
- if (substringIndex != -1) {
- if (multipleLineCommentCounter == 0) {
- int startPosition = beginningOfLineIndex + startSubstringIndexes[substringIndex];
- updateMappedPositionsWhileSplitting(startPosition, startPosition + max);
- }
- // compute the splitDelta resulting with the operator and blank removal
- if (substringIndex + 1 != startSubstringIndexes.length) {
- increaseSplitDelta(startSubstringIndexes[substringIndex] + max - startSubstringIndexes[substringIndex + 1]);
- }
- }
- // dump postfix operator?
- if (placeOperatorBehind) {
- if (insertSpaceBefore(operator)) {
- formattedSource.append(' ');
- if (operator != 0) {
- increaseSplitDelta(1);
- }
- }
- formattedSource.append(operatorString);
- if (operator != 0) {
- increaseSplitDelta(operatorString.length());
- }
- }
- return;
- }
- // fix for 1FG0BA3: LFCOM:WIN98 - Weird splitting on interfaces
- // extends has to stand alone on a line when currentString has been split.
- if (options.maxLineLength != 0 && splitLine != null && (operator == TokenNameextends)) {
- // || operator == TokenNameimplements
- // || operator == TokenNamethrows)) {
- formattedSource.append(options.lineSeparatorSequence);
- increaseSplitDelta(options.lineSeparatorSequence.length);
- dumpTab(depth + 1);
- } else {
- if (operator == TokenNameextends) {
- // || operator == TokenNameimplements
- // || operator == TokenNamethrows) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- }
- // perform actual splitting
- String result[] = splitLine.substrings;
- int[] splitOperators = splitLine.operators;
- if (result[0].length() == 0) {
- // when the substring 0 is null, the substring 1 is correctly indented.
- depth--;
- emptyFirstSubString = true;
- }
- // the operator going in front of the result[0] string is the operator
- // parameter
- for (int i = 0, max = result.length; i < max; i++) {
- // the new depth is the current one if this is the first substring,
- // the current one + 1 otherwise.
- // if the substring is a comment, use the current indentation Level
- // instead of the depth
- // (-1 because the ouputline increases depth).
- // (fix for 1FFC72R: LFCOM:ALL - Incorrect line split in presence of line
- // comments)
- String currentResult = result[i];
- if (currentResult.length() != 0 || splitOperators[i] != 0) {
- int newDepth = (currentResult.startsWith("/*") //$NON-NLS-1$
- || currentResult.startsWith("//")) //$NON-NLS-1$
- ? indentationLevel - 1 : depth;
- outputLine(currentResult, i == 0 || (i == 1 && emptyFirstSubString) ? preIndented : false,
- i == 0 ? newDepth : newDepth + 1, splitOperators[i], i, splitLine.startSubstringsIndexes, currentString
- .indexOf(currentResult));
- if (i != max - 1) {
- formattedSource.append(options.lineSeparatorSequence);
- increaseSplitDelta(options.lineSeparatorSequence.length);
- }
- }
- }
- if (result.length == splitOperators.length - 1) {
- int lastOperator = splitOperators[result.length];
- String lastOperatorString = operatorString(lastOperator);
- formattedSource.append(options.lineSeparatorSequence);
- increaseSplitDelta(options.lineSeparatorSequence.length);
- if (breakLineBeforeOperator(lastOperator)) {
- dumpTab(depth + 1);
- if (lastOperator != 0) {
- if (insertSpaceBefore(lastOperator)) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- formattedSource.append(lastOperatorString);
- increaseSplitDelta(lastOperatorString.length());
- if (insertSpaceAfter(lastOperator) && lastOperator != TokenNameimplements && lastOperator != TokenNameextends) {
- // && lastOperator != TokenNamethrows) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- }
- }
- }
- if (placeOperatorBehind) {
- if (insertSpaceBefore(operator)) {
- formattedSource.append(' ');
- increaseSplitDelta(1);
- }
- formattedSource.append(operatorString);
- //increaseSplitDelta(operatorString.length());
- }
- }
-
- /**
- * Pops the top statement of the stack if it is <code>token</code>
- */
- private int pop(int token) {
- int delta = 0;
- if ((constructionsCount > 0) && (constructions[constructionsCount - 1] == token)) {
- delta--;
- constructionsCount--;
- }
- return delta;
- }
-
- /**
- * Pops the top statement of the stack if it is a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.
- */
- private int popBlock() {
- int delta = 0;
- if ((constructionsCount > 0)
- && ((constructions[constructionsCount - 1] == BLOCK) || (constructions[constructionsCount - 1] == NONINDENT_BLOCK))) {
- if (constructions[constructionsCount - 1] == BLOCK)
- delta--;
- constructionsCount--;
- }
- return delta;
- }
-
- /**
- * Pops elements until the stack is empty or the top element is <code>token</code>.<br>
- * Does not remove <code>token</code> from the stack.
- *
- * @param token
- * the token to be left as the top of the stack
- */
- private int popExclusiveUntil(int token) {
- int delta = 0;
- int startCount = constructionsCount;
- for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
- if (constructions[i] != NONINDENT_BLOCK)
- delta--;
- constructionsCount--;
- }
- return delta;
- }
-
- /**
- * Pops elements until the stack is empty or the top element is a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
- * Does not remove it from the stack.
- */
- private int popExclusiveUntilBlock() {
- int startCount = constructionsCount;
- int delta = 0;
- for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK; i--) {
- constructionsCount--;
- delta--;
- }
- return delta;
- }
-
- /**
- * Pops elements until the stack is empty or the top element is a <code>BLOCK</code>, a <code>NONINDENT_BLOCK</code> or a
- * <code>CASE</code>.<br>
- * Does not remove it from the stack.
- */
- private int popExclusiveUntilBlockOrCase() {
- int startCount = constructionsCount;
- int delta = 0;
- for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK
- && constructions[i] != TokenNamecase; i--) {
- constructionsCount--;
- delta--;
- }
- return delta;
- }
-
- /**
- * Pops elements until the stack is empty or the top element is <code>token</code>.<br>
- * Removes <code>token</code> from the stack too.
- *
- * @param token
- * the token to remove from the stack
- */
- private int popInclusiveUntil(int token) {
- int startCount = constructionsCount;
- int delta = 0;
- for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
- if (constructions[i] != NONINDENT_BLOCK)
- delta--;
- constructionsCount--;
- }
- if (constructionsCount > 0) {
- if (constructions[constructionsCount - 1] != NONINDENT_BLOCK)
- delta--;
- constructionsCount--;
- }
- return delta;
- }
-
- /**
- * Pops elements until the stack is empty or the top element is a <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
- * Does not remove it from the stack.
- */
- private int popInclusiveUntilBlock() {
- int startCount = constructionsCount;
- int delta = 0;
- for (int i = startCount - 1; i >= 0 && (constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK); i--) {
- delta--;
- constructionsCount--;
- }
- if (constructionsCount > 0) {
- if (constructions[constructionsCount - 1] == BLOCK)
- delta--;
- constructionsCount--;
- }
- return delta;
- }
-
- /**
- * Pushes a block in the stack. <br>
- * Pushes a <code>BLOCK</code> if the stack is empty or if the top element is a <code>BLOCK</code>, pushes
- * <code>NONINDENT_BLOCK</code> otherwise. Creates a new bigger array if the current one is full.
- */
- private int pushBlock() {
- int delta = 0;
- if (constructionsCount == constructions.length)
- System.arraycopy(constructions, 0, (constructions = new int[constructionsCount * 2]), 0, constructionsCount);
- if ((constructionsCount == 0) || (constructions[constructionsCount - 1] == BLOCK)
- || (constructions[constructionsCount - 1] == NONINDENT_BLOCK) || (constructions[constructionsCount - 1] == TokenNamecase)) {
- delta++;
- constructions[constructionsCount++] = BLOCK;
- } else {
- constructions[constructionsCount++] = NONINDENT_BLOCK;
- }
- return delta;
- }
-
- /**
- * Pushes <code>token</code>.<br>
- * Creates a new bigger array if the current one is full.
- */
- private int pushControlStatement(int token) {
- if (constructionsCount == constructions.length)
- System.arraycopy(constructions, 0, (constructions = new int[constructionsCount * 2]), 0, constructionsCount);
- constructions[constructionsCount++] = token;
- return 1;
- }
-
- private static boolean separateFirstArgumentOn(int currentToken) {
- //return (currentToken == TokenNameCOMMA || currentToken ==
- // TokenNameSEMICOLON);
- return currentToken != TokenNameif && currentToken != TokenNameLPAREN && currentToken != TokenNameNOT
- && currentToken != TokenNamewhile && currentToken != TokenNamefor && currentToken != TokenNameforeach
- && currentToken != TokenNameswitch;
- }
-
- /**
- * Set the positions to map. The mapped positions should be retrieved using the getMappedPositions() method.
- *
- * @param positions
- * int[]
- * @deprecated Set the positions to map using the format(String, int, int[]) method.
- *
- * @see #getMappedPositions()
- */
- public void setPositionsToMap(int[] positions) {
- positionsToMap = positions;
- lineDelta = 0;
- globalDelta = 0;
- mappedPositions = new int[positions.length];
- }
-
- /**
- * Appends a space character to the current line buffer.
- */
- private void space() {
- currentLineBuffer.append(' ');
- increaseLineDelta(1);
- }
-
- /**
- * Splits <code>stringToSplit</code> on the top level token <br>
- * If there are several identical token at the same level, the string is cut into many pieces.
- *
- * @return an object containing the operator and all the substrings or null if the string cannot be split
- */
- public SplitLine split(String stringToSplit) {
- return split(stringToSplit, 0);
- }
-
- /**
- * Splits <code>stringToSplit</code> on the top level token <br>
- * If there are several identical token at the same level, the string is cut into many pieces.
- *
- * @return an object containing the operator and all the substrings or null if the string cannot be split
- */
- public SplitLine split(String stringToSplit, int offsetInGlobalLine) {
- /*
- * See http://dev.eclipse.org/bugs/show_bug.cgi?id=12540 and http://dev.eclipse.org/bugs/show_bug.cgi?id=14387
- */
- if (stringToSplit.indexOf("//$NON-NLS") != -1) { //$NON-NLS-1$
- return null;
- }
- // split doesn't work correct for PHP
- return null;
- // local variables
- // int currentToken = 0;
- // int splitTokenType = 0;
- // int splitTokenDepth = Integer.MAX_VALUE;
- // int splitTokenPriority = Integer.MAX_VALUE;
- // int[] substringsStartPositions = new int[10];
- // // contains the start position of substrings
- // int[] substringsEndPositions = new int[10];
- // // contains the start position of substrings
- // int substringsCount = 1; // index in the substringsStartPosition array
- // int[] splitOperators = new int[10];
- // // contains the start position of substrings
- // int splitOperatorsCount = 0; // index in the substringsStartPosition array
- // int[] openParenthesisPosition = new int[10];
- // int openParenthesisPositionCount = 0;
- // int position = 0;
- // int lastOpenParenthesisPosition = -1;
- // // used to remember the position of the 1st open parenthesis
- // // needed for a pattern like: A.B(C); we want formatted like A.B( split C);
- // // setup the scanner with a new source
- // int lastCommentStartPosition = -1;
- // // to remember the start position of the last comment
- // int firstTokenOnLine = -1;
- // // to remember the first token of the line
- // int previousToken = -1;
- // // to remember the previous token.
- // splitScanner.setSource(stringToSplit.toCharArray());
- // try {
- // // start the loop
- // while (true) {
- // // takes the next token
- // try {
- // if (currentToken != Scanner.TokenNameWHITESPACE)
- // previousToken = currentToken;
- // currentToken = splitScanner.getNextToken();
- // if (Scanner.DEBUG) {
- // int currentEndPosition = splitScanner.getCurrentTokenEndPosition();
- // int currentStartPosition = splitScanner
- // .getCurrentTokenStartPosition();
- // System.out.print(currentStartPosition + "," + currentEndPosition
- // + ": ");
- // System.out.println(scanner.toStringAction(currentToken));
- // }
- // } catch (InvalidInputException e) {
- // if (!handleInvalidToken(e))
- // throw e;
- // currentToken = 0;
- // // this value is not modify when an exception is raised.
- // }
- // if (currentToken == TokenNameEOF)
- // break;
- // if (firstTokenOnLine == -1) {
- // firstTokenOnLine = currentToken;
- // }
- // switch (currentToken) {
- // case TokenNameRBRACE :
- // case TokenNameRPAREN :
- // if (openParenthesisPositionCount > 0) {
- // if (openParenthesisPositionCount == 1
- // && lastOpenParenthesisPosition < openParenthesisPosition[0]) {
- // lastOpenParenthesisPosition = openParenthesisPosition[0];
- // } else if ((splitTokenDepth == Integer.MAX_VALUE)
- // || (splitTokenDepth > openParenthesisPositionCount && openParenthesisPositionCount == 1)) {
- // splitTokenType = 0;
- // splitTokenDepth = openParenthesisPositionCount;
- // splitTokenPriority = Integer.MAX_VALUE;
- // substringsStartPositions[0] = 0;
- // // better token means the whole line until now is the first
- // // substring
- // substringsCount = 1; // resets the count of substrings
- // substringsEndPositions[0] = openParenthesisPosition[0];
- // // substring ends on operator start
- // position = openParenthesisPosition[0];
- // // the string mustn't be cut before the closing parenthesis but
- // // after the opening one.
- // splitOperatorsCount = 1; // resets the count of split operators
- // splitOperators[0] = 0;
- // }
- // openParenthesisPositionCount--;
- // }
- // break;
- // case TokenNameLBRACE :
- // case TokenNameLPAREN :
- // if (openParenthesisPositionCount == openParenthesisPosition.length) {
- // System
- // .arraycopy(
- // openParenthesisPosition,
- // 0,
- // (openParenthesisPosition = new int[openParenthesisPositionCount * 2]),
- // 0, openParenthesisPositionCount);
- // }
- // openParenthesisPosition[openParenthesisPositionCount++] = splitScanner.currentPosition;
- // if (currentToken == TokenNameLPAREN
- // && previousToken == TokenNameRPAREN) {
- // openParenthesisPosition[openParenthesisPositionCount - 1] = splitScanner.startPosition;
- // }
- // break;
- // case TokenNameSEMICOLON :
- // // ;
- // case TokenNameCOMMA :
- // // ,
- // case TokenNameEQUAL :
- // // =
- // if (openParenthesisPositionCount < splitTokenDepth
- // || (openParenthesisPositionCount == splitTokenDepth && splitTokenPriority > getTokenPriority(currentToken))) {
- // // the current token is better than the one we currently have
- // // (in level or in priority if same level)
- // // reset the substringsCount
- // splitTokenDepth = openParenthesisPositionCount;
- // splitTokenType = currentToken;
- // splitTokenPriority = getTokenPriority(currentToken);
- // substringsStartPositions[0] = 0;
- // // better token means the whole line until now is the first
- // // substring
- // if (separateFirstArgumentOn(firstTokenOnLine)
- // && openParenthesisPositionCount > 0) {
- // substringsCount = 2; // resets the count of substrings
- // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1];
- // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1];
- // substringsEndPositions[1] = splitScanner.startPosition;
- // splitOperatorsCount = 2; // resets the count of split operators
- // splitOperators[0] = 0;
- // splitOperators[1] = currentToken;
- // position = splitScanner.currentPosition;
- // // next substring will start from operator end
- // } else {
- // substringsCount = 1; // resets the count of substrings
- // substringsEndPositions[0] = splitScanner.startPosition;
- // // substring ends on operator start
- // position = splitScanner.currentPosition;
- // // next substring will start from operator end
- // splitOperatorsCount = 1; // resets the count of split operators
- // splitOperators[0] = currentToken;
- // }
- // } else {
- // if ((openParenthesisPositionCount == splitTokenDepth && splitTokenPriority == getTokenPriority(currentToken))
- // && splitTokenType != TokenNameEQUAL
- // && currentToken != TokenNameEQUAL) {
- // // fix for 1FG0BCN: LFCOM:WIN98 - Missing one indentation after
- // // split
- // // take only the 1st = into account.
- // // if another token with the same priority is found,
- // // push the start position of the substring and
- // // push the token into the stack.
- // // create a new array object if the current one is full.
- // if (substringsCount == substringsStartPositions.length) {
- // System
- // .arraycopy(
- // substringsStartPositions,
- // 0,
- // (substringsStartPositions = new int[substringsCount * 2]),
- // 0, substringsCount);
- // System.arraycopy(substringsEndPositions, 0,
- // (substringsEndPositions = new int[substringsCount * 2]),
- // 0, substringsCount);
- // }
- // if (splitOperatorsCount == splitOperators.length) {
- // System.arraycopy(splitOperators, 0,
- // (splitOperators = new int[splitOperatorsCount * 2]), 0,
- // splitOperatorsCount);
- // }
- // substringsStartPositions[substringsCount] = position;
- // substringsEndPositions[substringsCount++] = splitScanner.startPosition;
- // // substring ends on operator start
- // position = splitScanner.currentPosition;
- // // next substring will start from operator end
- // splitOperators[splitOperatorsCount++] = currentToken;
- // }
- // }
- // break;
- // case TokenNameCOLON :
- // // : (15.24)
- // // see 1FK7C5R, we only split on a colon, when it is associated
- // // with a question-mark.
- // // indeed it might appear also behind a case statement, and we do
- // // not to break at this point.
- // if ((splitOperatorsCount == 0)
- // || splitOperators[splitOperatorsCount - 1] != TokenNameQUESTION) {
- // break;
- // }
- // case TokenNameextends :
- // case TokenNameimplements :
- // //case TokenNamethrows :
- // case TokenNameDOT :
- // // .
- // case TokenNameMULTIPLY :
- // // * (15.16.1)
- // case TokenNameDIVIDE :
- // // / (15.16.2)
- // case TokenNameREMAINDER :
- // // % (15.16.3)
- // case TokenNamePLUS :
- // // + (15.17, 15.17.2)
- // case TokenNameMINUS :
- // // - (15.17.2)
- // case TokenNameLEFT_SHIFT :
- // // << (15.18)
- // case TokenNameRIGHT_SHIFT :
- // // >> (15.18)
- // // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
- // case TokenNameLESS :
- // // < (15.19.1)
- // case TokenNameLESS_EQUAL :
- // // <= (15.19.1)
- // case TokenNameGREATER :
- // // > (15.19.1)
- // case TokenNameGREATER_EQUAL :
- // // >= (15.19.1)
- // // case TokenNameinstanceof : // instanceof
- // case TokenNameEQUAL_EQUAL :
- // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
- // case TokenNameEQUAL_EQUAL_EQUAL :
- // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
- // case TokenNameNOT_EQUAL :
- // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
- // case TokenNameNOT_EQUAL_EQUAL :
- // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
- // case TokenNameAND :
- // // & (15.21, 15.21.1, 15.21.2)
- // case TokenNameOR :
- // // | (15.21, 15.21.1, 15.21.2)
- // case TokenNameXOR :
- // // ^ (15.21, 15.21.1, 15.21.2)
- // case TokenNameAND_AND :
- // // && (15.22)
- // case TokenNameOR_OR :
- // // || (15.23)
- // case TokenNameQUESTION :
- // // ? (15.24)
- // case TokenNameMULTIPLY_EQUAL :
- // // *= (15.25.2)
- // case TokenNameDIVIDE_EQUAL :
- // // /= (15.25.2)
- // case TokenNameREMAINDER_EQUAL :
- // // %= (15.25.2)
- // case TokenNamePLUS_EQUAL :
- // // += (15.25.2)
- // case TokenNameMINUS_EQUAL :
- // // -= (15.25.2)
- // case TokenNameLEFT_SHIFT_EQUAL :
- // // <<= (15.25.2)
- // case TokenNameRIGHT_SHIFT_EQUAL :
- // // >>= (15.25.2)
- // // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
- // case TokenNameAND_EQUAL :
- // // &= (15.25.2)
- // case TokenNameXOR_EQUAL :
- // // ^= (15.25.2)
- // case TokenNameOR_EQUAL :
- // // |= (15.25.2)
- // if ((openParenthesisPositionCount < splitTokenDepth || (openParenthesisPositionCount == splitTokenDepth && splitTokenPriority
- // > getTokenPriority(currentToken)))
- // && !((currentToken == TokenNamePLUS || currentToken == TokenNameMINUS) && (previousToken == TokenNameLBRACE
- // || previousToken == TokenNameLBRACKET || splitScanner.startPosition == 0))) {
- // // the current token is better than the one we currently have
- // // (in level or in priority if same level)
- // // reset the substringsCount
- // splitTokenDepth = openParenthesisPositionCount;
- // splitTokenType = currentToken;
- // splitTokenPriority = getTokenPriority(currentToken);
- // substringsStartPositions[0] = 0;
- // // better token means the whole line until now is the first
- // // substring
- // if (separateFirstArgumentOn(firstTokenOnLine)
- // && openParenthesisPositionCount > 0) {
- // substringsCount = 2; // resets the count of substrings
- // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1];
- // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1];
- // substringsEndPositions[1] = splitScanner.startPosition;
- // splitOperatorsCount = 3; // resets the count of split operators
- // splitOperators[0] = 0;
- // splitOperators[1] = 0;
- // splitOperators[2] = currentToken;
- // position = splitScanner.currentPosition;
- // // next substring will start from operator end
- // } else {
- // substringsCount = 1; // resets the count of substrings
- // substringsEndPositions[0] = splitScanner.startPosition;
- // // substring ends on operator start
- // position = splitScanner.currentPosition;
- // // next substring will start from operator end
- // splitOperatorsCount = 2; // resets the count of split operators
- // splitOperators[0] = 0;
- // // nothing for first operand since operator will be inserted in
- // // front of the second operand
- // splitOperators[1] = currentToken;
- // }
- // } else {
- // if (openParenthesisPositionCount == splitTokenDepth
- // && splitTokenPriority == getTokenPriority(currentToken)) {
- // // if another token with the same priority is found,
- // // push the start position of the substring and
- // // push the token into the stack.
- // // create a new array object if the current one is full.
- // if (substringsCount == substringsStartPositions.length) {
- // System
- // .arraycopy(
- // substringsStartPositions,
- // 0,
- // (substringsStartPositions = new int[substringsCount * 2]),
- // 0, substringsCount);
- // System.arraycopy(substringsEndPositions, 0,
- // (substringsEndPositions = new int[substringsCount * 2]),
- // 0, substringsCount);
- // }
- // if (splitOperatorsCount == splitOperators.length) {
- // System.arraycopy(splitOperators, 0,
- // (splitOperators = new int[splitOperatorsCount * 2]), 0,
- // splitOperatorsCount);
- // }
- // substringsStartPositions[substringsCount] = position;
- // substringsEndPositions[substringsCount++] = splitScanner.startPosition;
- // // substring ends on operator start
- // position = splitScanner.currentPosition;
- // // next substring will start from operator end
- // splitOperators[splitOperatorsCount++] = currentToken;
- // }
- // }
- // default :
- // break;
- // }
- // if (isComment(currentToken)) {
- // lastCommentStartPosition = splitScanner.startPosition;
- // } else {
- // lastCommentStartPosition = -1;
- // }
- // }
- // } catch (InvalidInputException e) {
- // return null;
- // }
- // // if the string cannot be split, return null.
- // if (splitOperatorsCount == 0)
- // return null;
- // // ## SPECIAL CASES BEGIN
- // if (((splitOperatorsCount == 2 && splitOperators[1] == TokenNameDOT
- // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1)
- // || (splitOperatorsCount > 2 && splitOperators[1] == TokenNameDOT
- // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1 && lastOpenParenthesisPosition <= options.maxLineLength) ||
- // (separateFirstArgumentOn(firstTokenOnLine)
- // && splitTokenDepth > 0 && lastOpenParenthesisPosition > -1))
- // && (lastOpenParenthesisPosition < splitScanner.source.length && splitScanner.source[lastOpenParenthesisPosition] != ')')) {
- // // fix for 1FH4J2H: LFCOM:WINNT - Formatter - Empty parenthesis should
- // // not be broken on two lines
- // // only one split on a top level .
- // // or more than one split on . and substring before open parenthesis fits
- // // one line.
- // // or split inside parenthesis and first token is not a for/while/if
- // SplitLine sl = split(
- // stringToSplit.substring(lastOpenParenthesisPosition),
- // lastOpenParenthesisPosition);
- // if (sl == null || sl.operators[0] != TokenNameCOMMA) {
- // // trim() is used to remove the extra blanks at the end of the
- // // substring. See PR 1FGYPI1
- // return new SplitLine(new int[]{0, 0}, new String[]{
- // stringToSplit.substring(0, lastOpenParenthesisPosition).trim(),
- // stringToSplit.substring(lastOpenParenthesisPosition)}, new int[]{
- // offsetInGlobalLine,
- // lastOpenParenthesisPosition + offsetInGlobalLine});
- // } else {
- // // right substring can be split and is split on comma
- // // copy substrings and operators
- // // except if the 1st string is empty.
- // int startIndex = (sl.substrings[0].length() == 0) ? 1 : 0;
- // int subStringsLength = sl.substrings.length + 1 - startIndex;
- // String[] result = new String[subStringsLength];
- // int[] startIndexes = new int[subStringsLength];
- // int operatorsLength = sl.operators.length + 1 - startIndex;
- // int[] operators = new int[operatorsLength];
- // result[0] = stringToSplit.substring(0, lastOpenParenthesisPosition);
- // operators[0] = 0;
- // System.arraycopy(sl.startSubstringsIndexes, startIndex, startIndexes,
- // 1, subStringsLength - 1);
- // for (int i = subStringsLength - 1; i >= 0; i--) {
- // startIndexes[i] += offsetInGlobalLine;
- // }
- // System.arraycopy(sl.substrings, startIndex, result, 1,
- // subStringsLength - 1);
- // System.arraycopy(sl.operators, startIndex, operators, 1,
- // operatorsLength - 1);
- // return new SplitLine(operators, result, startIndexes);
- // }
- // }
- // // if the last token is a comment and the substring before the comment fits
- // // on a line,
- // // split before the comment and return the result.
- // if (lastCommentStartPosition > -1
- // && lastCommentStartPosition < options.maxLineLength
- // && splitTokenPriority > 50) {
- // int end = lastCommentStartPosition;
- // int start = lastCommentStartPosition;
- // if (stringToSplit.charAt(end - 1) == ' ') {
- // end--;
- // }
- // if (start != end && stringToSplit.charAt(start) == ' ') {
- // start++;
- // }
- // return new SplitLine(new int[]{0, 0}, new String[]{
- // stringToSplit.substring(0, end), stringToSplit.substring(start)},
- // new int[]{0, start});
- // }
- // if (position != stringToSplit.length()) {
- // if (substringsCount == substringsStartPositions.length) {
- // System.arraycopy(substringsStartPositions, 0,
- // (substringsStartPositions = new int[substringsCount * 2]), 0,
- // substringsCount);
- // System.arraycopy(substringsEndPositions, 0,
- // (substringsEndPositions = new int[substringsCount * 2]), 0,
- // substringsCount);
- // }
- // // avoid empty extra substring, e.g. line terminated with a semi-colon
- // substringsStartPositions[substringsCount] = position;
- // substringsEndPositions[substringsCount++] = stringToSplit.length();
- // }
- // if (splitOperatorsCount == splitOperators.length) {
- // System.arraycopy(splitOperators, 0,
- // (splitOperators = new int[splitOperatorsCount * 2]), 0,
- // splitOperatorsCount);
- // }
- // splitOperators[splitOperatorsCount] = 0;
- // // the last element of the stack is the position of the end of
- // // StringToSPlit
- // // +1 because the substring method excludes the last character
- // String[] result = new String[substringsCount];
- // for (int i = 0; i < substringsCount; i++) {
- // int start = substringsStartPositions[i];
- // int end = substringsEndPositions[i];
- // if (stringToSplit.charAt(start) == ' ') {
- // start++;
- // substringsStartPositions[i]++;
- // }
- // if (end != start && stringToSplit.charAt(end - 1) == ' ') {
- // end--;
- // }
- // result[i] = stringToSplit.substring(start, end);
- // substringsStartPositions[i] += offsetInGlobalLine;
- // }
- // if (splitOperatorsCount > substringsCount) {
- // System.arraycopy(substringsStartPositions, 0,
- // (substringsStartPositions = new int[splitOperatorsCount]), 0,
- // substringsCount);
- // System.arraycopy(substringsEndPositions, 0,
- // (substringsEndPositions = new int[splitOperatorsCount]), 0,
- // substringsCount);
- // for (int i = substringsCount; i < splitOperatorsCount; i++) {
- // substringsStartPositions[i] = position;
- // substringsEndPositions[i] = position;
- // }
- // System.arraycopy(splitOperators, 0,
- // (splitOperators = new int[splitOperatorsCount]), 0,
- // splitOperatorsCount);
- // } else {
- // System.arraycopy(substringsStartPositions, 0,
- // (substringsStartPositions = new int[substringsCount]), 0,
- // substringsCount);
- // System.arraycopy(substringsEndPositions, 0,
- // (substringsEndPositions = new int[substringsCount]), 0,
- // substringsCount);
- // System.arraycopy(splitOperators, 0,
- // (splitOperators = new int[substringsCount]), 0, substringsCount);
- // }
- // SplitLine splitLine = new SplitLine(splitOperators, result,
- // substringsStartPositions);
- // return splitLine;
- }
-
- private void updateMappedPositions(int startPosition) {
- if (positionsToMap == null) {
- return;
- }
- char[] source = scanner.source;
- int sourceLength = source.length;
- while (indexToMap < positionsToMap.length && positionsToMap[indexToMap] <= startPosition) {
- int posToMap = positionsToMap[indexToMap];
- if (posToMap < 0 || posToMap >= sourceLength) {
- // protection against out of bounds position
- if (posToMap == sourceLength) {
- mappedPositions[indexToMap] = formattedSource.length()-1;
- }
- indexToMap = positionsToMap.length; // no more mapping
- return;
- }
- if (CharOperation.isWhitespace(source[posToMap])) {
- mappedPositions[indexToMap] = startPosition + globalDelta + lineDelta;
- } else {
- if (posToMap == sourceLength - 1) {
- mappedPositions[indexToMap] = startPosition + globalDelta + lineDelta;
- } else {
- mappedPositions[indexToMap] = posToMap + globalDelta + lineDelta;
- }
- if (mappedPositions[indexToMap]>=formattedSource.length()) {
- mappedPositions[indexToMap]=formattedSource.length()-1;
- }
- }
- indexToMap++;
- }
- }
-
- private void updateMappedPositionsWhileSplitting(int startPosition, int endPosition) {
- if (mappedPositions == null || mappedPositions.length == indexInMap)
- return;
- while (indexInMap < mappedPositions.length && startPosition <= mappedPositions[indexInMap]
- && mappedPositions[indexInMap] < endPosition && indexInMap < indexToMap) {
- mappedPositions[indexInMap] += splitDelta;
- if (mappedPositions[indexInMap]>=formattedSource.length()) {
- mappedPositions[indexInMap]=formattedSource.length()-1;
- }
- indexInMap++;
- }
- }
-
- private int getLength(String s, int tabDepth) {
- int length = 0;
- for (int i = 0; i < tabDepth; i++) {
- length += options.tabSize;
- }
- for (int i = 0, max = s.length(); i < max; i++) {
- char currentChar = s.charAt(i);
- switch (currentChar) {
- case '\t':
- length += options.tabSize;
- break;
- default:
- length++;
- }
- }
- return length;
- }
-
- /**
- * Sets the initial indentation level
- *
- * @param indentationLevel
- * new indentation level
- *
- * @deprecated
- */
- public void setInitialIndentationLevel(int newIndentationLevel) {
- this.initialIndentationLevel = currentLineIndentationLevel = indentationLevel = newIndentationLevel;
- }
+ /**
+ * Represents a block in the <code>constructions</code> stack.
+ */
+ public static final TokenName BLOCK = TokenName.LBRACE;
+
+ /**
+ * Represents a block following a control statement in the
+ * <code>constructions</code> stack.
+ */
+ public static final TokenName NONINDENT_BLOCK = TokenName.NONE_INDENT_BLOCK;
+
+ /**
+ * Contains the formatted output.
+ */
+ StringBuffer formattedSource;
+
+ /**
+ * Contains the current line. <br>
+ * Will be dumped at the next "newline"
+ */
+ StringBuffer currentLineBuffer;
+
+ /**
+ * Used during the formatting to get each token.
+ */
+ Scanner scanner;
+
+ /**
+ * Contains the tokens responsible for the current indentation level and the
+ * blocks not closed yet.
+ */
+ private TokenName[] constructions;
+
+ /**
+ * Index in the <code>constructions</code> array.
+ */
+ private int constructionsCount;
+
+ /**
+ * Level of indentation of the current token (number of tab char put in
+ * front of it).
+ */
+ private int indentationLevel;
+
+ /**
+ * Regular level of indentation of all the lines
+ */
+ private int initialIndentationLevel;
+
+ /**
+ * Used to split a line.
+ */
+ Scanner splitScanner;
+
+ /**
+ * To remember the offset between the beginning of the line and the
+ * beginning of the comment.
+ */
+ int currentCommentOffset;
+
+ int currentLineIndentationLevel;
+
+ int maxLineSize = 30;
+
+ private boolean containsOpenCloseBraces;
+
+ private int indentationLevelForOpenCloseBraces;
+
+ /**
+ * Collections of positions to map
+ */
+ private int[] positionsToMap;
+
+ /**
+ * Collections of mapped positions
+ */
+ private int[] mappedPositions;
+
+ private int indexToMap;
+
+ private int indexInMap;
+
+ private int globalDelta;
+
+ private int lineDelta;
+
+ private int splitDelta;
+
+ private int beginningOfLineIndex;
+
+ private int multipleLineCommentCounter;
+
+ /**
+ * Creates a new instance of Code Formatter using the given settings.
+ *
+ * @deprecated backport 1.0 internal functionality
+ */
+ public CodeFormatter(ConfigurableOption[] settings) {
+ this(convertConfigurableOptions(settings));
+ }
+
+ /**
+ * Creates a new instance of Code Formatter using the FormattingOptions
+ * object given as argument
+ *
+ * @deprecated Use CodeFormatter(ConfigurableOption[]) instead
+ */
+// public CodeFormatter() {
+// this((Map) null);
+// }
+
+ /**
+ * Creates a new instance of Code Formatter using the given settings.
+ */
+ public CodeFormatter(Map settings) {
+ // initialize internal state
+ constructionsCount = 0;
+ constructions = new TokenName[10];
+ currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
+ currentCommentOffset = -1;
+ // initialize primary and secondary scanners
+ scanner = new Scanner(true /* comment */
+ , true /* whitespace */
+ , false /* nls */
+ , false /* assert */
+ , true, /* tokenizeStrings */
+ null, null, true /* taskCaseSensitive */); // regular scanner for
+ // forming lines
+ scanner.recordLineSeparator = true;
+ scanner.ignorePHPOneLiner = true;
+ // to remind of the position of the beginning of the line.
+ splitScanner = new Scanner(true /* comment */
+ , true /* whitespace */
+ , false /* nls */
+ , false /* assert */
+ , true, /* tokenizeStrings */
+ null, null, true /* taskCaseSensitive */);
+ splitScanner.ignorePHPOneLiner = true;
+ // secondary scanner to split long lines formed by primary scanning
+ // initialize current line buffer
+ currentLineBuffer = new StringBuffer();
+ this.options = new FormatterOptions(settings);
+ }
+
+ /**
+ * Returns true if a lineSeparator has to be inserted before
+ * <code>operator</code> false otherwise.
+ */
+ private static boolean breakLineBeforeOperator(TokenName operator) {
+ switch (operator) {
+ case COMMA:
+ case SEMICOLON:
+ case EQUAL:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * @deprecated backport 1.0 internal functionality
+ */
+ private static Map convertConfigurableOptions(ConfigurableOption[] settings) {
+ Hashtable options = new Hashtable(10);
+ for (int i = 0; i < settings.length; i++) {
+ if (settings[i].getComponentName().equals(
+ CodeFormatter.class.getName())) {
+ String optionName = settings[i].getOptionName();
+ int valueIndex = settings[i].getCurrentValueIndex();
+ if (optionName.equals("newline.openingBrace")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ } else if (optionName.equals("newline.controlStatement")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.newline.controlStatement", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ } else if (optionName.equals("newline.clearAll")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.newline.clearAll", valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ } else if (optionName.equals("newline.elseIf")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.newline.elseIf", valueIndex == 0 ? "do not insert" : "insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ } else if (optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.newline.emptyBlock", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ } else if (optionName.equals("lineSplit")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
+ } else if (optionName.equals("style.assignment")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.style.assignment", valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ } else if (optionName.equals("tabulation.char")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.tabulation.char", valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ } else if (optionName.equals("tabulation.size")) { //$NON-NLS-1$
+ options
+ .put(
+ "net.sourceforge.phpdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ return options;
+ }
+
+ /**
+ * Returns the end of the source code.
+ */
+ private final String copyRemainingSource() {
+ char str[] = scanner.source;
+ int startPosition = scanner.startPosition;
+ int length = str.length - startPosition;
+ StringBuffer bufr = new StringBuffer(length);
+ if (startPosition < str.length) {
+ bufr.append(str, startPosition, length);
+ }
+ return (bufr.toString());
+ }
+
+ /**
+ * Inserts <code>tabCount</code> tab character or their equivalent number
+ * of spaces.
+ */
+ private void dumpTab(int tabCount) {
+ if (options.indentWithTab) {
+ for (int j = 0; j < tabCount; j++) {
+ formattedSource.append('\t');
+ increaseSplitDelta(1);
+ }
+ } else {
+ for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+ }
+
+ /**
+ * Dumps <code>currentLineBuffer</code> into the formatted string.
+ */
+ private void flushBuffer() {
+ String currentString = currentLineBuffer.toString();
+ splitDelta = 0;
+ beginningOfLineIndex = formattedSource.length();
+ if (containsOpenCloseBraces) {
+ containsOpenCloseBraces = false;
+ outputLine(currentString,
+ false,
+ indentationLevelForOpenCloseBraces,
+ TokenName.NONE,
+ -1, null, 0);
+ indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+ } else {
+ outputLine(currentString,
+ false,
+ currentLineIndentationLevel,
+ TokenName.NONE,
+ -1, null, 0);
+ }
+ int scannerSourceLength = scanner.source.length;
+ if ((scannerSourceLength > 2)
+ && (scanner.startPosition < scannerSourceLength)) {
+ if (scanner.source[scannerSourceLength - 1] == '\n'
+ && scanner.source[scannerSourceLength - 2] == '\r') {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
+ } else if (scanner.source[scannerSourceLength - 1] == '\n') {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+ } else if (scanner.source[scannerSourceLength - 1] == '\r') {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+ }
+ }
+ updateMappedPositions(scanner.startPosition);
+ }
+
+ /**
+ * Formats the input string.
+ */
+ private void format() {
+ TokenName token = TokenName.NONE;
+ TokenName previousToken = TokenName.NONE;
+ TokenName previousCompilableToken = TokenName.NONE;
+
+ int indentationOffset = 0;
+ int newLinesInWhitespace = 0;
+ // number of new lines in the previous whitespace token
+ // (used to leave blank lines before comments)
+ int pendingNewLines = 0;
+ boolean expectingOpenBrace = false;
+ boolean clearNonBlockIndents = false;
+ // true if all indentations till the 1st { (usefull after } or ;)
+ boolean pendingSpace = true;
+ boolean pendingNewlineAfterParen = false;
+ // true when a cr is to be put after a ) (in conditional statements)
+ boolean inAssignment = false;
+ boolean inArrayAssignment = false;
+ boolean inThrowsClause = false;
+ boolean inClassOrInterfaceHeader = false;
+ int dollarBraceCount = 0;
+ // openBracketCount is used to count the number of open brackets not
+ // closed
+ // yet.
+ int openBracketCount = 0;
+ int unarySignModifier = 0;
+ // openParenthesis[0] is used to count the parenthesis not belonging to
+ // a
+ // condition
+ // (eg foo();). parenthesis in for (...) are count elsewhere in the
+ // array.
+ int openParenthesisCount = 1;
+ int[] openParenthesis = new int[10];
+ // tokenBeforeColon is used to know what token goes along with the
+ // current
+ // :
+ // it can be case or ?
+ int tokenBeforeColonCount = 0;
+ TokenName[] tokenBeforeColon = new TokenName[10];
+ constructionsCount = 0; // initializes the constructions count.
+ // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
+ TokenName nlicsToken = ITerminalSymbols.TokenName.NONE;
+ // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and
+ // else
+ boolean specialElse = false;
+ // OPTION (IndentationLevel): initial indentation level may be non-zero.
+ currentLineIndentationLevel += constructionsCount;
+ // An InvalidInputException exception might cause the termination of
+ // this
+ // loop.
+ int arrayDeclarationCount = 0;
+ int[] arrayDeclarationParenthesis = new int[10];
+ try {
+ while (true) {
+ // Get the next token. Catch invalid input and output it
+ // with minimal formatting, also catch end of input and
+ // exit the loop.
+ try {
+ token = scanner.getNextToken();
+ if (Scanner.DEBUG) {
+ int currentEndPosition = scanner
+ .getCurrentTokenEndPosition();
+ int currentStartPosition = scanner
+ .getCurrentTokenStartPosition();
+ System.out.print(currentStartPosition + ","
+ + currentEndPosition + ": ");
+ System.out.println(scanner.toStringAction(token));
+ }
+ // Patch for line comment
+ // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=23096
+ if (token == ITerminalSymbols.TokenName.COMMENT_LINE) {
+ int length = scanner.currentPosition;
+ loop: for (int index = length - 1; index >= 0; index--) {
+ switch (scanner.source[index]) {
+ case '\r':
+ case '\n':
+ scanner.currentPosition--;
+ break;
+ default:
+ break loop;
+ }
+ }
+ }
+ } catch (InvalidInputException e) {
+ if (!handleInvalidToken(e)) {
+ throw e;
+ }
+ token = ITerminalSymbols.TokenName.NONE;
+ }
+ if (token == Scanner.TokenName.EOF) {
+ break;
+ } else if (token == Scanner.TokenName.HEREDOC) {
+ // no indentation for heredocs and HTML !
+ outputCurrentTokenWithoutIndent(Scanner.TokenName.HEREDOC, 0);
+ continue;
+ } else if (token == Scanner.TokenName.INLINE_HTML) {
+ // no indentation for heredocs and HTML !
+ int newLineCount = 1;
+ if (scanner.startPosition == 0) {
+ newLineCount = 0;
+ }
+ outputCurrentTokenWithoutIndent(
+ Scanner.TokenName.INLINE_HTML, newLineCount);
+ int srcLen = scanner.source.length;
+ if (scanner.currentPosition < srcLen - 1) {
+ newLine(1);
+ }
+ continue;
+ }
+ /*
+ * ## MODIFYING the indentation level before generating new
+ * lines and indentation in the output string
+ */
+ // Removes all the indentations made by statements not followed
+ // by a
+ // block
+ // except if the current token is ELSE, CATCH or if we are in a
+ // switch/case
+ if (clearNonBlockIndents
+ && (token != Scanner.TokenName.WHITESPACE)) {
+ switch (token) {
+ case ELSE:
+ if (constructionsCount > 0
+ && constructions[constructionsCount - 1] == TokenName.ELSE) {
+ pendingNewLines = 1;
+ specialElse = true;
+ }
+ indentationLevel += popInclusiveUntil(TokenName.IF);
+ break;
+ // case TokenName.catch :
+ // indentationLevel += popInclusiveUntil(TokenName.catch);
+ // break;
+ // case TokenName.finally :
+ // indentationLevel += popInclusiveUntil(TokenName.catch);
+ // break;
+ case WHILE:
+ if (nlicsToken == TokenName.DO) {
+ indentationLevel += pop(TokenName.DO);
+ break;
+ }
+ default:
+ indentationLevel += popExclusiveUntilBlockOrCase();
+ // clear until a CASE, DEFAULT or BLOCK is encountered.
+ // Thus, the indentationLevel is correctly cleared
+ // either
+ // in a switch/case statement or in any other situation.
+ }
+ clearNonBlockIndents = false;
+ }
+ // returns to the indentation level created by the SWITCH
+ // keyword
+ // if the current token is a CASE or a DEFAULT
+ if (token == TokenName.CASE || token == TokenName.DEFAULT) {
+ indentationLevel += pop(TokenName.CASE);
+ }
+ // if (token == Scanner.TokenName.throws) {
+ // inThrowsClause = true;
+ // }
+ if ((token == Scanner.TokenName.CLASS || token == Scanner.TokenName.INTERFACE)
+ && previousToken != Scanner.TokenName.DOT) {
+ inClassOrInterfaceHeader = true;
+ }
+ /*
+ * ## APPEND newlines and indentations to the output string
+ */
+ // Do not add a new line between ELSE and IF, if the option
+ // elseIfOnSameLine is true.
+ // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
+ // if (pendingNewlineAfterParen
+ // && previousCompilableToken == TokenName.else
+ // && token == TokenName.if
+ // && options.compactElseIfMode) {
+ // pendingNewlineAfterParen = false;
+ // pendingNewLines = 0;
+ // indentationLevel += pop(TokenName.else);
+ // // because else if is now one single statement,
+ // // the indentation level after it is increased by one and not
+ // by 2
+ // // (else = 1 indent, if = 1 indent, but else if = 1 indent,
+ // not 2).
+ // }
+ // Add a newline & indent to the formatted source string if
+ // a for/if-else/while statement was scanned and there is no
+ // block
+ // following it.
+ pendingNewlineAfterParen = pendingNewlineAfterParen
+ || (previousCompilableToken == TokenName.RPAREN && token == TokenName.LBRACE);
+ if (pendingNewlineAfterParen
+ && token != Scanner.TokenName.WHITESPACE) {
+ pendingNewlineAfterParen = false;
+ // Do to add a newline & indent sequence if the current
+ // token is an
+ // open brace or a period or if the current token is a
+ // semi-colon and
+ // the
+ // previous token is a close paren.
+ // add a new line if a parenthesis belonging to a for()
+ // statement
+ // has been closed and the current token is not an opening
+ // brace
+ if (token != TokenName.LBRACE && !isComment(token)
+ // to avoid adding new line between else and a
+ // comment
+ && token != TokenName.DOT
+ && !(previousCompilableToken == TokenName.RPAREN && token == TokenName.SEMICOLON)) {
+ newLine(1);
+ currentLineIndentationLevel = indentationLevel;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ } else {
+ if (token == TokenName.LBRACE
+ && options.newLineBeforeOpeningBraceMode) {
+ newLine(1);
+ if (constructionsCount > 0
+ && constructions[constructionsCount - 1] != BLOCK
+ && constructions[constructionsCount - 1] != NONINDENT_BLOCK) {
+ currentLineIndentationLevel = indentationLevel - 1;
+ } else {
+ currentLineIndentationLevel = indentationLevel;
+ }
+ pendingNewLines = 0;
+ pendingSpace = false;
+ }
+ }
+ }
+ if (token == TokenName.LBRACE
+ && options.newLineBeforeOpeningBraceMode
+ && constructionsCount > 0
+ && constructions[constructionsCount - 1] == TokenName.DO) {
+ newLine(1);
+ currentLineIndentationLevel = indentationLevel - 1;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ }
+ // see PR 1G5G8EC
+ if (token == TokenName.LBRACE && inThrowsClause) {
+ inThrowsClause = false;
+ if (options.newLineBeforeOpeningBraceMode) {
+ newLine(1);
+ currentLineIndentationLevel = indentationLevel;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ }
+ }
+ // see PR 1G5G82G
+ if (token == TokenName.LBRACE && inClassOrInterfaceHeader) {
+ inClassOrInterfaceHeader = false;
+ if (options.newLineBeforeOpeningBraceMode) {
+ newLine(1);
+ currentLineIndentationLevel = indentationLevel;
+ pendingNewLines = 0;
+ pendingSpace = false;
+ }
+ }
+ // don't linebreak empty array declarations
+ if (token == TokenName.RPAREN && arrayDeclarationCount > 0) {
+ if (previousCompilableToken == TokenName.LPAREN) {
+ pendingNewLines = 0;
+ }
+ }
+ // Add pending new lines to the formatted source string.
+ // Note: pending new lines are not added if the current token
+ // is a single line comment or whitespace.
+ // if the comment is between parenthesis, there is no blank line
+ // preservation
+ // (if it's a one-line comment, a blank line is added after it).
+ if (((pendingNewLines > 0 && (!isComment(token)))
+ || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token)))
+ || (previousCompilableToken == TokenName.LBRACE && token == TokenName.RBRACE) || (newLinesInWhitespace > 0 && previousCompilableToken == TokenName.DOT))
+ && token != Scanner.TokenName.WHITESPACE) {
+ // Do not add newline & indent between an adjoining close
+ // brace and
+ // close paren. Anonymous inner classes may use this form.
+ boolean closeBraceAndCloseParen = previousToken == TokenName.RBRACE
+ && token == TokenName.RPAREN;
+ // OPTION (NewLineInCompoundStatement): do not add newline &
+ // indent
+ // between close brace and else, (do) while, catch, and
+ // finally if
+ // newlineInCompoundStatement is true.
+ boolean nlicsOption = previousToken == TokenName.RBRACE
+ && !options.newlineInControlStatementMode
+ && (token == TokenName.ELSE
+ || (token == TokenName.WHILE && nlicsToken == TokenName.DO)
+ || token == TokenName.CATCH || token == TokenName.FINALLY);
+ // Do not add a newline & indent between a close brace and
+ // semi-colon.
+ boolean semiColonAndCloseBrace = previousToken == TokenName.RBRACE
+ && token == TokenName.SEMICOLON;
+ // Do not add a new line & indent between a multiline
+ // comment and a
+ // opening brace
+ boolean commentAndOpenBrace = previousToken == Scanner.TokenName.COMMENT_BLOCK
+ && token == TokenName.LBRACE;
+ // Do not add a newline & indent between a close brace and a
+ // colon
+ // (in array assignments, for example).
+ boolean commaAndCloseBrace = previousToken == TokenName.RBRACE
+ && token == TokenName.COMMA;
+ // Add a newline and indent, if appropriate.
+ if (specialElse
+ || (!commentAndOpenBrace
+ && !closeBraceAndCloseParen && !nlicsOption
+ && !semiColonAndCloseBrace && !commaAndCloseBrace)) {
+ // if clearAllBlankLinesMode=false, leaves the blank
+ // lines
+ // inserted by the user
+ // if clearAllBlankLinesMode=true, removes all of then
+ // and insert only blank lines required by the
+ // formatting.
+ if (!options.clearAllBlankLinesMode) {
+ // (isComment(token))
+ pendingNewLines = (pendingNewLines < newLinesInWhitespace) ? newLinesInWhitespace
+ : pendingNewLines;
+ pendingNewLines = (pendingNewLines > 2) ? 2
+ : pendingNewLines;
+ }
+ if (previousCompilableToken == TokenName.LBRACE
+ && token == TokenName.RBRACE) {
+ containsOpenCloseBraces = true;
+ indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+ if (isComment(previousToken)) {
+ newLine(pendingNewLines);
+ } else {
+ /*
+ * if (!(constructionsCount > 1 &&
+ * constructions[constructionsCount-1] ==
+ * NONINDENT_BLOCK &&
+ * (constructions[constructionsCount-2] ==
+ * TokenName.for
+ */
+ if (options.newLineInEmptyBlockMode) {
+ if (inArrayAssignment) {
+ newLine(1); // array assigment with an
+ // empty block
+ } else {
+ newLine(pendingNewLines);
+ }
+ }
+ // }
+ }
+ } else {
+ // see PR 1FKKC3U: LFCOM:WINNT - Format problem with
+ // a comment
+ // before the ';'
+ if (!((previousToken == Scanner.TokenName.COMMENT_BLOCK || previousToken == Scanner.TokenName.COMMENT_PHPDOC) && token == TokenName.SEMICOLON)) {
+ newLine(pendingNewLines);
+ }
+ }
+ if (((previousCompilableToken == TokenName.SEMICOLON)
+ || (previousCompilableToken == TokenName.LBRACE)
+ || (previousCompilableToken == TokenName.RBRACE) || (isComment(previousToken)))
+ && (token == TokenName.RBRACE)) {
+ indentationOffset = -1;
+ indentationLevel += popExclusiveUntilBlock();
+ }
+ if (previousToken == Scanner.TokenName.COMMENT_LINE
+ && inAssignment) {
+ // PR 1FI5IPO
+ currentLineIndentationLevel++;
+ } else {
+ currentLineIndentationLevel = indentationLevel
+ + indentationOffset;
+ }
+ pendingSpace = false;
+ indentationOffset = 0;
+ }
+ pendingNewLines = 0;
+ newLinesInWhitespace = 0;
+ specialElse = false;
+ if (nlicsToken == TokenName.DO && token == TokenName.WHILE) {
+ nlicsToken = ITerminalSymbols.TokenName.NONE;
+ }
+ }
+ boolean phpTagAndWhitespace = previousToken == TokenName.INLINE_HTML
+ && token == TokenName.WHITESPACE;
+ switch (token) {
+ // case TokenName.DOLLAR :
+ // dollarBraceCount++;
+ // break;
+ case ELSE:
+ // case TokenName.finally :
+ expectingOpenBrace = true;
+ pendingNewlineAfterParen = true;
+ indentationLevel += pushControlStatement(token);
+ break;
+ case CASE:
+ case DEFAULT:
+ if (tokenBeforeColonCount == tokenBeforeColon.length) {
+ System
+ .arraycopy(
+ tokenBeforeColon,
+ 0,
+ (tokenBeforeColon = new TokenName[tokenBeforeColonCount * 2]),
+ 0, tokenBeforeColonCount);
+ }
+ tokenBeforeColon[tokenBeforeColonCount++] = TokenName.CASE;
+ indentationLevel += pushControlStatement(TokenName.CASE);
+ break;
+ case QUESTION:
+ if (tokenBeforeColonCount == tokenBeforeColon.length) {
+ System
+ .arraycopy(
+ tokenBeforeColon,
+ 0,
+ (tokenBeforeColon = new TokenName[tokenBeforeColonCount * 2]),
+ 0, tokenBeforeColonCount);
+ }
+ tokenBeforeColon[tokenBeforeColonCount++] = token;
+ break;
+ case SWITCH:
+ case FOR:
+ case FOREACH:
+ case IF:
+ case WHILE:
+ if (openParenthesisCount == openParenthesis.length) {
+ System
+ .arraycopy(
+ openParenthesis,
+ 0,
+ (openParenthesis = new int[openParenthesisCount * 2]),
+ 0, openParenthesisCount);
+ }
+ openParenthesis[openParenthesisCount++] = 0;
+ expectingOpenBrace = true;
+ indentationLevel += pushControlStatement(token);
+ break;
+ case TRY:
+ pendingNewlineAfterParen = true;
+ case CATCH:
+ // several CATCH statements can be contiguous.
+ // a CATCH is encountered pop until first CATCH (if a CATCH
+ // follows a TRY it works the same way,
+ // as CATCH and TRY are the same token in the stack).
+ expectingOpenBrace = true;
+ indentationLevel += pushControlStatement(TokenName.CATCH);
+ break;
+ case DO:
+ expectingOpenBrace = true;
+ indentationLevel += pushControlStatement(token);
+ nlicsToken = token;
+ break;
+ case NEW:
+ break;
+ case LPAREN:
+ // if (previousToken == TokenName.synchronized) {
+ // indentationLevel += pushControlStatement(previousToken);
+ // } else {
+ // Put a space between the previous and current token if the
+ // previous token was not a keyword, open paren, logical
+ // compliment (eg: !), semi-colon, open brace, close brace,
+ // super, or this.
+ if (previousCompilableToken != TokenName.LBRACKET
+ && previousToken != TokenName.IDENTIFIER
+ && previousToken != TokenName.NONE
+ && previousToken != TokenName.NOT
+ && previousToken != TokenName.LPAREN
+ && previousToken != TokenName.TWIDDLE
+ && previousToken != TokenName.SEMICOLON
+ && previousToken != TokenName.LBRACE
+ && previousToken != TokenName.RBRACE
+ && previousToken != TokenName.SUPER) {
+ // && previousToken != TokenName.THIS) {
+ if (!options.compactArrays) {
+ space();
+ }
+ }
+ // If in a for/if/while statement, increase the parenthesis
+ // count
+ // for the current openParenthesisCount
+ // else increase the count for stand alone parenthesis.
+ if (openParenthesisCount > 0)
+ openParenthesis[openParenthesisCount - 1]++;
+ else
+ openParenthesis[0]++;
+ pendingSpace = false;
+ // recognize array declaration for nice output
+ if (previousCompilableToken == TokenName.ARRAY) {
+ arrayDeclarationCount++;
+ arrayDeclarationParenthesis[arrayDeclarationCount] = openParenthesis[openParenthesisCount - 1];
+ if (!options.compactArrays) {
+ indentationLevel++;
+ pendingNewLines = 1;
+ }
+ }
+ // S }
+ break;
+ case RPAREN:
+ // check for closing array declaration
+ if (arrayDeclarationCount > 0) {
+ if (arrayDeclarationParenthesis[arrayDeclarationCount] == openParenthesis[openParenthesisCount - 1]) {
+ if (previousCompilableToken != TokenName.LPAREN) {
+ if (!options.compactArrays) {
+ newLine(1);
+ }
+ } else if (previousToken == TokenName.COMMENT_LINE
+ || previousToken == TokenName.COMMENT_BLOCK
+ || previousToken == TokenName.COMMENT_PHPDOC) {
+ // prevent to combine comment line and statement line (#1475484)
+ if (!options.compactArrays) {
+ newLine(1);
+ }
+ }
+ if (!options.compactArrays) {
+ indentationLevel--;
+
+ }
+ currentLineIndentationLevel = indentationLevel;
+ pendingNewLines = 0;
+ arrayDeclarationCount--;
+ }
+ }
+ // Decrease the parenthesis count
+ // if there is no more unclosed parenthesis,
+ // a new line and indent may be append (depending on the
+ // next
+ // token).
+ if ((openParenthesisCount > 1)
+ && (openParenthesis[openParenthesisCount - 1] > 0)) {
+ openParenthesis[openParenthesisCount - 1]--;
+ if (openParenthesis[openParenthesisCount - 1] <= 0) {
+ pendingNewlineAfterParen = true;
+ inAssignment = false;
+ openParenthesisCount--;
+ }
+ } else {
+ openParenthesis[0]--;
+ }
+ pendingSpace = false;
+ break;
+ case LBRACE:
+ if (previousCompilableToken == TokenName.DOLLAR) {
+ dollarBraceCount++;
+ } else {
+ if ((previousCompilableToken == TokenName.RBRACKET)
+ || (previousCompilableToken == TokenName.EQUAL)) {
+ // if (previousCompilableToken == TokenName.RBRACKET)
+ // {
+ inArrayAssignment = true;
+ inAssignment = false;
+ }
+ if (inArrayAssignment) {
+ indentationLevel += pushBlock();
+ } else {
+ // Add new line and increase indentation level after
+ // open brace.
+ pendingNewLines = 1;
+ indentationLevel += pushBlock();
+ inAssignment = false;
+ }
+ }
+ break;
+ case RBRACE:
+ if (dollarBraceCount > 0) {
+ dollarBraceCount--;
+ break;
+ }
+ if (previousCompilableToken == TokenName.RPAREN) {
+ pendingSpace = false;
+ }
+ if (inArrayAssignment) {
+ inArrayAssignment = false;
+ pendingNewLines = 1;
+ indentationLevel += popInclusiveUntilBlock();
+ } else {
+ pendingNewLines = 1;
+ indentationLevel += popInclusiveUntilBlock();
+ if (previousCompilableToken == TokenName.RPAREN) {
+ // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on
+ // message
+ // expression
+ currentLineBuffer
+ .append(options.lineSeparatorSequence);
+ increaseLineDelta(options.lineSeparatorSequence.length);
+ }
+ if (constructionsCount > 0) {
+ switch (constructions[constructionsCount - 1]) {
+ case FOR:
+ case FOREACH:
+ // indentationLevel += popExclusiveUntilBlock();
+ // break;
+ case SWITCH:
+ case IF:
+ case ELSE:
+ case TRY:
+ case CATCH:
+ case FINALLY:
+ case WHILE:
+ case DO:
+ // case TokenName.synchronized :
+ clearNonBlockIndents = true;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case LBRACKET:
+ openBracketCount++;
+ pendingSpace = false;
+ break;
+ case RBRACKET:
+ openBracketCount -= (openBracketCount > 0) ? 1 : 0;
+ // if there is no left bracket to close, the right bracket
+ // is
+ // ignored.
+ pendingSpace = false;
+ break;
+ case COMMA:
+ pendingSpace = false;
+ if (arrayDeclarationCount > 0) {
+ if (arrayDeclarationParenthesis[arrayDeclarationCount] == openParenthesis[openParenthesisCount - 1]) {
+ // there is no left parenthesis to close in current array declaration (#1475484)
+ if (!options.compactArrays) {
+ pendingNewLines = 1;
+ }
+ }
+ }
+ break;
+ case DOT:
+ if (!options.compactStringConcatenation) {
+ space();
+ }
+ pendingSpace = false;
+ break;
+ case SEMICOLON:
+ // Do not generate line terminators in the definition of
+ // the for statement.
+ // if not in this case, jump a line and reduce indentation
+ // after
+ // the brace
+ // if the block it closes belongs to a conditional statement
+ // (if,
+ // while, do...).
+ if (openParenthesisCount <= 1) {
+ pendingNewLines = 1;
+ if (expectingOpenBrace) {
+ clearNonBlockIndents = true;
+ expectingOpenBrace = false;
+ }
+ }
+ inAssignment = false;
+ pendingSpace = false;
+ break;
+ case PLUS_PLUS:
+ case MINUS_MINUS:
+ // Do not put a space between a post-increment/decrement
+ // and the identifier being modified.
+ if (previousToken == TokenName.IDENTIFIER
+ || previousToken == TokenName.RBRACKET
+ || previousToken == TokenName.VARIABLE) {
+ pendingSpace = false;
+ }
+ break;
+ case PLUS:
+ // previously ADDITION
+ case MINUS:
+ // Handle the unary operators plus and minus via a flag
+ if (!isLiteralToken(previousToken)
+ && previousToken != TokenName.IDENTIFIER
+ && previousToken != TokenName.RPAREN
+ && previousToken != TokenName.RBRACKET) {
+ unarySignModifier = 1;
+ }
+ break;
+ case COLON:
+ // In a switch/case statement, add a newline & indent
+ // when a colon is encountered.
+ if (tokenBeforeColonCount > 0) {
+ if (tokenBeforeColon[tokenBeforeColonCount - 1] == TokenName.CASE) {
+ pendingNewLines = 1;
+ }
+ tokenBeforeColonCount--;
+ }
+ break;
+ case EQUAL:
+ inAssignment = true;
+ break;
+ case COMMENT_LINE:
+ pendingNewLines = 1;
+ //if (inAssignment) {
+ // currentLineIndentationLevel++;
+ //}
+ break; // a line is always inserted after a one-line
+ // comment
+ case COMMENT_PHPDOC:
+ case COMMENT_BLOCK:
+ currentCommentOffset = getCurrentCommentOffset();
+ pendingNewLines = 1;
+ break;
+ case WHITESPACE:
+ if (!phpTagAndWhitespace) {
+ // Count the number of line terminators in the
+ // whitespace so
+ // line spacing can be preserved near comments.
+ char[] source = scanner.source;
+ newLinesInWhitespace = 0;
+ for (int i = scanner.startPosition, max = scanner.currentPosition; i < max; i++) {
+ if (source[i] == '\r') {
+ if (i < max - 1) {
+ if (source[++i] == '\n') {
+ newLinesInWhitespace++;
+ } else {
+ newLinesInWhitespace++;
+ }
+ } else {
+ newLinesInWhitespace++;
+ }
+ } else if (source[i] == '\n') {
+ newLinesInWhitespace++;
+ }
+ }
+ increaseLineDelta(scanner.startPosition
+ - scanner.currentPosition);
+ break;
+ }
+ // case TokenName.HTML :
+ // // Add the next token to the formatted source string.
+ // // outputCurrentToken(token);
+ // int startPosition = scanner.startPosition;
+ // flushBuffer();
+ // for (int i = startPosition, max =
+ // scanner.currentPosition; i <
+ // max; i++) {
+ // char currentCharacter = scanner.source[i];
+ // updateMappedPositions(i);
+ // currentLineBuffer.append(currentCharacter);
+ // }
+ // break;
+ default:
+ if ((token == TokenName.IDENTIFIER) || isLiteralToken(token)
+ || token == TokenName.SUPER) {
+ // || token == TokenName.this) {
+ // Do not put a space between a unary operator
+ // (eg: ++, --, +, -) and the identifier being modified.
+ if (previousToken == TokenName.PLUS_PLUS
+ || previousToken == TokenName.MINUS_MINUS
+ || (previousToken == TokenName.MINUS_GREATER && options.compactDereferencingMode) // ->
+ || (previousToken == TokenName.PLUS && unarySignModifier > 0)
+ || (previousToken == TokenName.MINUS && unarySignModifier > 0)) {
+ pendingSpace = false;
+ }
+ unarySignModifier = 0;
+ }
+ break;
+ }
+ // Do not output whitespace tokens.
+ if (token != Scanner.TokenName.WHITESPACE || phpTagAndWhitespace) {
+ /*
+ * Add pending space to the formatted source string. Do not
+ * output a space under the following circumstances: 1) this
+ * is the first pass 2) previous token is an open paren 3)
+ * previous token is a period 4) previous token is the
+ * logical compliment (eg: !) 5) previous token is the
+ * bitwise compliment (eg: ~) 6) previous token is the open
+ * bracket (eg: [) 7) in an assignment statement, if the
+ * previous token is an open brace or the current token is a
+ * close brace 8) previous token is a single line comment 9)
+ * current token is a '->'
+ */
+ if (token == TokenName.MINUS_GREATER
+ && options.compactDereferencingMode)
+ pendingSpace = false;
+
+ boolean openAndCloseBrace = previousCompilableToken == TokenName.LBRACE
+ && token == TokenName.RBRACE;
+ if (pendingSpace
+ && insertSpaceAfter(previousToken)
+ && !(inAssignment && (previousToken == TokenName.LBRACE || token == TokenName.RBRACE))
+ && previousToken != Scanner.TokenName.COMMENT_LINE) {
+ if ((!(options.compactAssignmentMode && token == TokenName.EQUAL))
+ && !openAndCloseBrace)
+ space();
+ }
+ // Add the next token to the formatted source string.
+ outputCurrentToken(token);
+ if (token == Scanner.TokenName.COMMENT_LINE
+ && openParenthesisCount > 1) {
+ pendingNewLines = 0;
+ currentLineBuffer.append(options.lineSeparatorSequence);
+ increaseLineDelta(options.lineSeparatorSequence.length);
+ }
+ pendingSpace = true;
+ }
+ // Whitespace tokens do not need to be remembered.
+ if (token != Scanner.TokenName.WHITESPACE || phpTagAndWhitespace) {
+ previousToken = token;
+ if (token != Scanner.TokenName.COMMENT_BLOCK
+ && token != Scanner.TokenName.COMMENT_LINE
+ && token != Scanner.TokenName.COMMENT_PHPDOC) {
+ previousCompilableToken = token;
+ }
+ }
+ }
+ output(copyRemainingSource());
+ flushBuffer();
+ // dump the last token of the source in the formatted output.
+ } catch (InvalidInputException e) {
+ output(copyRemainingSource());
+ flushBuffer();
+ // dump the last token of the source in the formatted output.
+ }
+ }
+
+ /**
+ * Formats the char array <code>sourceString</code>, and returns a string
+ * containing the formatted version.
+ *
+ * @return the formatted ouput.
+ */
+ public String formatSourceString(String sourceString) {
+ char[] sourceChars = sourceString.toCharArray();
+ formattedSource = new StringBuffer(sourceChars.length);
+ scanner.setSource(sourceChars);
+ format();
+ return formattedSource.toString();
+ }
+
+ /**
+ * Formats the char array <code>sourceString</code>, and returns a string
+ * containing the formatted version.
+ *
+ * @param string
+ * the string to format
+ * @param indentationLevel
+ * the initial indentation level
+ * @return the formatted ouput.
+ */
+ public String format(String string, int indentationLevel) {
+ return format(string, indentationLevel, (int[]) null);
+ }
+
+ /**
+ * Formats the char array <code>sourceString</code>, and returns a string
+ * containing the formatted version. The positions array is modified to
+ * contain the mapped positions.
+ *
+ * @param string
+ * the string to format
+ * @param indentationLevel
+ * the initial indentation level
+ * @param positions
+ * the array of positions to map
+ * @return the formatted ouput.
+ */
+ public String format(String string, int indentationLevel, int[] positions) {
+ return this.format(string, indentationLevel, positions, null);
+ }
+
+ public String format(String string, int indentationLevel, int[] positions,
+ String lineSeparator) {
+ if (lineSeparator != null) {
+ this.options.setLineSeparator(lineSeparator);
+ }
+ if (positions != null) {
+ this.setPositionsToMap(positions);
+ this.setInitialIndentationLevel(indentationLevel);
+ String formattedString = this.formatSourceString(string);
+ int[] mappedPositions = this.getMappedPositions();
+ System
+ .arraycopy(mappedPositions, 0, positions, 0,
+ positions.length);
+ return formattedString;
+ } else {
+ this.setInitialIndentationLevel(indentationLevel);
+ return this.formatSourceString(string);
+ }
+ }
+
+ /**
+ * Formats the char array <code>sourceString</code>, and returns a string
+ * containing the formatted version. The initial indentation level is 0.
+ *
+ * @param string
+ * the string to format
+ * @return the formatted ouput.
+ */
+ public String format(String string) {
+ return this.format(string, 0, (int[]) null);
+ }
+
+ /**
+ * Formats a given source string, starting indenting it at a particular
+ * depth and using the given options
+ *
+ * @deprecated backport 1.0 internal functionality
+ */
+ public static String format(String sourceString,
+ int initialIndentationLevel, ConfigurableOption[] options) {
+ CodeFormatter formatter = new CodeFormatter(options);
+ formatter.setInitialIndentationLevel(initialIndentationLevel);
+ return formatter.formatSourceString(sourceString);
+ }
+
+ /**
+ * Returns the number of characters and tab char between the beginning of
+ * the line and the beginning of the comment.
+ */
+ private int getCurrentCommentOffset() {
+ int linePtr = scanner.linePtr;
+ // if there is no beginning of line, return 0.
+ if (linePtr < 0)
+ return 0;
+ int offset = 0;
+ int beginningOfLine = scanner.lineEnds[linePtr];
+ int currentStartPosition = scanner.startPosition;
+ char[] source = scanner.source;
+ // find the position of the beginning of the line containing the comment
+ while (beginningOfLine > currentStartPosition) {
+ if (linePtr > 0) {
+ beginningOfLine = scanner.lineEnds[--linePtr];
+ } else {
+ beginningOfLine = 0;
+ break;
+ }
+ }
+ for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) {
+ char currentCharacter = source[i];
+ switch (currentCharacter) {
+ case '\t':
+ offset += options.tabSize;
+ break;
+ case ' ':
+ offset++;
+ break;
+ case '\r':
+ case '\n':
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+ }
+
+ /**
+ * Returns an array of descriptions for the configurable options. The
+ * descriptions may be changed and passed back to a different compiler.
+ *
+ * @deprecated backport 1.0 internal functionality
+ */
+// public static ConfigurableOption[] getDefaultOptions(Locale locale) {
+// String componentName = CodeFormatter.class.getName();
+// FormatterOptions options = new FormatterOptions();
+// return new ConfigurableOption[] {
+// new ConfigurableOption(componentName, "newline.openingBrace",
+// locale, options.newLineBeforeOpeningBraceMode ? 0 : 1),
+// //$NON-NLS-1$
+// new ConfigurableOption(componentName,
+// "newline.controlStatement", locale,
+// options.newlineInControlStatementMode ? 0 : 1),
+// //$NON-NLS-1$
+// new ConfigurableOption(componentName, "newline.clearAll",
+// locale, options.clearAllBlankLinesMode ? 0 : 1),
+// //$NON-NLS-1$
+// // new ConfigurableOption(componentName, "newline.elseIf",
+// // locale,
+// // options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$
+// new ConfigurableOption(componentName, "newline.emptyBlock",
+// locale, options.newLineInEmptyBlockMode ? 0 : 1),
+// //$NON-NLS-1$
+// new ConfigurableOption(componentName, "line.split", locale,
+// options.maxLineLength),
+// //$NON-NLS-1$
+// new ConfigurableOption(componentName,
+// "style.compactAssignment", locale,
+// options.compactAssignmentMode ? 0 : 1),
+// //$NON-NLS-1$
+// new ConfigurableOption(componentName, "tabulation.char",
+// locale, options.indentWithTab ? 0 : 1),
+// //$NON-NLS-1$
+// new ConfigurableOption(componentName,
+// "tabulation.size", locale, options.tabSize) //$NON-NLS-1$
+// };
+// }
+
+ /**
+ * Returns the array of mapped positions. Returns null is no positions have
+ * been set.
+ *
+ * @return int[]
+ * @deprecated There is no need to retrieve the mapped positions anymore.
+ */
+ public int[] getMappedPositions() {
+ if (null != mappedPositions) {
+ for (int i = 0; i < mappedPositions.length; i++) {
+ if (mappedPositions[i] >= formattedSource.length()) {
+ mappedPositions[i] = formattedSource.length() - 1;
+ }
+ }
+ }
+ return mappedPositions;
+ }
+
+ /**
+ * Returns the priority of the token given as argument <br>
+ * The most prioritary the token is, the smallest the return value is.
+ *
+ * @return the priority of <code>token</code>
+ * @param token
+ * the token of which the priority is requested
+ */
+// private static int getTokenPriority(int token) {
+// switch (token) {
+// case TokenName.extends:
+// // case TokenName.implements :
+// // case TokenName.throws :
+// return 10;
+// case TokenName.SEMICOLON:
+// // ;
+// return 20;
+// case TokenName.COMMA:
+// // ,
+// return 25;
+// case TokenName.EQUAL:
+// // =
+// return 30;
+// case TokenName.AND_AND:
+// // &&
+// case TokenName.OR_OR:
+// // ||
+// return 40;
+// case TokenName.QUESTION:
+// // ?
+// case TokenName.COLON:
+// // :
+// return 50; // it's better cutting on ?: than on ;
+// case TokenName.EQUAL_EQUAL:
+// // ==
+// case TokenName.EQUAL_EQUAL_EQUAL:
+// // ===
+// case TokenName.NOT_EQUAL:
+// // !=
+// case TokenName.NOT_EQUAL_EQUAL:
+// // !=
+// return 60;
+// case TokenName.LESS:
+// // <
+// case TokenName.LESS_EQUAL:
+// // <=
+// case TokenName.GREATER:
+// // >
+// case TokenName.GREATER_EQUAL:
+// // >=
+// // case TokenName.instanceof : // instanceof
+// return 70;
+// case TokenName.PLUS:
+// // +
+// case TokenName.MINUS:
+// // -
+// return 80;
+// case TokenName.MULTIPLY:
+// // *
+// case TokenName.DIVIDE:
+// // /
+// case TokenName.REMAINDER:
+// // %
+// return 90;
+// case TokenName.LEFT_SHIFT:
+// // <<
+// case TokenName.RIGHT_SHIFT:
+// // >>
+// // case TokenName.UNSIGNED_RIGHT_SHIFT : // >>>
+// return 100;
+// case TokenName.AND:
+// // &
+// case TokenName.OR:
+// // |
+// case TokenName.XOR:
+// // ^
+// return 110;
+// case TokenName.MULTIPLY_EQUAL:
+// // *=
+// case TokenName.DIVIDE_EQUAL:
+// // /=
+// case TokenName.REMAINDER_EQUAL:
+// // %=
+// case TokenName.PLUS_EQUAL:
+// // +=
+// case TokenName.MINUS_EQUAL:
+// // -=
+// case TokenName.LEFT_SHIFT_EQUAL:
+// // <<=
+// case TokenName.RIGHT_SHIFT_EQUAL:
+// // >>=
+// // case TokenName.UNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
+// case TokenName.AND_EQUAL:
+// // &=
+// case TokenName.XOR_EQUAL:
+// // ^=
+// case TokenName.OR_EQUAL:
+// // .=
+// case TokenName.DOT_EQUAL:
+// // |=
+// return 120;
+// case TokenName.DOT:
+// // .
+// return 130;
+// default:
+// return Integer.MAX_VALUE;
+// }
+// }
+
+ /**
+ * Handles the exception raised when an invalid token is encountered.
+ * Returns true if the exception has been handled, false otherwise.
+ */
+ private boolean handleInvalidToken(Exception e) {
+ if (e.getMessage().equals(Scanner.INVALID_CHARACTER_CONSTANT)
+ || e.getMessage().equals(Scanner.INVALID_CHAR_IN_STRING)
+ || e.getMessage().equals(Scanner.INVALID_ESCAPE)) {
+ return true;
+ }
+ return false;
+ }
+
+ private final void increaseGlobalDelta(int offset) {
+ globalDelta += offset;
+ }
+
+ private final void increaseLineDelta(int offset) {
+ lineDelta += offset;
+ }
+
+ private final void increaseSplitDelta(int offset) {
+ splitDelta += offset;
+ }
+
+ /**
+ * Returns true if a space has to be inserted after <code>operator</code>
+ * false otherwise.
+ */
+ private boolean insertSpaceAfter(TokenName token) {
+ switch (token) {
+ case LPAREN:
+ case NOT:
+ case TWIDDLE:
+ case NONE:
+ // no token
+ case WHITESPACE:
+ case LBRACKET:
+ case DOLLAR:
+ case COMMENT_LINE:
+ return false;
+ case DOT:
+ return !options.compactStringConcatenation;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Returns true if a space has to be inserted before <code>operator</code>
+ * false otherwise. <br>
+ * Cannot be static as it uses the code formatter options (to know if the
+ * compact assignment mode is on).
+ */
+ private boolean insertSpaceBefore(TokenName token) {
+ switch (token) {
+ case EQUAL:
+ return (!options.compactAssignmentMode);
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isComment(TokenName token) {
+ boolean result = token == Scanner.TokenName.COMMENT_BLOCK
+ || token == Scanner.TokenName.COMMENT_LINE
+ || token == Scanner.TokenName.COMMENT_PHPDOC;
+ return result;
+ }
+
+ private static boolean isLiteralToken(TokenName token) {
+ boolean result = token == TokenName.INTEGERLITERAL
+ // || token == TokenName.LongLiteral
+ // || token == TokenName.FloatingPointLiteral
+ || token == TokenName.DOUBLELITERAL
+ // || token == TokenName.CharacterLiteral
+ || token == TokenName.STRINGDOUBLEQUOTE;
+ return result;
+ }
+
+ /**
+ * If the length of <code>oneLineBuffer</code> exceeds
+ * <code>maxLineLength</code>, it is split and the result is dumped in
+ * <code>formattedSource</code>
+ *
+ * @param newLineCount
+ * the number of new lines to append
+ */
+ private void newLine(int newLineCount) {
+ // format current line
+ splitDelta = 0;
+ beginningOfLineIndex = formattedSource.length();
+ String currentLine = currentLineBuffer.toString();
+ if (containsOpenCloseBraces) {
+ containsOpenCloseBraces = false;
+ outputLine(currentLine, false, indentationLevelForOpenCloseBraces,
+ TokenName.NONE, -1, null, 0);
+ indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
+ } else {
+ outputLine(currentLine, false, currentLineIndentationLevel, TokenName.NONE, -1,
+ null, 0);
+ }
+ // dump line break(s)
+ for (int i = 0; i < newLineCount; i++) {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+ }
+ // reset formatter for next line
+ int currentLength = currentLine.length();
+ currentLineBuffer = new StringBuffer(
+ currentLength > maxLineSize ? maxLineSize = currentLength
+ : maxLineSize);
+ increaseGlobalDelta(splitDelta);
+ increaseGlobalDelta(lineDelta);
+ lineDelta = 0;
+ currentLineIndentationLevel = initialIndentationLevel;
+ }
+
+ private String operatorString(TokenName operator) {
+ switch (operator) {
+ case EXTENDS:
+ return "extends"; //$NON-NLS-1$
+ // case TokenName.implements :
+ // return "implements"; //$NON-NLS-1$
+ //
+ // case TokenName.throws :
+ // return "throws"; //$NON-NLS-1$
+ case SEMICOLON:
+ // ;
+ return ";"; //$NON-NLS-1$
+ case COMMA:
+ // ,
+ return ","; //$NON-NLS-1$
+ case EQUAL:
+ // =
+ return "="; //$NON-NLS-1$
+ case AND_AND:
+ // && (15.22)
+ return "&&"; //$NON-NLS-1$
+ case OR_OR:
+ // || (15.23)
+ return "||"; //$NON-NLS-1$
+ case QUESTION:
+ // ? (15.24)
+ return "?"; //$NON-NLS-1$
+ case COLON:
+ // : (15.24)
+ return ":"; //$NON-NLS-1$
+ case PAAMAYIM_NEKUDOTAYIM:
+ // : (15.24)
+ return "::"; //$NON-NLS-1$
+ case EQUAL_EQUAL:
+ // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+ return "=="; //$NON-NLS-1$
+ case EQUAL_EQUAL_EQUAL:
+ // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+ return "==="; //$NON-NLS-1$
+ case EQUAL_GREATER:
+ // -= (15.25.2)
+ return "=>"; //$NON-NLS-1$
+ case NOT_EQUAL:
+ // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+ return "!="; //$NON-NLS-1$
+ case NOT_EQUAL_EQUAL:
+ // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+ return "!=="; //$NON-NLS-1$
+ case LESS:
+ // < (15.19.1)
+ return "<"; //$NON-NLS-1$
+ case LESS_EQUAL:
+ // <= (15.19.1)
+ return "<="; //$NON-NLS-1$
+ case GREATER:
+ // > (15.19.1)
+ return ">"; //$NON-NLS-1$
+ case GREATER_EQUAL:
+ // >= (15.19.1)
+ return ">="; //$NON-NLS-1$
+ // case instanceof : // instanceof
+ // return "instanceof"; //$NON-NLS-1$
+ case PLUS:
+ // + (15.17, 15.17.2)
+ return "+"; //$NON-NLS-1$
+ case MINUS:
+ // - (15.17.2)
+ return "-"; //$NON-NLS-1$
+ case MULTIPLY:
+ // * (15.16.1)
+ return "*"; //$NON-NLS-1$
+ case DIVIDE:
+ // / (15.16.2)
+ return "/"; //$NON-NLS-1$
+ case REMAINDER:
+ // % (15.16.3)
+ return "%"; //$NON-NLS-1$
+ case LEFT_SHIFT:
+ // << (15.18)
+ return "<<"; //$NON-NLS-1$
+ case RIGHT_SHIFT:
+ // >> (15.18)
+ return ">>"; //$NON-NLS-1$
+ // case UNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+ // return ">>>"; //$NON-NLS-1$
+ case OP_AND:
+ // & (15.21, 15.21.1, 15.21.2)
+ return "&"; //$NON-NLS-1$
+ case OP_OR:
+ // | (15.21, 15.21.1, 15.21.2)
+ return "|"; //$NON-NLS-1$
+ case OP_XOR:
+ // ^ (15.21, 15.21.1, 15.21.2)
+ return "^"; //$NON-NLS-1$
+ case MULTIPLY_EQUAL:
+ // *= (15.25.2)
+ return "*="; //$NON-NLS-1$
+ case DIVIDE_EQUAL:
+ // /= (15.25.2)
+ return "/="; //$NON-NLS-1$
+ case REMAINDER_EQUAL:
+ // %= (15.25.2)
+ return "%="; //$NON-NLS-1$
+ case PLUS_EQUAL:
+ // += (15.25.2)
+ return "+="; //$NON-NLS-1$
+ case MINUS_EQUAL:
+ // -= (15.25.2)
+ return "-="; //$NON-NLS-1$
+ case MINUS_GREATER:
+ // -= (15.25.2)
+ return "->"; //$NON-NLS-1$
+ case LEFT_SHIFT_EQUAL:
+ // <<= (15.25.2)
+ return "<<="; //$NON-NLS-1$
+ case RIGHT_SHIFT_EQUAL:
+ // >>= (15.25.2)
+ return ">>="; //$NON-NLS-1$
+ // case UNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+ // return ">>>="; //$NON-NLS-1$
+ case AND_EQUAL:
+ // &= (15.25.2)
+ return "&="; //$NON-NLS-1$
+ case XOR_EQUAL:
+ // ^= (15.25.2)
+ return "^="; //$NON-NLS-1$
+ case OR_EQUAL:
+ // |= (15.25.2)
+ return "|="; //$NON-NLS-1$
+ case DOT_EQUAL:
+ // .=
+ return ".="; //$NON-NLS-1$
+ case DOT:
+ // .
+ return "."; //$NON-NLS-1$
+ default:
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Appends <code>stringToOutput</code> to the formatted output. <br>
+ * If it contains \n, append a LINE_SEPARATOR and indent after it.
+ */
+ private void output(String stringToOutput) {
+ char currentCharacter;
+ for (int i = 0, max = stringToOutput.length(); i < max; i++) {
+ currentCharacter = stringToOutput.charAt(i);
+ if (currentCharacter != '\t') {
+ currentLineBuffer.append(currentCharacter);
+ }
+ }
+ }
+
+ private void outputCurrentTokenWithoutIndent(TokenName heredoc, int newLineCount) {
+ newLine(newLineCount);
+ formattedSource.append(scanner.source, scanner.startPosition,
+ scanner.currentPosition - scanner.startPosition);
+ }
+
+ /**
+ * Appends <code>token</code> to the formatted output. <br>
+ * If it contains <code>\n</code>, append a LINE_SEPARATOR and indent
+ * after it.
+ */
+ private void outputCurrentToken(TokenName token) {
+ char[] source = scanner.source;
+ int startPosition = scanner.startPosition;
+ switch (token) {
+ case COMMENT_PHPDOC:
+ case COMMENT_BLOCK:
+ case COMMENT_LINE:
+ boolean endOfLine = false;
+ int currentCommentOffset = getCurrentCommentOffset();
+ int beginningOfLineSpaces = 0;
+ endOfLine = false;
+ currentCommentOffset = getCurrentCommentOffset();
+ beginningOfLineSpaces = 0;
+ boolean pendingCarriageReturn = false;
+ for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
+ char currentCharacter = source[i];
+ updateMappedPositions(i);
+ switch (currentCharacter) {
+ case '\r':
+ pendingCarriageReturn = true;
+ endOfLine = true;
+ break;
+ case '\n':
+ if (pendingCarriageReturn) {
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
+ } else {
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+ }
+ pendingCarriageReturn = false;
+ currentLineBuffer.append(options.lineSeparatorSequence);
+ beginningOfLineSpaces = 0;
+ endOfLine = true;
+ break;
+ case '\t':
+ if (pendingCarriageReturn) {
+ pendingCarriageReturn = false;
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+ currentLineBuffer.append(options.lineSeparatorSequence);
+ beginningOfLineSpaces = 0;
+ endOfLine = true;
+ }
+ if (endOfLine) {
+ // we remove a maximum of currentCommentOffset
+ // characters (tabs
+ // are converted to space numbers).
+ beginningOfLineSpaces += options.tabSize;
+ if (beginningOfLineSpaces > currentCommentOffset) {
+ currentLineBuffer.append(currentCharacter);
+ } else {
+ increaseGlobalDelta(-1);
+ }
+ } else {
+ currentLineBuffer.append(currentCharacter);
+ }
+ break;
+ case ' ':
+ if (pendingCarriageReturn) {
+ pendingCarriageReturn = false;
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+ currentLineBuffer.append(options.lineSeparatorSequence);
+ beginningOfLineSpaces = 0;
+ endOfLine = true;
+ }
+ if (endOfLine) {
+ // we remove a maximum of currentCommentOffset
+ // characters (tabs
+ // are converted to space numbers).
+ beginningOfLineSpaces++;
+ if (beginningOfLineSpaces > currentCommentOffset) {
+ currentLineBuffer.append(currentCharacter);
+ } else {
+ increaseGlobalDelta(-1);
+ }
+ } else {
+ currentLineBuffer.append(currentCharacter);
+ }
+ break;
+ default:
+ if (pendingCarriageReturn) {
+ pendingCarriageReturn = false;
+ increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
+ currentLineBuffer.append(options.lineSeparatorSequence);
+ beginningOfLineSpaces = 0;
+ endOfLine = true;
+ } else {
+ beginningOfLineSpaces = 0;
+ currentLineBuffer.append(currentCharacter);
+ endOfLine = false;
+ }
+ }
+ }
+ updateMappedPositions(scanner.currentPosition - 1);
+ multipleLineCommentCounter++;
+ break;
+ default:
+ for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
+ char currentCharacter = source[i];
+ updateMappedPositions(i);
+ currentLineBuffer.append(currentCharacter);
+ }
+ }
+ }
+
+ /**
+ * Outputs <code>currentString</code>:<br>
+ * <ul>
+ * <li>If its length is < maxLineLength, output
+ * <li>Otherwise it is split.
+ * </ul>
+ *
+ * @param currentString
+ * string to output
+ * @param preIndented
+ * whether the string to output was pre-indented
+ * @param depth
+ * number of indentation to put in front of
+ * <code>currentString</code>
+ * @param operator
+ * value of the operator belonging to <code>currentString</code>.
+ */
+ private void outputLine(String currentString, boolean preIndented,
+ int depth, TokenName operator, int substringIndex,
+ int[] startSubstringIndexes, int offsetInGlobalLine) {
+ boolean emptyFirstSubString = false;
+ String operatorString = operatorString(operator);
+ boolean placeOperatorBehind = !breakLineBeforeOperator(operator);
+ boolean placeOperatorAhead = !placeOperatorBehind;
+ // dump prefix operator?
+ if (placeOperatorAhead) {
+ if (!preIndented) {
+ dumpTab(depth);
+ preIndented = true;
+ }
+ if (operator.compareTo (TokenName.NONE) > 0) {
+ if (insertSpaceBefore(operator)) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ formattedSource.append(operatorString);
+ increaseSplitDelta(operatorString.length());
+ if (insertSpaceAfter(operator)
+ && operator != TokenName.IMPLEMENTS
+ && operator != TokenName.EXTENDS) {
+ // && operator != TokenName.throws) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+ }
+ SplitLine splitLine = null;
+ if (options.maxLineLength == 0
+ || getLength(currentString, depth) < options.maxLineLength
+ || (splitLine = split(currentString, offsetInGlobalLine)) == null) {
+ // depending on the type of operator, outputs new line before of
+ // after
+ // dumping it
+ // indent before postfix operator
+ // indent also when the line cannot be split
+ if (operator == TokenName.EXTENDS || operator == TokenName.IMPLEMENTS) {
+ // || operator == TokenName.throws) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ if (placeOperatorBehind) {
+ if (!preIndented) {
+ dumpTab(depth);
+ }
+ }
+ int max = currentString.length();
+ if (multipleLineCommentCounter != 0) {
+ try {
+ BufferedReader reader = new BufferedReader(
+ new StringReader(currentString));
+ String line = reader.readLine();
+ while (line != null) {
+ updateMappedPositionsWhileSplitting(
+ beginningOfLineIndex, beginningOfLineIndex
+ + line.length()
+ + options.lineSeparatorSequence.length);
+ formattedSource.append(line);
+ beginningOfLineIndex = beginningOfLineIndex
+ + line.length();
+ if ((line = reader.readLine()) != null) {
+ formattedSource
+ .append(options.lineSeparatorSequence);
+ beginningOfLineIndex += options.lineSeparatorSequence.length;
+ dumpTab(currentLineIndentationLevel);
+ }
+ }
+ reader.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ updateMappedPositionsWhileSplitting(beginningOfLineIndex,
+ beginningOfLineIndex + max);
+ for (int i = 0; i < max; i++) {
+ char currentChar = currentString.charAt(i);
+ switch (currentChar) {
+ case '\r':
+ break;
+ case '\n':
+ if (i != max - 1) {
+ // fix for 1FFYL5C: LFCOM:ALL - Incorrect
+ // indentation when
+ // split with a comment inside a condition
+ // a substring cannot end with a
+ // lineSeparatorSequence,
+ // except if it has been added by format() after a
+ // one-line
+ // comment
+ formattedSource
+ .append(options.lineSeparatorSequence);
+ // 1FGDDV6: LFCOM:WIN98 - Weird splitting on message
+ // expression
+ dumpTab(depth - 1);
+ }
+ break;
+ default:
+ formattedSource.append(currentChar);
+ }
+ }
+ }
+ // update positions inside the mappedPositions table
+ if (substringIndex != -1) {
+ if (multipleLineCommentCounter == 0) {
+ int startPosition = beginningOfLineIndex
+ + startSubstringIndexes[substringIndex];
+ updateMappedPositionsWhileSplitting(startPosition,
+ startPosition + max);
+ }
+ // compute the splitDelta resulting with the operator and blank
+ // removal
+ if (substringIndex + 1 != startSubstringIndexes.length) {
+ increaseSplitDelta(startSubstringIndexes[substringIndex]
+ + max - startSubstringIndexes[substringIndex + 1]);
+ }
+ }
+ // dump postfix operator?
+ if (placeOperatorBehind) {
+ if (insertSpaceBefore(operator)) {
+ formattedSource.append(' ');
+ if (operator.compareTo (TokenName.NONE) > 0) {
+ increaseSplitDelta(1);
+ }
+ }
+ formattedSource.append(operatorString);
+ if (operator.compareTo (TokenName.NONE) > 0) {
+ increaseSplitDelta(operatorString.length());
+ }
+ }
+ return;
+ }
+ // fix for 1FG0BA3: LFCOM:WIN98 - Weird splitting on interfaces
+ // extends has to stand alone on a line when currentString has been
+ // split.
+ if (options.maxLineLength != 0 && splitLine != null
+ && (operator == TokenName.EXTENDS)) {
+ // || operator == TokenName.IMPLEMENTS
+ // || operator == TokenName.THROWS)) {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+ dumpTab(depth + 1);
+ } else {
+ if (operator == TokenName.EXTENDS) {
+ // || operator == TokenName.implements
+ // || operator == TokenName.throws) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+ // perform actual splitting
+ String result[] = splitLine.substrings;
+ TokenName[] splitOperators = splitLine.operators;
+ if (result[0].length() == 0) {
+ // when the substring 0 is null, the substring 1 is correctly
+ // indented.
+ depth--;
+ emptyFirstSubString = true;
+ }
+ // the operator going in front of the result[0] string is the operator
+ // parameter
+ for (int i = 0, max = result.length; i < max; i++) {
+ // the new depth is the current one if this is the first substring,
+ // the current one + 1 otherwise.
+ // if the substring is a comment, use the current indentation Level
+ // instead of the depth
+ // (-1 because the ouputline increases depth).
+ // (fix for 1FFC72R: LFCOM:ALL - Incorrect line split in presence of
+ // line
+ // comments)
+ String currentResult = result[i];
+ if (currentResult.length() != 0 || splitOperators[i].compareTo (TokenName.NONE) > 0) {
+ int newDepth = (currentResult.startsWith("/*") //$NON-NLS-1$
+ || currentResult.startsWith("//")) //$NON-NLS-1$
+ ? indentationLevel - 1
+ : depth;
+ outputLine(currentResult,
+ i == 0 || (i == 1 && emptyFirstSubString) ? preIndented: false,
+ i == 0 ? newDepth : newDepth + 1,
+ splitOperators[i],
+ i,
+ splitLine.startSubstringsIndexes,
+ currentString.indexOf(currentResult));
+ if (i != max - 1) {
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+ }
+ }
+ }
+ if (result.length == splitOperators.length - 1) {
+ TokenName lastOperator = splitOperators[result.length];
+ String lastOperatorString = operatorString(lastOperator);
+ formattedSource.append(options.lineSeparatorSequence);
+ increaseSplitDelta(options.lineSeparatorSequence.length);
+ if (breakLineBeforeOperator(lastOperator)) {
+ dumpTab(depth + 1);
+ if (lastOperator.compareTo (TokenName.NONE) > 0) {
+ if (insertSpaceBefore(lastOperator)) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ formattedSource.append(lastOperatorString);
+ increaseSplitDelta(lastOperatorString.length());
+ if (insertSpaceAfter(lastOperator)
+ && lastOperator != TokenName.IMPLEMENTS
+ && lastOperator != TokenName.EXTENDS) {
+ // && lastOperator != TokenName.throws) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ }
+ }
+ }
+ if (placeOperatorBehind) {
+ if (insertSpaceBefore(operator)) {
+ formattedSource.append(' ');
+ increaseSplitDelta(1);
+ }
+ formattedSource.append(operatorString);
+ // increaseSplitDelta(operatorString.length());
+ }
+ }
+
+ /**
+ * Pops the top statement of the stack if it is <code>token</code>
+ */
+ private int pop(TokenName do1) {
+ int delta = 0;
+ if ((constructionsCount > 0)
+ && (constructions[constructionsCount - 1] == do1)) {
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops the top statement of the stack if it is a <code>BLOCK</code> or a
+ * <code>NONINDENT_BLOCK</code>.
+ */
+// private int popBlock() {
+// int delta = 0;
+// if ((constructionsCount > 0)
+// && ((constructions[constructionsCount - 1] == BLOCK) || (constructions[constructionsCount - 1] == NONINDENT_BLOCK))) {
+// if (constructions[constructionsCount - 1] == BLOCK)
+// delta--;
+// constructionsCount--;
+// }
+// return delta;
+// }
+
+ /**
+ * Pops elements until the stack is empty or the top element is
+ * <code>token</code>.<br>
+ * Does not remove <code>token</code> from the stack.
+ *
+ * @param token
+ * the token to be left as the top of the stack
+ */
+// private int popExclusiveUntil(int token) {
+// int delta = 0;
+// int startCount = constructionsCount;
+// for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
+// if (constructions[i] != NONINDENT_BLOCK)
+// delta--;
+// constructionsCount--;
+// }
+// return delta;
+// }
+
+ /**
+ * Pops elements until the stack is empty or the top element is a
+ * <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
+ * Does not remove it from the stack.
+ */
+ private int popExclusiveUntilBlock() {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK
+ && constructions[i] != NONINDENT_BLOCK; i--) {
+ constructionsCount--;
+ delta--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is a
+ * <code>BLOCK</code>, a <code>NONINDENT_BLOCK</code> or a
+ * <code>CASE</code>.<br>
+ * Does not remove it from the stack.
+ */
+ private int popExclusiveUntilBlockOrCase() {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK
+ && constructions[i] != NONINDENT_BLOCK
+ && constructions[i] != TokenName.CASE; i--) {
+ constructionsCount--;
+ delta--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is
+ * <code>token</code>.<br>
+ * Removes <code>token</code> from the stack too.
+ *
+ * @param token
+ * the token to remove from the stack
+ */
+ private int popInclusiveUntil(TokenName token) {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
+ if (constructions[i] != NONINDENT_BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ if (constructionsCount > 0) {
+ if (constructions[constructionsCount - 1] != NONINDENT_BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pops elements until the stack is empty or the top element is a
+ * <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
+ * Does not remove it from the stack.
+ */
+ private int popInclusiveUntilBlock() {
+ int startCount = constructionsCount;
+ int delta = 0;
+ for (int i = startCount - 1; i >= 0
+ && (constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK); i--) {
+ delta--;
+ constructionsCount--;
+ }
+ if (constructionsCount > 0) {
+ if (constructions[constructionsCount - 1] == BLOCK)
+ delta--;
+ constructionsCount--;
+ }
+ return delta;
+ }
+
+ /**
+ * Pushes a block in the stack. <br>
+ * Pushes a <code>BLOCK</code> if the stack is empty or if the top element
+ * is a <code>BLOCK</code>, pushes <code>NONINDENT_BLOCK</code>
+ * otherwise. Creates a new bigger array if the current one is full.
+ */
+ private int pushBlock() {
+ int delta = 0;
+ if (constructionsCount == constructions.length)
+ System.arraycopy(constructions, 0,
+ (constructions = new TokenName[constructionsCount * 2]), 0,
+ constructionsCount);
+ if ((constructionsCount == 0)
+ || (constructions[constructionsCount - 1] == BLOCK)
+ || (constructions[constructionsCount - 1] == NONINDENT_BLOCK)
+ || (constructions[constructionsCount - 1] == TokenName.CASE)) {
+ delta++;
+ constructions[constructionsCount++] = BLOCK;
+ } else {
+ constructions[constructionsCount++] = NONINDENT_BLOCK;
+ }
+ return delta;
+ }
+
+ /**
+ * Pushes <code>token</code>.<br>
+ * Creates a new bigger array if the current one is full.
+ */
+ private int pushControlStatement(TokenName token) {
+ if (constructionsCount == constructions.length)
+ System.arraycopy(constructions, 0,
+ (constructions = new TokenName[constructionsCount * 2]), 0,
+ constructionsCount);
+ constructions[constructionsCount++] = token;
+ return 1;
+ }
+
+// private static boolean separateFirstArgumentOn(int currentToken) {
+// // return (currentToken == TokenName.COMMA || currentToken ==
+// // TokenName.SEMICOLON);
+// return currentToken != TokenName.if && currentToken != TokenName.LPAREN
+// && currentToken != TokenName.NOT
+// && currentToken != TokenName.while
+// && currentToken != TokenName.for
+// && currentToken != TokenName.foreach
+// && currentToken != TokenName.switch;
+// }
+
+ /**
+ * Set the positions to map. The mapped positions should be retrieved using
+ * the getMappedPositions() method.
+ *
+ * @param positions
+ * int[]
+ * @deprecated Set the positions to map using the format(String, int, int[])
+ * method.
+ *
+ * @see #getMappedPositions()
+ */
+ public void setPositionsToMap(int[] positions) {
+ positionsToMap = positions;
+ lineDelta = 0;
+ globalDelta = 0;
+ mappedPositions = new int[positions.length];
+ }
+
+ /**
+ * Appends a space character to the current line buffer.
+ */
+ private void space() {
+ currentLineBuffer.append(' ');
+ increaseLineDelta(1);
+ }
+
+ /**
+ * Splits <code>stringToSplit</code> on the top level token <br>
+ * If there are several identical token at the same level, the string is cut
+ * into many pieces.
+ *
+ * @return an object containing the operator and all the substrings or null
+ * if the string cannot be split
+ */
+// public SplitLine split(String stringToSplit) {
+// return split(stringToSplit, 0);
+// }
+
+ /**
+ * Splits <code>stringToSplit</code> on the top level token <br>
+ * If there are several identical token at the same level, the string is cut
+ * into many pieces.
+ *
+ * @return an object containing the operator and all the substrings or null
+ * if the string cannot be split
+ */
+ public SplitLine split(String stringToSplit, int offsetInGlobalLine) {
+ /*
+ * See http://dev.eclipse.org/bugs/show_bug.cgi?id=12540 and
+ * http://dev.eclipse.org/bugs/show_bug.cgi?id=14387
+ */
+ if (stringToSplit.indexOf("//$NON-NLS") != -1) { //$NON-NLS-1$
+ return null;
+ }
+ // split doesn't work correct for PHP
+ return null;
+ // local variables
+ // int currentToken = 0;
+ // int splitTokenType = 0;
+ // int splitTokenDepth = Integer.MAX_VALUE;
+ // int splitTokenPriority = Integer.MAX_VALUE;
+ // int[] substringsStartPositions = new int[10];
+ // // contains the start position of substrings
+ // int[] substringsEndPositions = new int[10];
+ // // contains the start position of substrings
+ // int substringsCount = 1; // index in the substringsStartPosition
+ // array
+ // int[] splitOperators = new int[10];
+ // // contains the start position of substrings
+ // int splitOperatorsCount = 0; // index in the substringsStartPosition
+ // array
+ // int[] openParenthesisPosition = new int[10];
+ // int openParenthesisPositionCount = 0;
+ // int position = 0;
+ // int lastOpenParenthesisPosition = -1;
+ // // used to remember the position of the 1st open parenthesis
+ // // needed for a pattern like: A.B(C); we want formatted like A.B(
+ // split C);
+ // // setup the scanner with a new source
+ // int lastCommentStartPosition = -1;
+ // // to remember the start position of the last comment
+ // int firstTokenOnLine = -1;
+ // // to remember the first token of the line
+ // int previousToken = -1;
+ // // to remember the previous token.
+ // splitScanner.setSource(stringToSplit.toCharArray());
+ // try {
+ // // start the loop
+ // while (true) {
+ // // takes the next token
+ // try {
+ // if (currentToken != Scanner.TokenName.WHITESPACE)
+ // previousToken = currentToken;
+ // currentToken = splitScanner.getNextToken();
+ // if (Scanner.DEBUG) {
+ // int currentEndPosition = splitScanner.getCurrentTokenEndPosition();
+ // int currentStartPosition = splitScanner
+ // .getCurrentTokenStartPosition();
+ // System.out.print(currentStartPosition + "," + currentEndPosition
+ // + ": ");
+ // System.out.println(scanner.toStringAction(currentToken));
+ // }
+ // } catch (InvalidInputException e) {
+ // if (!handleInvalidToken(e))
+ // throw e;
+ // currentToken = 0;
+ // // this value is not modify when an exception is raised.
+ // }
+ // if (currentToken == TokenName.EOF)
+ // break;
+ // if (firstTokenOnLine == -1) {
+ // firstTokenOnLine = currentToken;
+ // }
+ // switch (currentToken) {
+ // case TokenName.RBRACE :
+ // case TokenName.RPAREN :
+ // if (openParenthesisPositionCount > 0) {
+ // if (openParenthesisPositionCount == 1
+ // && lastOpenParenthesisPosition < openParenthesisPosition[0]) {
+ // lastOpenParenthesisPosition = openParenthesisPosition[0];
+ // } else if ((splitTokenDepth == Integer.MAX_VALUE)
+ // || (splitTokenDepth > openParenthesisPositionCount &&
+ // openParenthesisPositionCount == 1)) {
+ // splitTokenType = 0;
+ // splitTokenDepth = openParenthesisPositionCount;
+ // splitTokenPriority = Integer.MAX_VALUE;
+ // substringsStartPositions[0] = 0;
+ // // better token means the whole line until now is the first
+ // // substring
+ // substringsCount = 1; // resets the count of substrings
+ // substringsEndPositions[0] = openParenthesisPosition[0];
+ // // substring ends on operator start
+ // position = openParenthesisPosition[0];
+ // // the string mustn't be cut before the closing parenthesis but
+ // // after the opening one.
+ // splitOperatorsCount = 1; // resets the count of split operators
+ // splitOperators[0] = 0;
+ // }
+ // openParenthesisPositionCount--;
+ // }
+ // break;
+ // case TokenName.LBRACE :
+ // case TokenName.LPAREN :
+ // if (openParenthesisPositionCount == openParenthesisPosition.length) {
+ // System
+ // .arraycopy(
+ // openParenthesisPosition,
+ // 0,
+ // (openParenthesisPosition = new int[openParenthesisPositionCount *
+ // 2]),
+ // 0, openParenthesisPositionCount);
+ // }
+ // openParenthesisPosition[openParenthesisPositionCount++] =
+ // splitScanner.currentPosition;
+ // if (currentToken == TokenName.LPAREN
+ // && previousToken == TokenName.RPAREN) {
+ // openParenthesisPosition[openParenthesisPositionCount - 1] =
+ // splitScanner.startPosition;
+ // }
+ // break;
+ // case TokenName.SEMICOLON :
+ // // ;
+ // case TokenName.COMMA :
+ // // ,
+ // case TokenName.EQUAL :
+ // // =
+ // if (openParenthesisPositionCount < splitTokenDepth
+ // || (openParenthesisPositionCount == splitTokenDepth &&
+ // splitTokenPriority > getTokenPriority(currentToken))) {
+ // // the current token is better than the one we currently have
+ // // (in level or in priority if same level)
+ // // reset the substringsCount
+ // splitTokenDepth = openParenthesisPositionCount;
+ // splitTokenType = currentToken;
+ // splitTokenPriority = getTokenPriority(currentToken);
+ // substringsStartPositions[0] = 0;
+ // // better token means the whole line until now is the first
+ // // substring
+ // if (separateFirstArgumentOn(firstTokenOnLine)
+ // && openParenthesisPositionCount > 0) {
+ // substringsCount = 2; // resets the count of substrings
+ // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth -
+ // 1];
+ // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth
+ // - 1];
+ // substringsEndPositions[1] = splitScanner.startPosition;
+ // splitOperatorsCount = 2; // resets the count of split operators
+ // splitOperators[0] = 0;
+ // splitOperators[1] = currentToken;
+ // position = splitScanner.currentPosition;
+ // // next substring will start from operator end
+ // } else {
+ // substringsCount = 1; // resets the count of substrings
+ // substringsEndPositions[0] = splitScanner.startPosition;
+ // // substring ends on operator start
+ // position = splitScanner.currentPosition;
+ // // next substring will start from operator end
+ // splitOperatorsCount = 1; // resets the count of split operators
+ // splitOperators[0] = currentToken;
+ // }
+ // } else {
+ // if ((openParenthesisPositionCount == splitTokenDepth &&
+ // splitTokenPriority == getTokenPriority(currentToken))
+ // && splitTokenType != TokenName.EQUAL
+ // && currentToken != TokenName.EQUAL) {
+ // // fix for 1FG0BCN: LFCOM:WIN98 - Missing one indentation after
+ // // split
+ // // take only the 1st = into account.
+ // // if another token with the same priority is found,
+ // // push the start position of the substring and
+ // // push the token into the stack.
+ // // create a new array object if the current one is full.
+ // if (substringsCount == substringsStartPositions.length) {
+ // System
+ // .arraycopy(
+ // substringsStartPositions,
+ // 0,
+ // (substringsStartPositions = new int[substringsCount * 2]),
+ // 0, substringsCount);
+ // System.arraycopy(substringsEndPositions, 0,
+ // (substringsEndPositions = new int[substringsCount * 2]),
+ // 0, substringsCount);
+ // }
+ // if (splitOperatorsCount == splitOperators.length) {
+ // System.arraycopy(splitOperators, 0,
+ // (splitOperators = new int[splitOperatorsCount * 2]), 0,
+ // splitOperatorsCount);
+ // }
+ // substringsStartPositions[substringsCount] = position;
+ // substringsEndPositions[substringsCount++] =
+ // splitScanner.startPosition;
+ // // substring ends on operator start
+ // position = splitScanner.currentPosition;
+ // // next substring will start from operator end
+ // splitOperators[splitOperatorsCount++] = currentToken;
+ // }
+ // }
+ // break;
+ // case TokenName.COLON :
+ // // : (15.24)
+ // // see 1FK7C5R, we only split on a colon, when it is associated
+ // // with a question-mark.
+ // // indeed it might appear also behind a case statement, and we do
+ // // not to break at this point.
+ // if ((splitOperatorsCount == 0)
+ // || splitOperators[splitOperatorsCount - 1] != TokenName.QUESTION) {
+ // break;
+ // }
+ // case TokenName.extends :
+ // case TokenName.implements :
+ // //case TokenName.throws :
+ // case TokenName.DOT :
+ // // .
+ // case TokenName.MULTIPLY :
+ // // * (15.16.1)
+ // case TokenName.DIVIDE :
+ // // / (15.16.2)
+ // case TokenName.REMAINDER :
+ // // % (15.16.3)
+ // case TokenName.PLUS :
+ // // + (15.17, 15.17.2)
+ // case TokenName.MINUS :
+ // // - (15.17.2)
+ // case TokenName.LEFT_SHIFT :
+ // // << (15.18)
+ // case TokenName.RIGHT_SHIFT :
+ // // >> (15.18)
+ // // case TokenName.UNSIGNED_RIGHT_SHIFT : // >>> (15.18)
+ // case TokenName.LESS :
+ // // < (15.19.1)
+ // case TokenName.LESS_EQUAL :
+ // // <= (15.19.1)
+ // case TokenName.GREATER :
+ // // > (15.19.1)
+ // case TokenName.GREATER_EQUAL :
+ // // >= (15.19.1)
+ // // case TokenName.instanceof : // instanceof
+ // case TokenName.EQUAL_EQUAL :
+ // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+ // case TokenName.EQUAL_EQUAL_EQUAL :
+ // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
+ // case TokenName.NOT_EQUAL :
+ // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+ // case TokenName.NOT_EQUAL_EQUAL :
+ // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
+ // case TokenName.AND :
+ // // & (15.21, 15.21.1, 15.21.2)
+ // case TokenName.OR :
+ // // | (15.21, 15.21.1, 15.21.2)
+ // case TokenName.XOR :
+ // // ^ (15.21, 15.21.1, 15.21.2)
+ // case TokenName.AND_AND :
+ // // && (15.22)
+ // case TokenName.OR_OR :
+ // // || (15.23)
+ // case TokenName.QUESTION :
+ // // ? (15.24)
+ // case TokenName.MULTIPLY_EQUAL :
+ // // *= (15.25.2)
+ // case TokenName.DIVIDE_EQUAL :
+ // // /= (15.25.2)
+ // case TokenName.REMAINDER_EQUAL :
+ // // %= (15.25.2)
+ // case TokenName.PLUS_EQUAL :
+ // // += (15.25.2)
+ // case TokenName.MINUS_EQUAL :
+ // // -= (15.25.2)
+ // case TokenName.LEFT_SHIFT_EQUAL :
+ // // <<= (15.25.2)
+ // case TokenName.RIGHT_SHIFT_EQUAL :
+ // // >>= (15.25.2)
+ // // case TokenName.UNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
+ // case TokenName.AND_EQUAL :
+ // // &= (15.25.2)
+ // case TokenName.XOR_EQUAL :
+ // // ^= (15.25.2)
+ // case TokenName.OR_EQUAL :
+ // // |= (15.25.2)
+ // if ((openParenthesisPositionCount < splitTokenDepth ||
+ // (openParenthesisPositionCount == splitTokenDepth &&
+ // splitTokenPriority
+ // > getTokenPriority(currentToken)))
+ // && !((currentToken == TokenName.PLUS || currentToken ==
+ // TokenName.MINUS) && (previousToken == TokenName.LBRACE
+ // || previousToken == TokenName.LBRACKET || splitScanner.startPosition
+ // == 0))) {
+ // // the current token is better than the one we currently have
+ // // (in level or in priority if same level)
+ // // reset the substringsCount
+ // splitTokenDepth = openParenthesisPositionCount;
+ // splitTokenType = currentToken;
+ // splitTokenPriority = getTokenPriority(currentToken);
+ // substringsStartPositions[0] = 0;
+ // // better token means the whole line until now is the first
+ // // substring
+ // if (separateFirstArgumentOn(firstTokenOnLine)
+ // && openParenthesisPositionCount > 0) {
+ // substringsCount = 2; // resets the count of substrings
+ // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth -
+ // 1];
+ // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth
+ // - 1];
+ // substringsEndPositions[1] = splitScanner.startPosition;
+ // splitOperatorsCount = 3; // resets the count of split operators
+ // splitOperators[0] = 0;
+ // splitOperators[1] = 0;
+ // splitOperators[2] = currentToken;
+ // position = splitScanner.currentPosition;
+ // // next substring will start from operator end
+ // } else {
+ // substringsCount = 1; // resets the count of substrings
+ // substringsEndPositions[0] = splitScanner.startPosition;
+ // // substring ends on operator start
+ // position = splitScanner.currentPosition;
+ // // next substring will start from operator end
+ // splitOperatorsCount = 2; // resets the count of split operators
+ // splitOperators[0] = 0;
+ // // nothing for first operand since operator will be inserted in
+ // // front of the second operand
+ // splitOperators[1] = currentToken;
+ // }
+ // } else {
+ // if (openParenthesisPositionCount == splitTokenDepth
+ // && splitTokenPriority == getTokenPriority(currentToken)) {
+ // // if another token with the same priority is found,
+ // // push the start position of the substring and
+ // // push the token into the stack.
+ // // create a new array object if the current one is full.
+ // if (substringsCount == substringsStartPositions.length) {
+ // System
+ // .arraycopy(
+ // substringsStartPositions,
+ // 0,
+ // (substringsStartPositions = new int[substringsCount * 2]),
+ // 0, substringsCount);
+ // System.arraycopy(substringsEndPositions, 0,
+ // (substringsEndPositions = new int[substringsCount * 2]),
+ // 0, substringsCount);
+ // }
+ // if (splitOperatorsCount == splitOperators.length) {
+ // System.arraycopy(splitOperators, 0,
+ // (splitOperators = new int[splitOperatorsCount * 2]), 0,
+ // splitOperatorsCount);
+ // }
+ // substringsStartPositions[substringsCount] = position;
+ // substringsEndPositions[substringsCount++] =
+ // splitScanner.startPosition;
+ // // substring ends on operator start
+ // position = splitScanner.currentPosition;
+ // // next substring will start from operator end
+ // splitOperators[splitOperatorsCount++] = currentToken;
+ // }
+ // }
+ // default :
+ // break;
+ // }
+ // if (isComment(currentToken)) {
+ // lastCommentStartPosition = splitScanner.startPosition;
+ // } else {
+ // lastCommentStartPosition = -1;
+ // }
+ // }
+ // } catch (InvalidInputException e) {
+ // return null;
+ // }
+ // // if the string cannot be split, return null.
+ // if (splitOperatorsCount == 0)
+ // return null;
+ // // ## SPECIAL CASES BEGIN
+ // if (((splitOperatorsCount == 2 && splitOperators[1] == TokenName.DOT
+ // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1)
+ // || (splitOperatorsCount > 2 && splitOperators[1] == TokenName.DOT
+ // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1 &&
+ // lastOpenParenthesisPosition <= options.maxLineLength) ||
+ // (separateFirstArgumentOn(firstTokenOnLine)
+ // && splitTokenDepth > 0 && lastOpenParenthesisPosition > -1))
+ // && (lastOpenParenthesisPosition < splitScanner.source.length &&
+ // splitScanner.source[lastOpenParenthesisPosition] != ')')) {
+ // // fix for 1FH4J2H: LFCOM:WINNT - Formatter - Empty parenthesis
+ // should
+ // // not be broken on two lines
+ // // only one split on a top level .
+ // // or more than one split on . and substring before open parenthesis
+ // fits
+ // // one line.
+ // // or split inside parenthesis and first token is not a for/while/if
+ // SplitLine sl = split(
+ // stringToSplit.substring(lastOpenParenthesisPosition),
+ // lastOpenParenthesisPosition);
+ // if (sl == null || sl.operators[0] != TokenName.COMMA) {
+ // // trim() is used to remove the extra blanks at the end of the
+ // // substring. See PR 1FGYPI1
+ // return new SplitLine(new int[]{0, 0}, new String[]{
+ // stringToSplit.substring(0, lastOpenParenthesisPosition).trim(),
+ // stringToSplit.substring(lastOpenParenthesisPosition)}, new int[]{
+ // offsetInGlobalLine,
+ // lastOpenParenthesisPosition + offsetInGlobalLine});
+ // } else {
+ // // right substring can be split and is split on comma
+ // // copy substrings and operators
+ // // except if the 1st string is empty.
+ // int startIndex = (sl.substrings[0].length() == 0) ? 1 : 0;
+ // int subStringsLength = sl.substrings.length + 1 - startIndex;
+ // String[] result = new String[subStringsLength];
+ // int[] startIndexes = new int[subStringsLength];
+ // int operatorsLength = sl.operators.length + 1 - startIndex;
+ // int[] operators = new int[operatorsLength];
+ // result[0] = stringToSplit.substring(0, lastOpenParenthesisPosition);
+ // operators[0] = 0;
+ // System.arraycopy(sl.startSubstringsIndexes, startIndex, startIndexes,
+ // 1, subStringsLength - 1);
+ // for (int i = subStringsLength - 1; i >= 0; i--) {
+ // startIndexes[i] += offsetInGlobalLine;
+ // }
+ // System.arraycopy(sl.substrings, startIndex, result, 1,
+ // subStringsLength - 1);
+ // System.arraycopy(sl.operators, startIndex, operators, 1,
+ // operatorsLength - 1);
+ // return new SplitLine(operators, result, startIndexes);
+ // }
+ // }
+ // // if the last token is a comment and the substring before the
+ // comment fits
+ // // on a line,
+ // // split before the comment and return the result.
+ // if (lastCommentStartPosition > -1
+ // && lastCommentStartPosition < options.maxLineLength
+ // && splitTokenPriority > 50) {
+ // int end = lastCommentStartPosition;
+ // int start = lastCommentStartPosition;
+ // if (stringToSplit.charAt(end - 1) == ' ') {
+ // end--;
+ // }
+ // if (start != end && stringToSplit.charAt(start) == ' ') {
+ // start++;
+ // }
+ // return new SplitLine(new int[]{0, 0}, new String[]{
+ // stringToSplit.substring(0, end), stringToSplit.substring(start)},
+ // new int[]{0, start});
+ // }
+ // if (position != stringToSplit.length()) {
+ // if (substringsCount == substringsStartPositions.length) {
+ // System.arraycopy(substringsStartPositions, 0,
+ // (substringsStartPositions = new int[substringsCount * 2]), 0,
+ // substringsCount);
+ // System.arraycopy(substringsEndPositions, 0,
+ // (substringsEndPositions = new int[substringsCount * 2]), 0,
+ // substringsCount);
+ // }
+ // // avoid empty extra substring, e.g. line terminated with a
+ // semi-colon
+ // substringsStartPositions[substringsCount] = position;
+ // substringsEndPositions[substringsCount++] = stringToSplit.length();
+ // }
+ // if (splitOperatorsCount == splitOperators.length) {
+ // System.arraycopy(splitOperators, 0,
+ // (splitOperators = new int[splitOperatorsCount * 2]), 0,
+ // splitOperatorsCount);
+ // }
+ // splitOperators[splitOperatorsCount] = 0;
+ // // the last element of the stack is the position of the end of
+ // // StringToSPlit
+ // // +1 because the substring method excludes the last character
+ // String[] result = new String[substringsCount];
+ // for (int i = 0; i < substringsCount; i++) {
+ // int start = substringsStartPositions[i];
+ // int end = substringsEndPositions[i];
+ // if (stringToSplit.charAt(start) == ' ') {
+ // start++;
+ // substringsStartPositions[i]++;
+ // }
+ // if (end != start && stringToSplit.charAt(end - 1) == ' ') {
+ // end--;
+ // }
+ // result[i] = stringToSplit.substring(start, end);
+ // substringsStartPositions[i] += offsetInGlobalLine;
+ // }
+ // if (splitOperatorsCount > substringsCount) {
+ // System.arraycopy(substringsStartPositions, 0,
+ // (substringsStartPositions = new int[splitOperatorsCount]), 0,
+ // substringsCount);
+ // System.arraycopy(substringsEndPositions, 0,
+ // (substringsEndPositions = new int[splitOperatorsCount]), 0,
+ // substringsCount);
+ // for (int i = substringsCount; i < splitOperatorsCount; i++) {
+ // substringsStartPositions[i] = position;
+ // substringsEndPositions[i] = position;
+ // }
+ // System.arraycopy(splitOperators, 0,
+ // (splitOperators = new int[splitOperatorsCount]), 0,
+ // splitOperatorsCount);
+ // } else {
+ // System.arraycopy(substringsStartPositions, 0,
+ // (substringsStartPositions = new int[substringsCount]), 0,
+ // substringsCount);
+ // System.arraycopy(substringsEndPositions, 0,
+ // (substringsEndPositions = new int[substringsCount]), 0,
+ // substringsCount);
+ // System.arraycopy(splitOperators, 0,
+ // (splitOperators = new int[substringsCount]), 0, substringsCount);
+ // }
+ // SplitLine splitLine = new SplitLine(splitOperators, result,
+ // substringsStartPositions);
+ // return splitLine;
+ }
+
+ private void updateMappedPositions(int startPosition) {
+ if (positionsToMap == null) {
+ return;
+ }
+ char[] source = scanner.source;
+ int sourceLength = source.length;
+ while (indexToMap < positionsToMap.length
+ && positionsToMap[indexToMap] <= startPosition) {
+ int posToMap = positionsToMap[indexToMap];
+ if (posToMap < 0 || posToMap >= sourceLength) {
+ // protection against out of bounds position
+ if (posToMap == sourceLength) {
+ mappedPositions[indexToMap] = formattedSource.length();
+ }
+ indexToMap = positionsToMap.length; // no more mapping
+ return;
+ }
+ if (CharOperation.isWhitespace(source[posToMap])) {
+ mappedPositions[indexToMap] = startPosition + globalDelta
+ + lineDelta;
+ } else {
+ if (posToMap == sourceLength - 1) {
+ mappedPositions[indexToMap] = startPosition + globalDelta
+ + lineDelta;
+ } else {
+ mappedPositions[indexToMap] = posToMap + globalDelta
+ + lineDelta;
+ }
+ }
+ indexToMap++;
+ }
+ }
+
+ private void updateMappedPositionsWhileSplitting(int startPosition,
+ int endPosition) {
+ if (mappedPositions == null || mappedPositions.length == indexInMap)
+ return;
+ while (indexInMap < mappedPositions.length
+ && startPosition <= mappedPositions[indexInMap]
+ && mappedPositions[indexInMap] < endPosition
+ && indexInMap < indexToMap) {
+ mappedPositions[indexInMap] += splitDelta;
+ indexInMap++;
+ }
+ }
+
+ private int getLength(String s, int tabDepth) {
+ int length = 0;
+ for (int i = 0; i < tabDepth; i++) {
+ length += options.tabSize;
+ }
+ for (int i = 0, max = s.length(); i < max; i++) {
+ char currentChar = s.charAt(i);
+ switch (currentChar) {
+ case '\t':
+ length += options.tabSize;
+ break;
+ default:
+ length++;
+ }
+ }
+ return length;
+ }
+
+ /**
+ * Sets the initial indentation level
+ *
+ * @param indentationLevel
+ * new indentation level
+ *
+ * @deprecated
+ */
+ public void setInitialIndentationLevel(int newIndentationLevel) {
+ this.initialIndentationLevel = currentLineIndentationLevel = indentationLevel = newIndentationLevel;
+ }
}
\ No newline at end of file