X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/CodeFormatter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/CodeFormatter.java index e4ec3cf..4d7ed3e 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/CodeFormatter.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/CodeFormatter.java @@ -1,36 +1,34 @@ /******************************************************************************* * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v0.5 + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v05.html - * + * * Contributors: * IBM Corporation - initial API and implementation ******************************************************************************/ package net.sourceforge.phpdt.internal.formatter; + import java.io.BufferedReader; 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; import net.sourceforge.phpdt.core.compiler.InvalidInputException; import net.sourceforge.phpdt.internal.compiler.ConfigurableOption; import net.sourceforge.phpdt.internal.compiler.parser.Scanner; -import net.sourceforge.phpdt.internal.corext.codemanipulation.StubUtility; -import net.sourceforge.phpdt.internal.corext.util.Strings; import net.sourceforge.phpdt.internal.formatter.impl.FormatterOptions; import net.sourceforge.phpdt.internal.formatter.impl.SplitLine; -import net.sourceforge.phpdt.internal.ui.preferences.CodeFormatterPreferencePage; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.formatter.IContentFormatterExtension; -import org.eclipse.jface.text.formatter.IFormattingContext; /** *

How to format a piece of code ?

* */ public class CodeFormatter implements ITerminalSymbols, ICodeFormatter { - // IContentFormatterExtension { - public FormatterOptions options; - /** - * Represents a block in the constructions stack. - */ - public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE; - /** - * Represents a block following a control statement in the constructions - * stack. - */ - public static final int NONINDENT_BLOCK = -100; - /** - * Contains the formatted output. - */ - StringBuffer formattedSource; - /** - * Contains the current line.
- * 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 constructions 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); // regular scanner for forming lines - scanner.recordLineSeparator = 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); - // 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 operator - * 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 tabCount 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 currentLineBuffer 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) { - 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. - 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; - /* - * ## 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 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; - //S } - break; - case TokenNameRPAREN : - // 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 : - //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 : - 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) { - 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 sourceString, 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 sourceString, 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 sourceString, 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 sourceString, 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
- * The most prioritary the token is, the smallest the return value is. - * - * @return the priority of token - * @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 : - // |= - 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 operator - * 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 operator - * false otherwise.
- * 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 oneLineBuffer exceeds maxLineLength, - * it is split and the result is dumped in formattedSource - * - * @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 : - // . - return "."; //$NON-NLS-1$ - default : - return ""; //$NON-NLS-1$ - } - } - /** - * Appends stringToOutput to the formatted output.
- * 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); - } - } - } - /** - * Appends token to the formatted output.
- * If it contains \n, 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 currentString:
- * - * - * @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 currentString - * @param operator - * value of the operator belonging to currentString. - */ - 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 token - */ - 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 BLOCK or a - * NONINDENT_BLOCK. - */ - 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 token. - *
- * Does not remove token 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 BLOCK - * or a NONINDENT_BLOCK.
- * 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 BLOCK, - * a NONINDENT_BLOCK or a CASE.
- * 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 token. - *
- * Removes token 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 BLOCK - * or a NONINDENT_BLOCK.
- * 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.
- * Pushes a BLOCK if the stack is empty or if the top element - * is a BLOCK, pushes NONINDENT_BLOCK - * 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 token.
- * 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 != 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 stringToSplit on the top level token
- * 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 stringToSplit on the top level token
- * 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(); - } - 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; - } - + // IContentFormatterExtension { + public FormatterOptions options; + + /** + * Represents a block in the constructions stack. + */ + public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE; + + /** + * Represents a block following a control statement in the + * constructions stack. + */ + public static final int NONINDENT_BLOCK = -100; + + /** + * Contains the formatted output. + */ + StringBuffer formattedSource; + + /** + * Contains the current line.
+ * 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 constructions 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 + * operator 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 tabCount 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 currentLineBuffer 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; + } + } + // don't linebreak empty array declarations + if (token == TokenNameRPAREN && arrayDeclarationCount > 0) { + if (previousCompilableToken == TokenNameLPAREN) { + 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 == TokenNameLBRACE && token == TokenNameRBRACE) || (newLinesInWhitespace > 0 && previousCompilableToken == TokenNameDOT)) + && 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) { + 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 == TokenNamearray) { + arrayDeclarationCount++; + arrayDeclarationParenthesis[arrayDeclarationCount] = openParenthesis[openParenthesisCount - 1]; + if (!options.compactArrays) { + indentationLevel++; + pendingNewLines = 1; + } + } + // S } + break; + case TokenNameRPAREN: + // check for closing array declaration + if (arrayDeclarationCount > 0) { + if (arrayDeclarationParenthesis[arrayDeclarationCount] == openParenthesis[openParenthesisCount - 1]) { + if (previousCompilableToken != TokenNameLPAREN) { + if (!options.compactArrays) { + newLine(1); + } + } else if (previousToken == TokenNameCOMMENT_LINE + || previousToken == TokenNameCOMMENT_BLOCK + || previousToken == TokenNameCOMMENT_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 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(); + inAssignment = false; + } + } + 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) { + 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 TokenNameDOT: + if (!options.compactStringConcatenation) { + space(); + } + 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 sourceString, 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 sourceString, 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 sourceString, 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 sourceString, 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
+ * The most prioritary the token is, the smallest the return value is. + * + * @return the priority of token + * @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 operator + * false otherwise. + */ + private boolean insertSpaceAfter(int token) { + switch (token) { + case TokenNameLPAREN: + case TokenNameNOT: + case TokenNameTWIDDLE: + case 0: + // no token + case TokenNameWHITESPACE: + case TokenNameLBRACKET: + case TokenNameDOLLAR: + case Scanner.TokenNameCOMMENT_LINE: + return false; + case TokenNameDOT: + return !options.compactStringConcatenation; + default: + return true; + } + } + + /** + * Returns true if a space has to be inserted before operator + * false otherwise.
+ * 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 oneLineBuffer exceeds + * maxLineLength, it is split and the result is dumped in + * formattedSource + * + * @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 stringToOutput to the formatted output.
+ * 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 token to the formatted output.
+ * If it contains \n, 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 currentString:
+ * + * + * @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 + * currentString + * @param operator + * value of the operator belonging to currentString. + */ + 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 token + */ + 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 BLOCK or a + * NONINDENT_BLOCK. + */ +// 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 + * token.
+ * Does not remove token 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 + * BLOCK or a NONINDENT_BLOCK.
+ * 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 + * BLOCK, a NONINDENT_BLOCK or a + * CASE.
+ * 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 + * token.
+ * Removes token 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 + * BLOCK or a NONINDENT_BLOCK.
+ * 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.
+ * Pushes a BLOCK if the stack is empty or if the top element + * is a BLOCK, pushes NONINDENT_BLOCK + * 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 token.
+ * 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 stringToSplit on the top level token
+ * 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 stringToSplit on the top level token
+ * 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(); + } + 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