1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
 
   3  * All rights reserved. This program and the accompanying materials
 
   4  * are made available under the terms of the Common Public License v0.5
 
   6  * which accompanies this distribution, and is available at
 
   7  * http://www.eclipse.org/legal/cpl-v05.html
 
  10  *     IBM Corporation - initial API and implementation
 
  11  ******************************************************************************/
 
  12 package net.sourceforge.phpdt.internal.formatter;
 
  14 import java.io.BufferedReader;
 
  15 import java.io.IOException;
 
  16 import java.io.StringReader;
 
  17 import java.util.Hashtable;
 
  18 import java.util.Locale;
 
  21 import javax.swing.text.html.Option;
 
  23 import net.sourceforge.phpdt.core.ICodeFormatter;
 
  24 import net.sourceforge.phpdt.core.compiler.CharOperation;
 
  25 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 
  26 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
 
  27 import net.sourceforge.phpdt.internal.compiler.ConfigurableOption;
 
  28 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
 
  29 import net.sourceforge.phpdt.internal.formatter.impl.FormatterOptions;
 
  30 import net.sourceforge.phpdt.internal.formatter.impl.SplitLine;
 
  33  * <h2>How to format a piece of code ?</h2>
 
  35  * <li>Create an instance of <code>CodeFormatter</code>
 
  36  * <li>Use the method <code>void format(aString)</code> on this instance to
 
  37  * format <code>aString</code>. It will return the formatted string.
 
  40 public class CodeFormatter implements ITerminalSymbols, ICodeFormatter {
 
  41         // IContentFormatterExtension {
 
  42         public FormatterOptions options;
 
  45          * Represents a block in the <code>constructions</code> stack.
 
  47         public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE;
 
  50          * Represents a block following a control statement in the
 
  51          * <code>constructions</code> stack.
 
  53         public static final int NONINDENT_BLOCK = -100;
 
  56          * Contains the formatted output.
 
  58         StringBuffer formattedSource;
 
  61          * Contains the current line. <br>
 
  62          * Will be dumped at the next "newline"
 
  64         StringBuffer currentLineBuffer;
 
  67          * Used during the formatting to get each token.
 
  72          * Contains the tokens responsible for the current indentation level and the
 
  73          * blocks not closed yet.
 
  75         private int[] constructions;
 
  78          * Index in the <code>constructions</code> array.
 
  80         private int constructionsCount;
 
  83          * Level of indentation of the current token (number of tab char put in
 
  86         private int indentationLevel;
 
  89          * Regular level of indentation of all the lines
 
  91         private int initialIndentationLevel;
 
  94          * Used to split a line.
 
  99          * To remember the offset between the beginning of the line and the
 
 100          * beginning of the comment.
 
 102         int currentCommentOffset;
 
 104         int currentLineIndentationLevel;
 
 106         int maxLineSize = 30;
 
 108         private boolean containsOpenCloseBraces;
 
 110         private int indentationLevelForOpenCloseBraces;
 
 113          * Collections of positions to map
 
 115         private int[] positionsToMap;
 
 118          * Collections of mapped positions
 
 120         private int[] mappedPositions;
 
 122         private int indexToMap;
 
 124         private int indexInMap;
 
 126         private int globalDelta;
 
 128         private int lineDelta;
 
 130         private int splitDelta;
 
 132         private int beginningOfLineIndex;
 
 134         private int multipleLineCommentCounter;
 
 137          * Creates a new instance of Code Formatter using the given settings.
 
 139          * @deprecated backport 1.0 internal functionality
 
 141         public CodeFormatter(ConfigurableOption[] settings) {
 
 142                 this(convertConfigurableOptions(settings));
 
 146          * Creates a new instance of Code Formatter using the FormattingOptions
 
 147          * object given as argument
 
 149          * @deprecated Use CodeFormatter(ConfigurableOption[]) instead
 
 151         public CodeFormatter() {
 
 156          * Creates a new instance of Code Formatter using the given settings.
 
 158         public CodeFormatter(Map settings) {
 
 159                 // initialize internal state
 
 160                 constructionsCount = 0;
 
 161                 constructions = new int[10];
 
 162                 currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
 
 163                 currentCommentOffset = -1;
 
 164                 // initialize primary and secondary scanners
 
 165                 scanner = new Scanner(true /* comment */
 
 166                 , true /* whitespace */
 
 169                 , true, /* tokenizeStrings */
 
 170                 null, null, true /* taskCaseSensitive */); // regular scanner for
 
 172                 scanner.recordLineSeparator = true;
 
 173                 scanner.ignorePHPOneLiner = true;
 
 174                 // to remind of the position of the beginning of the line.
 
 175                 splitScanner = new Scanner(true /* comment */
 
 176                 , true /* whitespace */
 
 179                 , true, /* tokenizeStrings */
 
 180                 null, null, true /* taskCaseSensitive */);
 
 181                 splitScanner.ignorePHPOneLiner = true;
 
 182                 // secondary scanner to split long lines formed by primary scanning
 
 183                 // initialize current line buffer
 
 184                 currentLineBuffer = new StringBuffer();
 
 185                 this.options = new FormatterOptions(settings);
 
 189          * Returns true if a lineSeparator has to be inserted before
 
 190          * <code>operator</code> false otherwise.
 
 192         private static boolean breakLineBeforeOperator(int operator) {
 
 195                 case TokenNameSEMICOLON:
 
 204          * @deprecated backport 1.0 internal functionality
 
 206         private static Map convertConfigurableOptions(ConfigurableOption[] settings) {
 
 207                 Hashtable options = new Hashtable(10);
 
 208                 for (int i = 0; i < settings.length; i++) {
 
 209                         if (settings[i].getComponentName().equals(
 
 210                                         CodeFormatter.class.getName())) {
 
 211                                 String optionName = settings[i].getOptionName();
 
 212                                 int valueIndex = settings[i].getCurrentValueIndex();
 
 213                                 if (optionName.equals("newline.openingBrace")) { //$NON-NLS-1$
 
 216                                                                         "net.sourceforge.phpdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 217                                 } else if (optionName.equals("newline.controlStatement")) { //$NON-NLS-1$
 
 220                                                                         "net.sourceforge.phpdt.core.formatter.newline.controlStatement", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 221                                 } else if (optionName.equals("newline.clearAll")) { //$NON-NLS-1$
 
 224                                                                         "net.sourceforge.phpdt.core.formatter.newline.clearAll", valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 225                                 } else if (optionName.equals("newline.elseIf")) { //$NON-NLS-1$
 
 228                                                                         "net.sourceforge.phpdt.core.formatter.newline.elseIf", valueIndex == 0 ? "do not insert" : "insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 229                                 } else if (optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$
 
 232                                                                         "net.sourceforge.phpdt.core.formatter.newline.emptyBlock", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 233                                 } else if (optionName.equals("lineSplit")) { //$NON-NLS-1$
 
 236                                                                         "net.sourceforge.phpdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
 
 237                                 } else if (optionName.equals("style.assignment")) { //$NON-NLS-1$
 
 240                                                                         "net.sourceforge.phpdt.core.formatter.style.assignment", valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 241                                 } else if (optionName.equals("tabulation.char")) { //$NON-NLS-1$
 
 244                                                                         "net.sourceforge.phpdt.core.formatter.tabulation.char", valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 245                                 } else if (optionName.equals("tabulation.size")) { //$NON-NLS-1$
 
 248                                                                         "net.sourceforge.phpdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
 
 256          * Returns the end of the source code.
 
 258         private final String copyRemainingSource() {
 
 259                 char str[] = scanner.source;
 
 260                 int startPosition = scanner.startPosition;
 
 261                 int length = str.length - startPosition;
 
 262                 StringBuffer bufr = new StringBuffer(length);
 
 263                 if (startPosition < str.length) {
 
 264                         bufr.append(str, startPosition, length);
 
 266                 return (bufr.toString());
 
 270          * Inserts <code>tabCount</code> tab character or their equivalent number
 
 273         private void dumpTab(int tabCount) {
 
 274                 if (options.indentWithTab) {
 
 275                         for (int j = 0; j < tabCount; j++) {
 
 276                                 formattedSource.append('\t');
 
 277                                 increaseSplitDelta(1);
 
 280                         for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
 
 281                                 formattedSource.append(' ');
 
 282                                 increaseSplitDelta(1);
 
 288          * Dumps <code>currentLineBuffer</code> into the formatted string.
 
 290         private void flushBuffer() {
 
 291                 String currentString = currentLineBuffer.toString();
 
 293                 beginningOfLineIndex = formattedSource.length();
 
 294                 if (containsOpenCloseBraces) {
 
 295                         containsOpenCloseBraces = false;
 
 296                         outputLine(currentString, false,
 
 297                                         indentationLevelForOpenCloseBraces, 0, -1, null, 0);
 
 298                         indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
 
 300                         outputLine(currentString, false, currentLineIndentationLevel, 0,
 
 303                 int scannerSourceLength = scanner.source.length;
 
 304                 if ((scannerSourceLength > 2)
 
 305                                 && (scanner.startPosition < scannerSourceLength)) {
 
 306                         if (scanner.source[scannerSourceLength - 1] == '\n'
 
 307                                         && scanner.source[scannerSourceLength - 2] == '\r') {
 
 308                                 formattedSource.append(options.lineSeparatorSequence);
 
 309                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
 
 310                         } else if (scanner.source[scannerSourceLength - 1] == '\n') {
 
 311                                 formattedSource.append(options.lineSeparatorSequence);
 
 312                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
 
 313                         } else if (scanner.source[scannerSourceLength - 1] == '\r') {
 
 314                                 formattedSource.append(options.lineSeparatorSequence);
 
 315                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
 
 318                 updateMappedPositions(scanner.startPosition);
 
 322          * Formats the input string.
 
 324         private void format() {
 
 326                 int previousToken = 0;
 
 327                 int previousCompilableToken = 0;
 
 328                 int indentationOffset = 0;
 
 329                 int newLinesInWhitespace = 0;
 
 330                 // number of new lines in the previous whitespace token
 
 331                 // (used to leave blank lines before comments)
 
 332                 int pendingNewLines = 0;
 
 333                 boolean expectingOpenBrace = false;
 
 334                 boolean clearNonBlockIndents = false;
 
 335                 // true if all indentations till the 1st { (usefull after } or ;)
 
 336                 boolean pendingSpace = true;
 
 337                 boolean pendingNewlineAfterParen = false;
 
 338                 // true when a cr is to be put after a ) (in conditional statements)
 
 339                 boolean inAssignment = false;
 
 340                 boolean inArrayAssignment = false;
 
 341                 boolean inThrowsClause = false;
 
 342                 boolean inClassOrInterfaceHeader = false;
 
 343                 int dollarBraceCount = 0;
 
 344                 // openBracketCount is used to count the number of open brackets not
 
 347                 int openBracketCount = 0;
 
 348                 int unarySignModifier = 0;
 
 349                 // openParenthesis[0] is used to count the parenthesis not belonging to
 
 352                 // (eg foo();). parenthesis in for (...) are count elsewhere in the
 
 354                 int openParenthesisCount = 1;
 
 355                 int[] openParenthesis = new int[10];
 
 356                 // tokenBeforeColon is used to know what token goes along with the
 
 359                 // it can be case or ?
 
 360                 int tokenBeforeColonCount = 0;
 
 361                 int[] tokenBeforeColon = new int[10];
 
 362                 constructionsCount = 0; // initializes the constructions count.
 
 363                 // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
 
 365                 // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and
 
 367                 boolean specialElse = false;
 
 368                 // OPTION (IndentationLevel): initial indentation level may be non-zero.
 
 369                 currentLineIndentationLevel += constructionsCount;
 
 370                 // An InvalidInputException exception might cause the termination of
 
 373                 int arrayDeclarationCount = 0;
 
 374                 int[] arrayDeclarationParenthesis = new int[10];
 
 377                                 // Get the next token. Catch invalid input and output it
 
 378                                 // with minimal formatting, also catch end of input and
 
 381                                         token = scanner.getNextToken();
 
 383                                                 int currentEndPosition = scanner
 
 384                                                                 .getCurrentTokenEndPosition();
 
 385                                                 int currentStartPosition = scanner
 
 386                                                                 .getCurrentTokenStartPosition();
 
 387                                                 System.out.print(currentStartPosition + ","
 
 388                                                                 + currentEndPosition + ": ");
 
 389                                                 System.out.println(scanner.toStringAction(token));
 
 391                                         // Patch for line comment
 
 392                                         // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=23096
 
 393                                         if (token == ITerminalSymbols.TokenNameCOMMENT_LINE) {
 
 394                                                 int length = scanner.currentPosition;
 
 395                                                 loop: for (int index = length - 1; index >= 0; index--) {
 
 396                                                         switch (scanner.source[index]) {
 
 399                                                                 scanner.currentPosition--;
 
 406                                 } catch (InvalidInputException e) {
 
 407                                         if (!handleInvalidToken(e)) {
 
 412                                 if (token == Scanner.TokenNameEOF) {
 
 414                                 } else if (token == Scanner.TokenNameHEREDOC) {
 
 415                                         // no indentation for heredocs and HTML !
 
 416                                         outputCurrentTokenWithoutIndent(Scanner.TokenNameHEREDOC, 0);
 
 418                                 } else if (token == Scanner.TokenNameINLINE_HTML) {
 
 419                                         // no indentation for heredocs and HTML !
 
 420                                         int newLineCount = 1;
 
 421                                         if (scanner.startPosition == 0) {
 
 424                                         outputCurrentTokenWithoutIndent(
 
 425                                                         Scanner.TokenNameINLINE_HTML, newLineCount);
 
 426                                         int srcLen = scanner.source.length;
 
 427                                         if (scanner.currentPosition < srcLen - 1) {
 
 433                                  * ## MODIFYING the indentation level before generating new
 
 434                                  * lines and indentation in the output string
 
 436                                 // Removes all the indentations made by statements not followed
 
 439                                 // except if the current token is ELSE, CATCH or if we are in a
 
 441                                 if (clearNonBlockIndents
 
 442                                                 && (token != Scanner.TokenNameWHITESPACE)) {
 
 445                                                 if (constructionsCount > 0
 
 446                                                                 && constructions[constructionsCount - 1] == TokenNameelse) {
 
 450                                                 indentationLevel += popInclusiveUntil(TokenNameif);
 
 452                                         // case TokenNamecatch :
 
 453                                         // indentationLevel += popInclusiveUntil(TokenNamecatch);
 
 455                                         // case TokenNamefinally :
 
 456                                         // indentationLevel += popInclusiveUntil(TokenNamecatch);
 
 459                                                 if (nlicsToken == TokenNamedo) {
 
 460                                                         indentationLevel += pop(TokenNamedo);
 
 464                                                 indentationLevel += popExclusiveUntilBlockOrCase();
 
 465                                                 // clear until a CASE, DEFAULT or BLOCK is encountered.
 
 466                                                 // Thus, the indentationLevel is correctly cleared
 
 468                                                 // in a switch/case statement or in any other situation.
 
 470                                         clearNonBlockIndents = false;
 
 472                                 // returns to the indentation level created by the SWITCH
 
 474                                 // if the current token is a CASE or a DEFAULT
 
 475                                 if (token == TokenNamecase || token == TokenNamedefault) {
 
 476                                         indentationLevel += pop(TokenNamecase);
 
 478                                 // if (token == Scanner.TokenNamethrows) {
 
 479                                 // inThrowsClause = true;
 
 481                                 if ((token == Scanner.TokenNameclass || token == Scanner.TokenNameinterface)
 
 482                                                 && previousToken != Scanner.TokenNameDOT) {
 
 483                                         inClassOrInterfaceHeader = true;
 
 486                                  * ## APPEND newlines and indentations to the output string
 
 488                                 // Do not add a new line between ELSE and IF, if the option
 
 489                                 // elseIfOnSameLine is true.
 
 490                                 // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
 
 491                                 // if (pendingNewlineAfterParen
 
 492                                 // && previousCompilableToken == TokenNameelse
 
 493                                 // && token == TokenNameif
 
 494                                 // && options.compactElseIfMode) {
 
 495                                 // pendingNewlineAfterParen = false;
 
 496                                 // pendingNewLines = 0;
 
 497                                 // indentationLevel += pop(TokenNameelse);
 
 498                                 // // because else if is now one single statement,
 
 499                                 // // the indentation level after it is increased by one and not
 
 501                                 // // (else = 1 indent, if = 1 indent, but else if = 1 indent,
 
 504                                 // Add a newline & indent to the formatted source string if
 
 505                                 // a for/if-else/while statement was scanned and there is no
 
 508                                 pendingNewlineAfterParen = pendingNewlineAfterParen
 
 509                                                 || (previousCompilableToken == TokenNameRPAREN && token == TokenNameLBRACE);
 
 510                                 if (pendingNewlineAfterParen
 
 511                                                 && token != Scanner.TokenNameWHITESPACE) {
 
 512                                         pendingNewlineAfterParen = false;
 
 513                                         // Do to add a newline & indent sequence if the current
 
 515                                         // open brace or a period or if the current token is a
 
 518                                         // previous token is a close paren.
 
 519                                         // add a new line if a parenthesis belonging to a for()
 
 521                                         // has been closed and the current token is not an opening
 
 523                                         if (token != TokenNameLBRACE && !isComment(token)
 
 524                                                         // to avoid adding new line between else and a
 
 526                                                         && token != TokenNameDOT
 
 527                                                         && !(previousCompilableToken == TokenNameRPAREN && token == TokenNameSEMICOLON)) {
 
 529                                                 currentLineIndentationLevel = indentationLevel;
 
 531                                                 pendingSpace = false;
 
 533                                                 if (token == TokenNameLBRACE
 
 534                                                                 && options.newLineBeforeOpeningBraceMode) {
 
 536                                                         if (constructionsCount > 0
 
 537                                                                         && constructions[constructionsCount - 1] != BLOCK
 
 538                                                                         && constructions[constructionsCount - 1] != NONINDENT_BLOCK) {
 
 539                                                                 currentLineIndentationLevel = indentationLevel - 1;
 
 541                                                                 currentLineIndentationLevel = indentationLevel;
 
 544                                                         pendingSpace = false;
 
 548                                 if (token == TokenNameLBRACE
 
 549                                                 && options.newLineBeforeOpeningBraceMode
 
 550                                                 && constructionsCount > 0
 
 551                                                 && constructions[constructionsCount - 1] == TokenNamedo) {
 
 553                                         currentLineIndentationLevel = indentationLevel - 1;
 
 555                                         pendingSpace = false;
 
 558                                 if (token == TokenNameLBRACE && inThrowsClause) {
 
 559                                         inThrowsClause = false;
 
 560                                         if (options.newLineBeforeOpeningBraceMode) {
 
 562                                                 currentLineIndentationLevel = indentationLevel;
 
 564                                                 pendingSpace = false;
 
 568                                 if (token == TokenNameLBRACE && inClassOrInterfaceHeader) {
 
 569                                         inClassOrInterfaceHeader = false;
 
 570                                         if (options.newLineBeforeOpeningBraceMode) {
 
 572                                                 currentLineIndentationLevel = indentationLevel;
 
 574                                                 pendingSpace = false;
 
 577                                 // don't linebreak empty array declarations
 
 578                                 if (token == TokenNameRPAREN && arrayDeclarationCount > 0) {
 
 579                                         if (previousCompilableToken == TokenNameLPAREN) {
 
 583                                 // Add pending new lines to the formatted source string.
 
 584                                 // Note: pending new lines are not added if the current token
 
 585                                 // is a single line comment or whitespace.
 
 586                                 // if the comment is between parenthesis, there is no blank line
 
 588                                 // (if it's a one-line comment, a blank line is added after it).
 
 589                                 if (((pendingNewLines > 0 && (!isComment(token)))
 
 590                                                 || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token)))
 
 591                                                 || (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE) || (newLinesInWhitespace > 0 && previousCompilableToken == TokenNameDOT))
 
 592                                                 && token != Scanner.TokenNameWHITESPACE) {
 
 593                                         // Do not add newline & indent between an adjoining close
 
 595                                         // close paren. Anonymous inner classes may use this form.
 
 596                                         boolean closeBraceAndCloseParen = previousToken == TokenNameRBRACE
 
 597                                                         && token == TokenNameRPAREN;
 
 598                                         // OPTION (NewLineInCompoundStatement): do not add newline &
 
 600                                         // between close brace and else, (do) while, catch, and
 
 602                                         // newlineInCompoundStatement is true.
 
 603                                         boolean nlicsOption = previousToken == TokenNameRBRACE
 
 604                                                         && !options.newlineInControlStatementMode
 
 605                                                         && (token == TokenNameelse
 
 606                                                                         || (token == TokenNamewhile && nlicsToken == TokenNamedo)
 
 607                                                                         || token == TokenNamecatch || token == TokenNamefinally);
 
 608                                         // Do not add a newline & indent between a close brace and
 
 610                                         boolean semiColonAndCloseBrace = previousToken == TokenNameRBRACE
 
 611                                                         && token == TokenNameSEMICOLON;
 
 612                                         // Do not add a new line & indent between a multiline
 
 615                                         boolean commentAndOpenBrace = previousToken == Scanner.TokenNameCOMMENT_BLOCK
 
 616                                                         && token == TokenNameLBRACE;
 
 617                                         // Do not add a newline & indent between a close brace and a
 
 619                                         // (in array assignments, for example).
 
 620                                         boolean commaAndCloseBrace = previousToken == TokenNameRBRACE
 
 621                                                         && token == TokenNameCOMMA;
 
 622                                         // Add a newline and indent, if appropriate.
 
 624                                                         || (!commentAndOpenBrace
 
 625                                                                         && !closeBraceAndCloseParen && !nlicsOption
 
 626                                                                         && !semiColonAndCloseBrace && !commaAndCloseBrace)) {
 
 627                                                 // if clearAllBlankLinesMode=false, leaves the blank
 
 629                                                 // inserted by the user
 
 630                                                 // if clearAllBlankLinesMode=true, removes all of then
 
 631                                                 // and insert only blank lines required by the
 
 633                                                 if (!options.clearAllBlankLinesMode) {
 
 634                                                         // (isComment(token))
 
 635                                                         pendingNewLines = (pendingNewLines < newLinesInWhitespace) ? newLinesInWhitespace
 
 637                                                         pendingNewLines = (pendingNewLines > 2) ? 2
 
 640                                                 if (previousCompilableToken == TokenNameLBRACE
 
 641                                                                 && token == TokenNameRBRACE) {
 
 642                                                         containsOpenCloseBraces = true;
 
 643                                                         indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
 
 644                                                         if (isComment(previousToken)) {
 
 645                                                                 newLine(pendingNewLines);
 
 648                                                                  * if (!(constructionsCount > 1 &&
 
 649                                                                  * constructions[constructionsCount-1] ==
 
 651                                                                  * (constructions[constructionsCount-2] ==
 
 654                                                                 if (options.newLineInEmptyBlockMode) {
 
 655                                                                         if (inArrayAssignment) {
 
 656                                                                                 newLine(1); // array assigment with an
 
 659                                                                                 newLine(pendingNewLines);
 
 665                                                         // see PR 1FKKC3U: LFCOM:WINNT - Format problem with
 
 668                                                         if (!((previousToken == Scanner.TokenNameCOMMENT_BLOCK || previousToken == Scanner.TokenNameCOMMENT_PHPDOC) && token == TokenNameSEMICOLON)) {
 
 669                                                                 newLine(pendingNewLines);
 
 672                                                 if (((previousCompilableToken == TokenNameSEMICOLON)
 
 673                                                                 || (previousCompilableToken == TokenNameLBRACE)
 
 674                                                                 || (previousCompilableToken == TokenNameRBRACE) || (isComment(previousToken)))
 
 675                                                                 && (token == TokenNameRBRACE)) {
 
 676                                                         indentationOffset = -1;
 
 677                                                         indentationLevel += popExclusiveUntilBlock();
 
 679                                                 if (previousToken == Scanner.TokenNameCOMMENT_LINE
 
 682                                                         currentLineIndentationLevel++;
 
 684                                                         currentLineIndentationLevel = indentationLevel
 
 687                                                 pendingSpace = false;
 
 688                                                 indentationOffset = 0;
 
 691                                         newLinesInWhitespace = 0;
 
 693                                         if (nlicsToken == TokenNamedo && token == TokenNamewhile) {
 
 697                                 boolean phpTagAndWhitespace = previousToken == TokenNameINLINE_HTML
 
 698                                                 && token == TokenNameWHITESPACE;
 
 700                                 // case TokenNameDOLLAR :
 
 701                                 // dollarBraceCount++;
 
 704                                         // case TokenNamefinally :
 
 705                                         expectingOpenBrace = true;
 
 706                                         pendingNewlineAfterParen = true;
 
 707                                         indentationLevel += pushControlStatement(token);
 
 710                                 case TokenNamedefault:
 
 711                                         if (tokenBeforeColonCount == tokenBeforeColon.length) {
 
 716                                                                                 (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
 
 717                                                                                 0, tokenBeforeColonCount);
 
 719                                         tokenBeforeColon[tokenBeforeColonCount++] = TokenNamecase;
 
 720                                         indentationLevel += pushControlStatement(TokenNamecase);
 
 722                                 case TokenNameQUESTION:
 
 723                                         if (tokenBeforeColonCount == tokenBeforeColon.length) {
 
 728                                                                                 (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
 
 729                                                                                 0, tokenBeforeColonCount);
 
 731                                         tokenBeforeColon[tokenBeforeColonCount++] = token;
 
 733                                 case TokenNameswitch:
 
 735                                 case TokenNameforeach:
 
 738                                         if (openParenthesisCount == openParenthesis.length) {
 
 743                                                                                 (openParenthesis = new int[openParenthesisCount * 2]),
 
 744                                                                                 0, openParenthesisCount);
 
 746                                         openParenthesis[openParenthesisCount++] = 0;
 
 747                                         expectingOpenBrace = true;
 
 748                                         indentationLevel += pushControlStatement(token);
 
 751                                         pendingNewlineAfterParen = true;
 
 753                                         // several CATCH statements can be contiguous.
 
 754                                         // a CATCH is encountered pop until first CATCH (if a CATCH
 
 755                                         // follows a TRY it works the same way,
 
 756                                         // as CATCH and TRY are the same token in the stack).
 
 757                                         expectingOpenBrace = true;
 
 758                                         indentationLevel += pushControlStatement(TokenNamecatch);
 
 761                                         expectingOpenBrace = true;
 
 762                                         indentationLevel += pushControlStatement(token);
 
 767                                 case TokenNameLPAREN:
 
 768                                         // if (previousToken == TokenNamesynchronized) {
 
 769                                         // indentationLevel += pushControlStatement(previousToken);
 
 771                                         // Put a space between the previous and current token if the
 
 772                                         // previous token was not a keyword, open paren, logical
 
 773                                         // compliment (eg: !), semi-colon, open brace, close brace,
 
 775                                         if (previousCompilableToken != TokenNameLBRACKET
 
 776                                                         && previousToken != TokenNameIdentifier
 
 777                                                         && previousToken != 0
 
 778                                                         && previousToken != TokenNameNOT
 
 779                                                         && previousToken != TokenNameLPAREN
 
 780                                                         && previousToken != TokenNameTWIDDLE
 
 781                                                         && previousToken != TokenNameSEMICOLON
 
 782                                                         && previousToken != TokenNameLBRACE
 
 783                                                         && previousToken != TokenNameRBRACE
 
 784                                                         && previousToken != TokenNamesuper) {
 
 785                                                 // && previousToken != TokenNamethis) {
 
 786                                                 if (!options.compactArrays) {
 
 790                                         // If in a for/if/while statement, increase the parenthesis
 
 792                                         // for the current openParenthesisCount
 
 793                                         // else increase the count for stand alone parenthesis.
 
 794                                         if (openParenthesisCount > 0)
 
 795                                                 openParenthesis[openParenthesisCount - 1]++;
 
 797                                                 openParenthesis[0]++;
 
 798                                         pendingSpace = false;
 
 799                                         // recognize array declaration for nice output
 
 800                                         if (previousCompilableToken == TokenNamearray) {
 
 801                                                 arrayDeclarationCount++;
 
 802                                                 arrayDeclarationParenthesis[arrayDeclarationCount] = openParenthesis[openParenthesisCount - 1];
 
 803                                                 if (!options.compactArrays) {
 
 810                                 case TokenNameRPAREN:
 
 811                                         // check for closing array declaration
 
 812                                         if (arrayDeclarationCount > 0) {
 
 813                                                 if (arrayDeclarationParenthesis[arrayDeclarationCount] == openParenthesis[openParenthesisCount - 1]) {
 
 814                                                         if (previousCompilableToken != TokenNameLPAREN) {
 
 815                                                                 if (!options.compactArrays) {
 
 818                                                         } else if (previousToken == TokenNameCOMMENT_LINE
 
 819                                                                         || previousToken == TokenNameCOMMENT_BLOCK
 
 820                                                                         || previousToken == TokenNameCOMMENT_PHPDOC) {
 
 821                                                                 // prevent to combine comment line and statement line (#1475484)
 
 822                                                                 if (!options.compactArrays) {
 
 826                                                         if (!options.compactArrays) {
 
 830                                                         currentLineIndentationLevel = indentationLevel;
 
 832                                                         arrayDeclarationCount--;
 
 835                                         // Decrease the parenthesis count
 
 836                                         // if there is no more unclosed parenthesis,
 
 837                                         // a new line and indent may be append (depending on the
 
 840                                         if ((openParenthesisCount > 1)
 
 841                                                         && (openParenthesis[openParenthesisCount - 1] > 0)) {
 
 842                                                 openParenthesis[openParenthesisCount - 1]--;
 
 843                                                 if (openParenthesis[openParenthesisCount - 1] <= 0) {
 
 844                                                         pendingNewlineAfterParen = true;
 
 845                                                         inAssignment = false;
 
 846                                                         openParenthesisCount--;
 
 849                                                 openParenthesis[0]--;
 
 851                                         pendingSpace = false;
 
 853                                 case TokenNameLBRACE:
 
 854                                         if (previousCompilableToken == TokenNameDOLLAR) {
 
 857                                                 if ((previousCompilableToken == TokenNameRBRACKET)
 
 858                                                                 || (previousCompilableToken == TokenNameEQUAL)) {
 
 859                                                         // if (previousCompilableToken == TokenNameRBRACKET)
 
 861                                                         inArrayAssignment = true;
 
 862                                                         inAssignment = false;
 
 864                                                 if (inArrayAssignment) {
 
 865                                                         indentationLevel += pushBlock();
 
 867                                                         // Add new line and increase indentation level after
 
 870                                                         indentationLevel += pushBlock();
 
 871                                                         inAssignment = false;
 
 875                                 case TokenNameRBRACE:
 
 876                                         if (dollarBraceCount > 0) {
 
 880                                         if (previousCompilableToken == TokenNameRPAREN) {
 
 881                                                 pendingSpace = false;
 
 883                                         if (inArrayAssignment) {
 
 884                                                 inArrayAssignment = false;
 
 886                                                 indentationLevel += popInclusiveUntilBlock();
 
 889                                                 indentationLevel += popInclusiveUntilBlock();
 
 890                                                 if (previousCompilableToken == TokenNameRPAREN) {
 
 891                                                         // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on
 
 895                                                                         .append(options.lineSeparatorSequence);
 
 896                                                         increaseLineDelta(options.lineSeparatorSequence.length);
 
 898                                                 if (constructionsCount > 0) {
 
 899                                                         switch (constructions[constructionsCount - 1]) {
 
 901                                                         case TokenNameforeach:
 
 902                                                                 // indentationLevel += popExclusiveUntilBlock();
 
 904                                                         case TokenNameswitch:
 
 909                                                         case TokenNamefinally:
 
 912                                                                 // case TokenNamesynchronized :
 
 913                                                                 clearNonBlockIndents = true;
 
 920                                 case TokenNameLBRACKET:
 
 922                                         pendingSpace = false;
 
 924                                 case TokenNameRBRACKET:
 
 925                                         openBracketCount -= (openBracketCount > 0) ? 1 : 0;
 
 926                                         // if there is no left bracket to close, the right bracket
 
 929                                         pendingSpace = false;
 
 932                                         pendingSpace = false;
 
 933                                         if (arrayDeclarationCount > 0) {
 
 934                                                 if (arrayDeclarationParenthesis[arrayDeclarationCount] == openParenthesis[openParenthesisCount - 1]) {
 
 935                                                         // there is no left parenthesis to close in current array declaration (#1475484)
 
 936                                                         if (!options.compactArrays) {
 
 943                                         if (!options.compactStringConcatenation) {
 
 946                                         pendingSpace = false;
 
 948                                 case TokenNameSEMICOLON:
 
 949                                         // Do not generate line terminators in the definition of
 
 950                                         // the for statement.
 
 951                                         // if not in this case, jump a line and reduce indentation
 
 954                                         // if the block it closes belongs to a conditional statement
 
 957                                         if (openParenthesisCount <= 1) {
 
 959                                                 if (expectingOpenBrace) {
 
 960                                                         clearNonBlockIndents = true;
 
 961                                                         expectingOpenBrace = false;
 
 964                                         inAssignment = false;
 
 965                                         pendingSpace = false;
 
 967                                 case TokenNamePLUS_PLUS:
 
 968                                 case TokenNameMINUS_MINUS:
 
 969                                         // Do not put a space between a post-increment/decrement
 
 970                                         // and the identifier being modified.
 
 971                                         if (previousToken == TokenNameIdentifier
 
 972                                                         || previousToken == TokenNameRBRACKET
 
 973                                                         || previousToken == TokenNameVariable) {
 
 974                                                 pendingSpace = false;
 
 978                                         // previously ADDITION
 
 980                                         // Handle the unary operators plus and minus via a flag
 
 981                                         if (!isLiteralToken(previousToken)
 
 982                                                         && previousToken != TokenNameIdentifier
 
 983                                                         && previousToken != TokenNameRPAREN
 
 984                                                         && previousToken != TokenNameRBRACKET) {
 
 985                                                 unarySignModifier = 1;
 
 989                                         // In a switch/case statement, add a newline & indent
 
 990                                         // when a colon is encountered.
 
 991                                         if (tokenBeforeColonCount > 0) {
 
 992                                                 if (tokenBeforeColon[tokenBeforeColonCount - 1] == TokenNamecase) {
 
 995                                                 tokenBeforeColonCount--;
 
1001                                 case Scanner.TokenNameCOMMENT_LINE:
 
1002                                         pendingNewLines = 1;
 
1003                                         //if (inAssignment) {
 
1004                                         //      currentLineIndentationLevel++;
 
1006                                         break; // a line is always inserted after a one-line
 
1008                                 case Scanner.TokenNameCOMMENT_PHPDOC:
 
1009                                 case Scanner.TokenNameCOMMENT_BLOCK:
 
1010                                         currentCommentOffset = getCurrentCommentOffset();
 
1011                                         pendingNewLines = 1;
 
1013                                 case Scanner.TokenNameWHITESPACE:
 
1014                                         if (!phpTagAndWhitespace) {
 
1015                                                 // Count the number of line terminators in the
 
1017                                                 // line spacing can be preserved near comments.
 
1018                                                 char[] source = scanner.source;
 
1019                                                 newLinesInWhitespace = 0;
 
1020                                                 for (int i = scanner.startPosition, max = scanner.currentPosition; i < max; i++) {
 
1021                                                         if (source[i] == '\r') {
 
1023                                                                         if (source[++i] == '\n') {
 
1024                                                                                 newLinesInWhitespace++;
 
1026                                                                                 newLinesInWhitespace++;
 
1029                                                                         newLinesInWhitespace++;
 
1031                                                         } else if (source[i] == '\n') {
 
1032                                                                 newLinesInWhitespace++;
 
1035                                                 increaseLineDelta(scanner.startPosition
 
1036                                                                 - scanner.currentPosition);
 
1039                                         // case TokenNameHTML :
 
1040                                         // // Add the next token to the formatted source string.
 
1041                                         // // outputCurrentToken(token);
 
1042                                         // int startPosition = scanner.startPosition;
 
1044                                         // for (int i = startPosition, max =
 
1045                                         // scanner.currentPosition; i <
 
1047                                         // char currentCharacter = scanner.source[i];
 
1048                                         // updateMappedPositions(i);
 
1049                                         // currentLineBuffer.append(currentCharacter);
 
1053                                         if ((token == TokenNameIdentifier) || isLiteralToken(token)
 
1054                                                         || token == TokenNamesuper) {
 
1055                                                 // || token == TokenNamethis) {
 
1056                                                 // Do not put a space between a unary operator
 
1057                                                 // (eg: ++, --, +, -) and the identifier being modified.
 
1058                                                 if (previousToken == TokenNamePLUS_PLUS
 
1059                                                                 || previousToken == TokenNameMINUS_MINUS
 
1060                                                                 || (previousToken == TokenNameMINUS_GREATER && options.compactDereferencingMode) // ->
 
1061                                                                 || (previousToken == TokenNamePLUS && unarySignModifier > 0)
 
1062                                                                 || (previousToken == TokenNameMINUS && unarySignModifier > 0)) {
 
1063                                                         pendingSpace = false;
 
1065                                                 unarySignModifier = 0;
 
1069                                 // Do not output whitespace tokens.
 
1070                                 if (token != Scanner.TokenNameWHITESPACE || phpTagAndWhitespace) {
 
1072                                          * Add pending space to the formatted source string. Do not
 
1073                                          * output a space under the following circumstances: 1) this
 
1074                                          * is the first pass 2) previous token is an open paren 3)
 
1075                                          * previous token is a period 4) previous token is the
 
1076                                          * logical compliment (eg: !) 5) previous token is the
 
1077                                          * bitwise compliment (eg: ~) 6) previous token is the open
 
1078                                          * bracket (eg: [) 7) in an assignment statement, if the
 
1079                                          * previous token is an open brace or the current token is a
 
1080                                          * close brace 8) previous token is a single line comment 9)
 
1081                                          * current token is a '->'
 
1083                                         if (token == TokenNameMINUS_GREATER
 
1084                                                         && options.compactDereferencingMode)
 
1085                                                 pendingSpace = false;
 
1087                                         boolean openAndCloseBrace = previousCompilableToken == TokenNameLBRACE
 
1088                                                         && token == TokenNameRBRACE;
 
1090                                                         && insertSpaceAfter(previousToken)
 
1091                                                         && !(inAssignment && (previousToken == TokenNameLBRACE || token == TokenNameRBRACE))
 
1092                                                         && previousToken != Scanner.TokenNameCOMMENT_LINE) {
 
1093                                                 if ((!(options.compactAssignmentMode && token == TokenNameEQUAL))
 
1094                                                                 && !openAndCloseBrace)
 
1097                                         // Add the next token to the formatted source string.
 
1098                                         outputCurrentToken(token);
 
1099                                         if (token == Scanner.TokenNameCOMMENT_LINE
 
1100                                                         && openParenthesisCount > 1) {
 
1101                                                 pendingNewLines = 0;
 
1102                                                 currentLineBuffer.append(options.lineSeparatorSequence);
 
1103                                                 increaseLineDelta(options.lineSeparatorSequence.length);
 
1105                                         pendingSpace = true;
 
1107                                 // Whitespace tokens do not need to be remembered.
 
1108                                 if (token != Scanner.TokenNameWHITESPACE || phpTagAndWhitespace) {
 
1109                                         previousToken = token;
 
1110                                         if (token != Scanner.TokenNameCOMMENT_BLOCK
 
1111                                                         && token != Scanner.TokenNameCOMMENT_LINE
 
1112                                                         && token != Scanner.TokenNameCOMMENT_PHPDOC) {
 
1113                                                 previousCompilableToken = token;
 
1117                         output(copyRemainingSource());
 
1119                         // dump the last token of the source in the formatted output.
 
1120                 } catch (InvalidInputException e) {
 
1121                         output(copyRemainingSource());
 
1123                         // dump the last token of the source in the formatted output.
 
1128          * Formats the char array <code>sourceString</code>, and returns a string
 
1129          * containing the formatted version.
 
1131          * @return the formatted ouput.
 
1133         public String formatSourceString(String sourceString) {
 
1134                 char[] sourceChars = sourceString.toCharArray();
 
1135                 formattedSource = new StringBuffer(sourceChars.length);
 
1136                 scanner.setSource(sourceChars);
 
1138                 return formattedSource.toString();
 
1142          * Formats the char array <code>sourceString</code>, and returns a string
 
1143          * containing the formatted version.
 
1146          *            the string to format
 
1147          * @param indentationLevel
 
1148          *            the initial indentation level
 
1149          * @return the formatted ouput.
 
1151         public String format(String string, int indentationLevel) {
 
1152                 return format(string, indentationLevel, (int[]) null);
 
1156          * Formats the char array <code>sourceString</code>, and returns a string
 
1157          * containing the formatted version. The positions array is modified to
 
1158          * contain the mapped positions.
 
1161          *            the string to format
 
1162          * @param indentationLevel
 
1163          *            the initial indentation level
 
1165          *            the array of positions to map
 
1166          * @return the formatted ouput.
 
1168         public String format(String string, int indentationLevel, int[] positions) {
 
1169                 return this.format(string, indentationLevel, positions, null);
 
1172         public String format(String string, int indentationLevel, int[] positions,
 
1173                         String lineSeparator) {
 
1174                 if (lineSeparator != null) {
 
1175                         this.options.setLineSeparator(lineSeparator);
 
1177                 if (positions != null) {
 
1178                         this.setPositionsToMap(positions);
 
1179                         this.setInitialIndentationLevel(indentationLevel);
 
1180                         String formattedString = this.formatSourceString(string);
 
1181                         int[] mappedPositions = this.getMappedPositions();
 
1183                                         .arraycopy(mappedPositions, 0, positions, 0,
 
1185                         return formattedString;
 
1187                         this.setInitialIndentationLevel(indentationLevel);
 
1188                         return this.formatSourceString(string);
 
1193          * Formats the char array <code>sourceString</code>, and returns a string
 
1194          * containing the formatted version. The initial indentation level is 0.
 
1197          *            the string to format
 
1198          * @return the formatted ouput.
 
1200         public String format(String string) {
 
1201                 return this.format(string, 0, (int[]) null);
 
1205          * Formats a given source string, starting indenting it at a particular
 
1206          * depth and using the given options
 
1208          * @deprecated backport 1.0 internal functionality
 
1210         public static String format(String sourceString,
 
1211                         int initialIndentationLevel, ConfigurableOption[] options) {
 
1212                 CodeFormatter formatter = new CodeFormatter(options);
 
1213                 formatter.setInitialIndentationLevel(initialIndentationLevel);
 
1214                 return formatter.formatSourceString(sourceString);
 
1218          * Returns the number of characters and tab char between the beginning of
 
1219          * the line and the beginning of the comment.
 
1221         private int getCurrentCommentOffset() {
 
1222                 int linePtr = scanner.linePtr;
 
1223                 // if there is no beginning of line, return 0.
 
1227                 int beginningOfLine = scanner.lineEnds[linePtr];
 
1228                 int currentStartPosition = scanner.startPosition;
 
1229                 char[] source = scanner.source;
 
1230                 // find the position of the beginning of the line containing the comment
 
1231                 while (beginningOfLine > currentStartPosition) {
 
1233                                 beginningOfLine = scanner.lineEnds[--linePtr];
 
1235                                 beginningOfLine = 0;
 
1239                 for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) {
 
1240                         char currentCharacter = source[i];
 
1241                         switch (currentCharacter) {
 
1243                                 offset += options.tabSize;
 
1259          * Returns an array of descriptions for the configurable options. The
 
1260          * descriptions may be changed and passed back to a different compiler.
 
1262          * @deprecated backport 1.0 internal functionality
 
1264         public static ConfigurableOption[] getDefaultOptions(Locale locale) {
 
1265                 String componentName = CodeFormatter.class.getName();
 
1266                 FormatterOptions options = new FormatterOptions();
 
1267                 return new ConfigurableOption[] {
 
1268                                 new ConfigurableOption(componentName, "newline.openingBrace",
 
1269                                                 locale, options.newLineBeforeOpeningBraceMode ? 0 : 1),
 
1271                                 new ConfigurableOption(componentName,
 
1272                                                 "newline.controlStatement", locale,
 
1273                                                 options.newlineInControlStatementMode ? 0 : 1),
 
1275                                 new ConfigurableOption(componentName, "newline.clearAll",
 
1276                                                 locale, options.clearAllBlankLinesMode ? 0 : 1),
 
1278                                 // new ConfigurableOption(componentName, "newline.elseIf",
 
1280                                 // options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$
 
1281                                 new ConfigurableOption(componentName, "newline.emptyBlock",
 
1282                                                 locale, options.newLineInEmptyBlockMode ? 0 : 1),
 
1284                                 new ConfigurableOption(componentName, "line.split", locale,
 
1285                                                 options.maxLineLength),
 
1287                                 new ConfigurableOption(componentName,
 
1288                                                 "style.compactAssignment", locale,
 
1289                                                 options.compactAssignmentMode ? 0 : 1),
 
1291                                 new ConfigurableOption(componentName, "tabulation.char",
 
1292                                                 locale, options.indentWithTab ? 0 : 1),
 
1294                                 new ConfigurableOption(componentName,
 
1295                                                 "tabulation.size", locale, options.tabSize) //$NON-NLS-1$
 
1300          * Returns the array of mapped positions. Returns null is no positions have
 
1304          * @deprecated There is no need to retrieve the mapped positions anymore.
 
1306         public int[] getMappedPositions() {
 
1307                 if (null != mappedPositions) {
 
1308                         for (int i = 0; i < mappedPositions.length; i++) {
 
1309                                 if (mappedPositions[i] >= formattedSource.length()) {
 
1310                                         mappedPositions[i] = formattedSource.length() - 1;
 
1314                 return mappedPositions;
 
1318          * Returns the priority of the token given as argument <br>
 
1319          * The most prioritary the token is, the smallest the return value is.
 
1321          * @return the priority of <code>token</code>
 
1323          *            the token of which the priority is requested
 
1325         private static int getTokenPriority(int token) {
 
1327                 case TokenNameextends:
 
1328                         // case TokenNameimplements :
 
1329                         // case TokenNamethrows :
 
1331                 case TokenNameSEMICOLON:
 
1334                 case TokenNameCOMMA:
 
1337                 case TokenNameEQUAL:
 
1340                 case TokenNameAND_AND:
 
1342                 case TokenNameOR_OR:
 
1345                 case TokenNameQUESTION:
 
1347                 case TokenNameCOLON:
 
1349                         return 50; // it's better cutting on ?: than on ;
 
1350                 case TokenNameEQUAL_EQUAL:
 
1352                 case TokenNameEQUAL_EQUAL_EQUAL:
 
1354                 case TokenNameNOT_EQUAL:
 
1356                 case TokenNameNOT_EQUAL_EQUAL:
 
1361                 case TokenNameLESS_EQUAL:
 
1363                 case TokenNameGREATER:
 
1365                 case TokenNameGREATER_EQUAL:
 
1367                         // case TokenNameinstanceof : // instanceof
 
1371                 case TokenNameMINUS:
 
1374                 case TokenNameMULTIPLY:
 
1376                 case TokenNameDIVIDE:
 
1378                 case TokenNameREMAINDER:
 
1381                 case TokenNameLEFT_SHIFT:
 
1383                 case TokenNameRIGHT_SHIFT:
 
1385                         // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>>
 
1394                 case TokenNameMULTIPLY_EQUAL:
 
1396                 case TokenNameDIVIDE_EQUAL:
 
1398                 case TokenNameREMAINDER_EQUAL:
 
1400                 case TokenNamePLUS_EQUAL:
 
1402                 case TokenNameMINUS_EQUAL:
 
1404                 case TokenNameLEFT_SHIFT_EQUAL:
 
1406                 case TokenNameRIGHT_SHIFT_EQUAL:
 
1408                         // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
 
1409                 case TokenNameAND_EQUAL:
 
1411                 case TokenNameXOR_EQUAL:
 
1413                 case TokenNameOR_EQUAL:
 
1415                 case TokenNameDOT_EQUAL:
 
1422                         return Integer.MAX_VALUE;
 
1427          * Handles the exception raised when an invalid token is encountered.
 
1428          * Returns true if the exception has been handled, false otherwise.
 
1430         private boolean handleInvalidToken(Exception e) {
 
1431                 if (e.getMessage().equals(Scanner.INVALID_CHARACTER_CONSTANT)
 
1432                                 || e.getMessage().equals(Scanner.INVALID_CHAR_IN_STRING)
 
1433                                 || e.getMessage().equals(Scanner.INVALID_ESCAPE)) {
 
1439         private final void increaseGlobalDelta(int offset) {
 
1440                 globalDelta += offset;
 
1443         private final void increaseLineDelta(int offset) {
 
1444                 lineDelta += offset;
 
1447         private final void increaseSplitDelta(int offset) {
 
1448                 splitDelta += offset;
 
1452          * Returns true if a space has to be inserted after <code>operator</code>
 
1455         private boolean insertSpaceAfter(int token) {
 
1457                 case TokenNameLPAREN:
 
1459                 case TokenNameTWIDDLE:
 
1462                 case TokenNameWHITESPACE:
 
1463                 case TokenNameLBRACKET:
 
1464                 case TokenNameDOLLAR:
 
1465                 case Scanner.TokenNameCOMMENT_LINE:
 
1468                         return !options.compactStringConcatenation;
 
1475          * Returns true if a space has to be inserted before <code>operator</code>
 
1476          * false otherwise. <br>
 
1477          * Cannot be static as it uses the code formatter options (to know if the
 
1478          * compact assignment mode is on).
 
1480         private boolean insertSpaceBefore(int token) {
 
1482                 case TokenNameEQUAL:
 
1483                         return (!options.compactAssignmentMode);
 
1489         private static boolean isComment(int token) {
 
1490                 boolean result = token == Scanner.TokenNameCOMMENT_BLOCK
 
1491                                 || token == Scanner.TokenNameCOMMENT_LINE
 
1492                                 || token == Scanner.TokenNameCOMMENT_PHPDOC;
 
1496         private static boolean isLiteralToken(int token) {
 
1497                 boolean result = token == TokenNameIntegerLiteral
 
1498                 // || token == TokenNameLongLiteral
 
1499                                 // || token == TokenNameFloatingPointLiteral
 
1500                                 || token == TokenNameDoubleLiteral
 
1501                                 // || token == TokenNameCharacterLiteral
 
1502                                 || token == TokenNameStringDoubleQuote;
 
1507          * If the length of <code>oneLineBuffer</code> exceeds
 
1508          * <code>maxLineLength</code>, it is split and the result is dumped in
 
1509          * <code>formattedSource</code>
 
1511          * @param newLineCount
 
1512          *            the number of new lines to append
 
1514         private void newLine(int newLineCount) {
 
1515                 // format current line
 
1517                 beginningOfLineIndex = formattedSource.length();
 
1518                 String currentLine = currentLineBuffer.toString();
 
1519                 if (containsOpenCloseBraces) {
 
1520                         containsOpenCloseBraces = false;
 
1521                         outputLine(currentLine, false, indentationLevelForOpenCloseBraces,
 
1523                         indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
 
1525                         outputLine(currentLine, false, currentLineIndentationLevel, 0, -1,
 
1528                 // dump line break(s)
 
1529                 for (int i = 0; i < newLineCount; i++) {
 
1530                         formattedSource.append(options.lineSeparatorSequence);
 
1531                         increaseSplitDelta(options.lineSeparatorSequence.length);
 
1533                 // reset formatter for next line
 
1534                 int currentLength = currentLine.length();
 
1535                 currentLineBuffer = new StringBuffer(
 
1536                                 currentLength > maxLineSize ? maxLineSize = currentLength
 
1538                 increaseGlobalDelta(splitDelta);
 
1539                 increaseGlobalDelta(lineDelta);
 
1541                 currentLineIndentationLevel = initialIndentationLevel;
 
1544         private String operatorString(int operator) {
 
1546                 case TokenNameextends:
 
1547                         return "extends"; //$NON-NLS-1$
 
1548                         // case TokenNameimplements :
 
1549                         // return "implements"; //$NON-NLS-1$
 
1551                         // case TokenNamethrows :
 
1552                         // return "throws"; //$NON-NLS-1$
 
1553                 case TokenNameSEMICOLON:
 
1555                         return ";"; //$NON-NLS-1$
 
1556                 case TokenNameCOMMA:
 
1558                         return ","; //$NON-NLS-1$
 
1559                 case TokenNameEQUAL:
 
1561                         return "="; //$NON-NLS-1$
 
1562                 case TokenNameAND_AND:
 
1564                         return "&&"; //$NON-NLS-1$
 
1565                 case TokenNameOR_OR:
 
1567                         return "||"; //$NON-NLS-1$
 
1568                 case TokenNameQUESTION:
 
1570                         return "?"; //$NON-NLS-1$
 
1571                 case TokenNameCOLON:
 
1573                         return ":"; //$NON-NLS-1$
 
1574                 case TokenNamePAAMAYIM_NEKUDOTAYIM:
 
1576                         return "::"; //$NON-NLS-1$
 
1577                 case TokenNameEQUAL_EQUAL:
 
1578                         // == (15.20, 15.20.1, 15.20.2, 15.20.3)
 
1579                         return "=="; //$NON-NLS-1$
 
1580                 case TokenNameEQUAL_EQUAL_EQUAL:
 
1581                         // == (15.20, 15.20.1, 15.20.2, 15.20.3)
 
1582                         return "==="; //$NON-NLS-1$
 
1583                 case TokenNameEQUAL_GREATER:
 
1585                         return "=>"; //$NON-NLS-1$
 
1586                 case TokenNameNOT_EQUAL:
 
1587                         // != (15.20, 15.20.1, 15.20.2, 15.20.3)
 
1588                         return "!="; //$NON-NLS-1$
 
1589                 case TokenNameNOT_EQUAL_EQUAL:
 
1590                         // != (15.20, 15.20.1, 15.20.2, 15.20.3)
 
1591                         return "!=="; //$NON-NLS-1$
 
1594                         return "<"; //$NON-NLS-1$
 
1595                 case TokenNameLESS_EQUAL:
 
1597                         return "<="; //$NON-NLS-1$
 
1598                 case TokenNameGREATER:
 
1600                         return ">"; //$NON-NLS-1$
 
1601                 case TokenNameGREATER_EQUAL:
 
1603                         return ">="; //$NON-NLS-1$
 
1604                         // case TokenNameinstanceof : // instanceof
 
1605                         // return "instanceof"; //$NON-NLS-1$
 
1607                         // + (15.17, 15.17.2)
 
1608                         return "+"; //$NON-NLS-1$
 
1609                 case TokenNameMINUS:
 
1611                         return "-"; //$NON-NLS-1$
 
1612                 case TokenNameMULTIPLY:
 
1614                         return "*"; //$NON-NLS-1$
 
1615                 case TokenNameDIVIDE:
 
1617                         return "/"; //$NON-NLS-1$
 
1618                 case TokenNameREMAINDER:
 
1620                         return "%"; //$NON-NLS-1$
 
1621                 case TokenNameLEFT_SHIFT:
 
1623                         return "<<"; //$NON-NLS-1$
 
1624                 case TokenNameRIGHT_SHIFT:
 
1626                         return ">>"; //$NON-NLS-1$
 
1627                         // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
 
1628                         // return ">>>"; //$NON-NLS-1$
 
1630                         // & (15.21, 15.21.1, 15.21.2)
 
1631                         return "&"; //$NON-NLS-1$
 
1633                         // | (15.21, 15.21.1, 15.21.2)
 
1634                         return "|"; //$NON-NLS-1$
 
1636                         // ^ (15.21, 15.21.1, 15.21.2)
 
1637                         return "^"; //$NON-NLS-1$
 
1638                 case TokenNameMULTIPLY_EQUAL:
 
1640                         return "*="; //$NON-NLS-1$
 
1641                 case TokenNameDIVIDE_EQUAL:
 
1643                         return "/="; //$NON-NLS-1$
 
1644                 case TokenNameREMAINDER_EQUAL:
 
1646                         return "%="; //$NON-NLS-1$
 
1647                 case TokenNamePLUS_EQUAL:
 
1649                         return "+="; //$NON-NLS-1$
 
1650                 case TokenNameMINUS_EQUAL:
 
1652                         return "-="; //$NON-NLS-1$
 
1653                 case TokenNameMINUS_GREATER:
 
1655                         return "->"; //$NON-NLS-1$
 
1656                 case TokenNameLEFT_SHIFT_EQUAL:
 
1658                         return "<<="; //$NON-NLS-1$
 
1659                 case TokenNameRIGHT_SHIFT_EQUAL:
 
1661                         return ">>="; //$NON-NLS-1$
 
1662                         // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
 
1663                         // return ">>>="; //$NON-NLS-1$
 
1664                 case TokenNameAND_EQUAL:
 
1666                         return "&="; //$NON-NLS-1$
 
1667                 case TokenNameXOR_EQUAL:
 
1669                         return "^="; //$NON-NLS-1$
 
1670                 case TokenNameOR_EQUAL:
 
1672                         return "|="; //$NON-NLS-1$
 
1673                 case TokenNameDOT_EQUAL:
 
1675                         return ".="; //$NON-NLS-1$
 
1678                         return "."; //$NON-NLS-1$
 
1680                         return ""; //$NON-NLS-1$
 
1685          * Appends <code>stringToOutput</code> to the formatted output. <br>
 
1686          * If it contains \n, append a LINE_SEPARATOR and indent after it.
 
1688         private void output(String stringToOutput) {
 
1689                 char currentCharacter;
 
1690                 for (int i = 0, max = stringToOutput.length(); i < max; i++) {
 
1691                         currentCharacter = stringToOutput.charAt(i);
 
1692                         if (currentCharacter != '\t') {
 
1693                                 currentLineBuffer.append(currentCharacter);
 
1698         private void outputCurrentTokenWithoutIndent(int token, int newLineCount) {
 
1699                 newLine(newLineCount);
 
1700                 formattedSource.append(scanner.source, scanner.startPosition,
 
1701                                 scanner.currentPosition - scanner.startPosition);
 
1705          * Appends <code>token</code> to the formatted output. <br>
 
1706          * If it contains <code>\n</code>, append a LINE_SEPARATOR and indent
 
1709         private void outputCurrentToken(int token) {
 
1710                 char[] source = scanner.source;
 
1711                 int startPosition = scanner.startPosition;
 
1713                 case Scanner.TokenNameCOMMENT_PHPDOC:
 
1714                 case Scanner.TokenNameCOMMENT_BLOCK:
 
1715                 case Scanner.TokenNameCOMMENT_LINE:
 
1716                         boolean endOfLine = false;
 
1717                         int currentCommentOffset = getCurrentCommentOffset();
 
1718                         int beginningOfLineSpaces = 0;
 
1720                         currentCommentOffset = getCurrentCommentOffset();
 
1721                         beginningOfLineSpaces = 0;
 
1722                         boolean pendingCarriageReturn = false;
 
1723                         for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
 
1724                                 char currentCharacter = source[i];
 
1725                                 updateMappedPositions(i);
 
1726                                 switch (currentCharacter) {
 
1728                                         pendingCarriageReturn = true;
 
1732                                         if (pendingCarriageReturn) {
 
1733                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
 
1735                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
 
1737                                         pendingCarriageReturn = false;
 
1738                                         currentLineBuffer.append(options.lineSeparatorSequence);
 
1739                                         beginningOfLineSpaces = 0;
 
1743                                         if (pendingCarriageReturn) {
 
1744                                                 pendingCarriageReturn = false;
 
1745                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
 
1746                                                 currentLineBuffer.append(options.lineSeparatorSequence);
 
1747                                                 beginningOfLineSpaces = 0;
 
1751                                                 // we remove a maximum of currentCommentOffset
 
1753                                                 // are converted to space numbers).
 
1754                                                 beginningOfLineSpaces += options.tabSize;
 
1755                                                 if (beginningOfLineSpaces > currentCommentOffset) {
 
1756                                                         currentLineBuffer.append(currentCharacter);
 
1758                                                         increaseGlobalDelta(-1);
 
1761                                                 currentLineBuffer.append(currentCharacter);
 
1765                                         if (pendingCarriageReturn) {
 
1766                                                 pendingCarriageReturn = false;
 
1767                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
 
1768                                                 currentLineBuffer.append(options.lineSeparatorSequence);
 
1769                                                 beginningOfLineSpaces = 0;
 
1773                                                 // we remove a maximum of currentCommentOffset
 
1775                                                 // are converted to space numbers).
 
1776                                                 beginningOfLineSpaces++;
 
1777                                                 if (beginningOfLineSpaces > currentCommentOffset) {
 
1778                                                         currentLineBuffer.append(currentCharacter);
 
1780                                                         increaseGlobalDelta(-1);
 
1783                                                 currentLineBuffer.append(currentCharacter);
 
1787                                         if (pendingCarriageReturn) {
 
1788                                                 pendingCarriageReturn = false;
 
1789                                                 increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
 
1790                                                 currentLineBuffer.append(options.lineSeparatorSequence);
 
1791                                                 beginningOfLineSpaces = 0;
 
1794                                                 beginningOfLineSpaces = 0;
 
1795                                                 currentLineBuffer.append(currentCharacter);
 
1800                         updateMappedPositions(scanner.currentPosition - 1);
 
1801                         multipleLineCommentCounter++;
 
1804                         for (int i = startPosition, max = scanner.currentPosition; i < max; i++) {
 
1805                                 char currentCharacter = source[i];
 
1806                                 updateMappedPositions(i);
 
1807                                 currentLineBuffer.append(currentCharacter);
 
1813          * Outputs <code>currentString</code>:<br>
 
1815          * <li>If its length is < maxLineLength, output
 
1816          * <li>Otherwise it is split.
 
1819          * @param currentString
 
1821          * @param preIndented
 
1822          *            whether the string to output was pre-indented
 
1824          *            number of indentation to put in front of
 
1825          *            <code>currentString</code>
 
1827          *            value of the operator belonging to <code>currentString</code>.
 
1829         private void outputLine(String currentString, boolean preIndented,
 
1830                         int depth, int operator, int substringIndex,
 
1831                         int[] startSubstringIndexes, int offsetInGlobalLine) {
 
1832                 boolean emptyFirstSubString = false;
 
1833                 String operatorString = operatorString(operator);
 
1834                 boolean placeOperatorBehind = !breakLineBeforeOperator(operator);
 
1835                 boolean placeOperatorAhead = !placeOperatorBehind;
 
1836                 // dump prefix operator?
 
1837                 if (placeOperatorAhead) {
 
1842                         if (operator != 0) {
 
1843                                 if (insertSpaceBefore(operator)) {
 
1844                                         formattedSource.append(' ');
 
1845                                         increaseSplitDelta(1);
 
1847                                 formattedSource.append(operatorString);
 
1848                                 increaseSplitDelta(operatorString.length());
 
1849                                 if (insertSpaceAfter(operator)
 
1850                                                 && operator != TokenNameimplements
 
1851                                                 && operator != TokenNameextends) {
 
1852                                         // && operator != TokenNamethrows) {
 
1853                                         formattedSource.append(' ');
 
1854                                         increaseSplitDelta(1);
 
1858                 SplitLine splitLine = null;
 
1859                 if (options.maxLineLength == 0
 
1860                                 || getLength(currentString, depth) < options.maxLineLength
 
1861                                 || (splitLine = split(currentString, offsetInGlobalLine)) == null) {
 
1862                         // depending on the type of operator, outputs new line before of
 
1865                         // indent before postfix operator
 
1866                         // indent also when the line cannot be split
 
1867                         if (operator == TokenNameextends || operator == TokenNameimplements) {
 
1868                                 // || operator == TokenNamethrows) {
 
1869                                 formattedSource.append(' ');
 
1870                                 increaseSplitDelta(1);
 
1872                         if (placeOperatorBehind) {
 
1877                         int max = currentString.length();
 
1878                         if (multipleLineCommentCounter != 0) {
 
1880                                         BufferedReader reader = new BufferedReader(
 
1881                                                         new StringReader(currentString));
 
1882                                         String line = reader.readLine();
 
1883                                         while (line != null) {
 
1884                                                 updateMappedPositionsWhileSplitting(
 
1885                                                                 beginningOfLineIndex, beginningOfLineIndex
 
1887                                                                                 + options.lineSeparatorSequence.length);
 
1888                                                 formattedSource.append(line);
 
1889                                                 beginningOfLineIndex = beginningOfLineIndex
 
1891                                                 if ((line = reader.readLine()) != null) {
 
1893                                                                         .append(options.lineSeparatorSequence);
 
1894                                                         beginningOfLineIndex += options.lineSeparatorSequence.length;
 
1895                                                         dumpTab(currentLineIndentationLevel);
 
1899                                 } catch (IOException e) {
 
1900                                         e.printStackTrace();
 
1903                                 updateMappedPositionsWhileSplitting(beginningOfLineIndex,
 
1904                                                 beginningOfLineIndex + max);
 
1905                                 for (int i = 0; i < max; i++) {
 
1906                                         char currentChar = currentString.charAt(i);
 
1907                                         switch (currentChar) {
 
1912                                                         // fix for 1FFYL5C: LFCOM:ALL - Incorrect
 
1914                                                         // split with a comment inside a condition
 
1915                                                         // a substring cannot end with a
 
1916                                                         // lineSeparatorSequence,
 
1917                                                         // except if it has been added by format() after a
 
1921                                                                         .append(options.lineSeparatorSequence);
 
1922                                                         // 1FGDDV6: LFCOM:WIN98 - Weird splitting on message
 
1928                                                 formattedSource.append(currentChar);
 
1932                         // update positions inside the mappedPositions table
 
1933                         if (substringIndex != -1) {
 
1934                                 if (multipleLineCommentCounter == 0) {
 
1935                                         int startPosition = beginningOfLineIndex
 
1936                                                         + startSubstringIndexes[substringIndex];
 
1937                                         updateMappedPositionsWhileSplitting(startPosition,
 
1938                                                         startPosition + max);
 
1940                                 // compute the splitDelta resulting with the operator and blank
 
1942                                 if (substringIndex + 1 != startSubstringIndexes.length) {
 
1943                                         increaseSplitDelta(startSubstringIndexes[substringIndex]
 
1944                                                         + max - startSubstringIndexes[substringIndex + 1]);
 
1947                         // dump postfix operator?
 
1948                         if (placeOperatorBehind) {
 
1949                                 if (insertSpaceBefore(operator)) {
 
1950                                         formattedSource.append(' ');
 
1951                                         if (operator != 0) {
 
1952                                                 increaseSplitDelta(1);
 
1955                                 formattedSource.append(operatorString);
 
1956                                 if (operator != 0) {
 
1957                                         increaseSplitDelta(operatorString.length());
 
1962                 // fix for 1FG0BA3: LFCOM:WIN98 - Weird splitting on interfaces
 
1963                 // extends has to stand alone on a line when currentString has been
 
1965                 if (options.maxLineLength != 0 && splitLine != null
 
1966                                 && (operator == TokenNameextends)) {
 
1967                         // || operator == TokenNameimplements
 
1968                         // || operator == TokenNamethrows)) {
 
1969                         formattedSource.append(options.lineSeparatorSequence);
 
1970                         increaseSplitDelta(options.lineSeparatorSequence.length);
 
1973                         if (operator == TokenNameextends) {
 
1974                                 // || operator == TokenNameimplements
 
1975                                 // || operator == TokenNamethrows) {
 
1976                                 formattedSource.append(' ');
 
1977                                 increaseSplitDelta(1);
 
1980                 // perform actual splitting
 
1981                 String result[] = splitLine.substrings;
 
1982                 int[] splitOperators = splitLine.operators;
 
1983                 if (result[0].length() == 0) {
 
1984                         // when the substring 0 is null, the substring 1 is correctly
 
1987                         emptyFirstSubString = true;
 
1989                 // the operator going in front of the result[0] string is the operator
 
1991                 for (int i = 0, max = result.length; i < max; i++) {
 
1992                         // the new depth is the current one if this is the first substring,
 
1993                         // the current one + 1 otherwise.
 
1994                         // if the substring is a comment, use the current indentation Level
 
1995                         // instead of the depth
 
1996                         // (-1 because the ouputline increases depth).
 
1997                         // (fix for 1FFC72R: LFCOM:ALL - Incorrect line split in presence of
 
2000                         String currentResult = result[i];
 
2001                         if (currentResult.length() != 0 || splitOperators[i] != 0) {
 
2002                                 int newDepth = (currentResult.startsWith("/*") //$NON-NLS-1$
 
2003                                 || currentResult.startsWith("//")) //$NON-NLS-1$
 
2004                                 ? indentationLevel - 1
 
2006                                 outputLine(currentResult, i == 0
 
2007                                                 || (i == 1 && emptyFirstSubString) ? preIndented
 
2008                                                 : false, i == 0 ? newDepth : newDepth + 1,
 
2009                                                 splitOperators[i], i, splitLine.startSubstringsIndexes,
 
2010                                                 currentString.indexOf(currentResult));
 
2012                                         formattedSource.append(options.lineSeparatorSequence);
 
2013                                         increaseSplitDelta(options.lineSeparatorSequence.length);
 
2017                 if (result.length == splitOperators.length - 1) {
 
2018                         int lastOperator = splitOperators[result.length];
 
2019                         String lastOperatorString = operatorString(lastOperator);
 
2020                         formattedSource.append(options.lineSeparatorSequence);
 
2021                         increaseSplitDelta(options.lineSeparatorSequence.length);
 
2022                         if (breakLineBeforeOperator(lastOperator)) {
 
2024                                 if (lastOperator != 0) {
 
2025                                         if (insertSpaceBefore(lastOperator)) {
 
2026                                                 formattedSource.append(' ');
 
2027                                                 increaseSplitDelta(1);
 
2029                                         formattedSource.append(lastOperatorString);
 
2030                                         increaseSplitDelta(lastOperatorString.length());
 
2031                                         if (insertSpaceAfter(lastOperator)
 
2032                                                         && lastOperator != TokenNameimplements
 
2033                                                         && lastOperator != TokenNameextends) {
 
2034                                                 // && lastOperator != TokenNamethrows) {
 
2035                                                 formattedSource.append(' ');
 
2036                                                 increaseSplitDelta(1);
 
2041                 if (placeOperatorBehind) {
 
2042                         if (insertSpaceBefore(operator)) {
 
2043                                 formattedSource.append(' ');
 
2044                                 increaseSplitDelta(1);
 
2046                         formattedSource.append(operatorString);
 
2047                         // increaseSplitDelta(operatorString.length());
 
2052          * Pops the top statement of the stack if it is <code>token</code>
 
2054         private int pop(int token) {
 
2056                 if ((constructionsCount > 0)
 
2057                                 && (constructions[constructionsCount - 1] == token)) {
 
2059                         constructionsCount--;
 
2065          * Pops the top statement of the stack if it is a <code>BLOCK</code> or a
 
2066          * <code>NONINDENT_BLOCK</code>.
 
2068         private int popBlock() {
 
2070                 if ((constructionsCount > 0)
 
2071                                 && ((constructions[constructionsCount - 1] == BLOCK) || (constructions[constructionsCount - 1] == NONINDENT_BLOCK))) {
 
2072                         if (constructions[constructionsCount - 1] == BLOCK)
 
2074                         constructionsCount--;
 
2080          * Pops elements until the stack is empty or the top element is
 
2081          * <code>token</code>.<br>
 
2082          * Does not remove <code>token</code> from the stack.
 
2085          *            the token to be left as the top of the stack
 
2087         private int popExclusiveUntil(int token) {
 
2089                 int startCount = constructionsCount;
 
2090                 for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
 
2091                         if (constructions[i] != NONINDENT_BLOCK)
 
2093                         constructionsCount--;
 
2099          * Pops elements until the stack is empty or the top element is a
 
2100          * <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
 
2101          * Does not remove it from the stack.
 
2103         private int popExclusiveUntilBlock() {
 
2104                 int startCount = constructionsCount;
 
2106                 for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK
 
2107                                 && constructions[i] != NONINDENT_BLOCK; i--) {
 
2108                         constructionsCount--;
 
2115          * Pops elements until the stack is empty or the top element is a
 
2116          * <code>BLOCK</code>, a <code>NONINDENT_BLOCK</code> or a
 
2117          * <code>CASE</code>.<br>
 
2118          * Does not remove it from the stack.
 
2120         private int popExclusiveUntilBlockOrCase() {
 
2121                 int startCount = constructionsCount;
 
2123                 for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK
 
2124                                 && constructions[i] != NONINDENT_BLOCK
 
2125                                 && constructions[i] != TokenNamecase; i--) {
 
2126                         constructionsCount--;
 
2133          * Pops elements until the stack is empty or the top element is
 
2134          * <code>token</code>.<br>
 
2135          * Removes <code>token</code> from the stack too.
 
2138          *            the token to remove from the stack
 
2140         private int popInclusiveUntil(int token) {
 
2141                 int startCount = constructionsCount;
 
2143                 for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) {
 
2144                         if (constructions[i] != NONINDENT_BLOCK)
 
2146                         constructionsCount--;
 
2148                 if (constructionsCount > 0) {
 
2149                         if (constructions[constructionsCount - 1] != NONINDENT_BLOCK)
 
2151                         constructionsCount--;
 
2157          * Pops elements until the stack is empty or the top element is a
 
2158          * <code>BLOCK</code> or a <code>NONINDENT_BLOCK</code>.<br>
 
2159          * Does not remove it from the stack.
 
2161         private int popInclusiveUntilBlock() {
 
2162                 int startCount = constructionsCount;
 
2164                 for (int i = startCount - 1; i >= 0
 
2165                                 && (constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK); i--) {
 
2167                         constructionsCount--;
 
2169                 if (constructionsCount > 0) {
 
2170                         if (constructions[constructionsCount - 1] == BLOCK)
 
2172                         constructionsCount--;
 
2178          * Pushes a block in the stack. <br>
 
2179          * Pushes a <code>BLOCK</code> if the stack is empty or if the top element
 
2180          * is a <code>BLOCK</code>, pushes <code>NONINDENT_BLOCK</code>
 
2181          * otherwise. Creates a new bigger array if the current one is full.
 
2183         private int pushBlock() {
 
2185                 if (constructionsCount == constructions.length)
 
2186                         System.arraycopy(constructions, 0,
 
2187                                         (constructions = new int[constructionsCount * 2]), 0,
 
2188                                         constructionsCount);
 
2189                 if ((constructionsCount == 0)
 
2190                                 || (constructions[constructionsCount - 1] == BLOCK)
 
2191                                 || (constructions[constructionsCount - 1] == NONINDENT_BLOCK)
 
2192                                 || (constructions[constructionsCount - 1] == TokenNamecase)) {
 
2194                         constructions[constructionsCount++] = BLOCK;
 
2196                         constructions[constructionsCount++] = NONINDENT_BLOCK;
 
2202          * Pushes <code>token</code>.<br>
 
2203          * Creates a new bigger array if the current one is full.
 
2205         private int pushControlStatement(int token) {
 
2206                 if (constructionsCount == constructions.length)
 
2207                         System.arraycopy(constructions, 0,
 
2208                                         (constructions = new int[constructionsCount * 2]), 0,
 
2209                                         constructionsCount);
 
2210                 constructions[constructionsCount++] = token;
 
2214         private static boolean separateFirstArgumentOn(int currentToken) {
 
2215                 // return (currentToken == TokenNameCOMMA || currentToken ==
 
2216                 // TokenNameSEMICOLON);
 
2217                 return currentToken != TokenNameif && currentToken != TokenNameLPAREN
 
2218                                 && currentToken != TokenNameNOT
 
2219                                 && currentToken != TokenNamewhile
 
2220                                 && currentToken != TokenNamefor
 
2221                                 && currentToken != TokenNameforeach
 
2222                                 && currentToken != TokenNameswitch;
 
2226          * Set the positions to map. The mapped positions should be retrieved using
 
2227          * the getMappedPositions() method.
 
2231          * @deprecated Set the positions to map using the format(String, int, int[])
 
2234          * @see #getMappedPositions()
 
2236         public void setPositionsToMap(int[] positions) {
 
2237                 positionsToMap = positions;
 
2240                 mappedPositions = new int[positions.length];
 
2244          * Appends a space character to the current line buffer.
 
2246         private void space() {
 
2247                 currentLineBuffer.append(' ');
 
2248                 increaseLineDelta(1);
 
2252          * Splits <code>stringToSplit</code> on the top level token <br>
 
2253          * If there are several identical token at the same level, the string is cut
 
2256          * @return an object containing the operator and all the substrings or null
 
2257          *         if the string cannot be split
 
2259         public SplitLine split(String stringToSplit) {
 
2260                 return split(stringToSplit, 0);
 
2264          * Splits <code>stringToSplit</code> on the top level token <br>
 
2265          * If there are several identical token at the same level, the string is cut
 
2268          * @return an object containing the operator and all the substrings or null
 
2269          *         if the string cannot be split
 
2271         public SplitLine split(String stringToSplit, int offsetInGlobalLine) {
 
2273                  * See http://dev.eclipse.org/bugs/show_bug.cgi?id=12540 and
 
2274                  * http://dev.eclipse.org/bugs/show_bug.cgi?id=14387
 
2276                 if (stringToSplit.indexOf("//$NON-NLS") != -1) { //$NON-NLS-1$
 
2279                 // split doesn't work correct for PHP
 
2282                 // int currentToken = 0;
 
2283                 // int splitTokenType = 0;
 
2284                 // int splitTokenDepth = Integer.MAX_VALUE;
 
2285                 // int splitTokenPriority = Integer.MAX_VALUE;
 
2286                 // int[] substringsStartPositions = new int[10];
 
2287                 // // contains the start position of substrings
 
2288                 // int[] substringsEndPositions = new int[10];
 
2289                 // // contains the start position of substrings
 
2290                 // int substringsCount = 1; // index in the substringsStartPosition
 
2292                 // int[] splitOperators = new int[10];
 
2293                 // // contains the start position of substrings
 
2294                 // int splitOperatorsCount = 0; // index in the substringsStartPosition
 
2296                 // int[] openParenthesisPosition = new int[10];
 
2297                 // int openParenthesisPositionCount = 0;
 
2298                 // int position = 0;
 
2299                 // int lastOpenParenthesisPosition = -1;
 
2300                 // // used to remember the position of the 1st open parenthesis
 
2301                 // // needed for a pattern like: A.B(C); we want formatted like A.B(
 
2303                 // // setup the scanner with a new source
 
2304                 // int lastCommentStartPosition = -1;
 
2305                 // // to remember the start position of the last comment
 
2306                 // int firstTokenOnLine = -1;
 
2307                 // // to remember the first token of the line
 
2308                 // int previousToken = -1;
 
2309                 // // to remember the previous token.
 
2310                 // splitScanner.setSource(stringToSplit.toCharArray());
 
2312                 // // start the loop
 
2314                 // // takes the next token
 
2316                 // if (currentToken != Scanner.TokenNameWHITESPACE)
 
2317                 // previousToken = currentToken;
 
2318                 // currentToken = splitScanner.getNextToken();
 
2319                 // if (Scanner.DEBUG) {
 
2320                 // int currentEndPosition = splitScanner.getCurrentTokenEndPosition();
 
2321                 // int currentStartPosition = splitScanner
 
2322                 // .getCurrentTokenStartPosition();
 
2323                 // System.out.print(currentStartPosition + "," + currentEndPosition
 
2325                 // System.out.println(scanner.toStringAction(currentToken));
 
2327                 // } catch (InvalidInputException e) {
 
2328                 // if (!handleInvalidToken(e))
 
2330                 // currentToken = 0;
 
2331                 // // this value is not modify when an exception is raised.
 
2333                 // if (currentToken == TokenNameEOF)
 
2335                 // if (firstTokenOnLine == -1) {
 
2336                 // firstTokenOnLine = currentToken;
 
2338                 // switch (currentToken) {
 
2339                 // case TokenNameRBRACE :
 
2340                 // case TokenNameRPAREN :
 
2341                 // if (openParenthesisPositionCount > 0) {
 
2342                 // if (openParenthesisPositionCount == 1
 
2343                 // && lastOpenParenthesisPosition < openParenthesisPosition[0]) {
 
2344                 // lastOpenParenthesisPosition = openParenthesisPosition[0];
 
2345                 // } else if ((splitTokenDepth == Integer.MAX_VALUE)
 
2346                 // || (splitTokenDepth > openParenthesisPositionCount &&
 
2347                 // openParenthesisPositionCount == 1)) {
 
2348                 // splitTokenType = 0;
 
2349                 // splitTokenDepth = openParenthesisPositionCount;
 
2350                 // splitTokenPriority = Integer.MAX_VALUE;
 
2351                 // substringsStartPositions[0] = 0;
 
2352                 // // better token means the whole line until now is the first
 
2354                 // substringsCount = 1; // resets the count of substrings
 
2355                 // substringsEndPositions[0] = openParenthesisPosition[0];
 
2356                 // // substring ends on operator start
 
2357                 // position = openParenthesisPosition[0];
 
2358                 // // the string mustn't be cut before the closing parenthesis but
 
2359                 // // after the opening one.
 
2360                 // splitOperatorsCount = 1; // resets the count of split operators
 
2361                 // splitOperators[0] = 0;
 
2363                 // openParenthesisPositionCount--;
 
2366                 // case TokenNameLBRACE :
 
2367                 // case TokenNameLPAREN :
 
2368                 // if (openParenthesisPositionCount == openParenthesisPosition.length) {
 
2371                 // openParenthesisPosition,
 
2373                 // (openParenthesisPosition = new int[openParenthesisPositionCount *
 
2375                 // 0, openParenthesisPositionCount);
 
2377                 // openParenthesisPosition[openParenthesisPositionCount++] =
 
2378                 // splitScanner.currentPosition;
 
2379                 // if (currentToken == TokenNameLPAREN
 
2380                 // && previousToken == TokenNameRPAREN) {
 
2381                 // openParenthesisPosition[openParenthesisPositionCount - 1] =
 
2382                 // splitScanner.startPosition;
 
2385                 // case TokenNameSEMICOLON :
 
2387                 // case TokenNameCOMMA :
 
2389                 // case TokenNameEQUAL :
 
2391                 // if (openParenthesisPositionCount < splitTokenDepth
 
2392                 // || (openParenthesisPositionCount == splitTokenDepth &&
 
2393                 // splitTokenPriority > getTokenPriority(currentToken))) {
 
2394                 // // the current token is better than the one we currently have
 
2395                 // // (in level or in priority if same level)
 
2396                 // // reset the substringsCount
 
2397                 // splitTokenDepth = openParenthesisPositionCount;
 
2398                 // splitTokenType = currentToken;
 
2399                 // splitTokenPriority = getTokenPriority(currentToken);
 
2400                 // substringsStartPositions[0] = 0;
 
2401                 // // better token means the whole line until now is the first
 
2403                 // if (separateFirstArgumentOn(firstTokenOnLine)
 
2404                 // && openParenthesisPositionCount > 0) {
 
2405                 // substringsCount = 2; // resets the count of substrings
 
2406                 // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth -
 
2408                 // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth
 
2410                 // substringsEndPositions[1] = splitScanner.startPosition;
 
2411                 // splitOperatorsCount = 2; // resets the count of split operators
 
2412                 // splitOperators[0] = 0;
 
2413                 // splitOperators[1] = currentToken;
 
2414                 // position = splitScanner.currentPosition;
 
2415                 // // next substring will start from operator end
 
2417                 // substringsCount = 1; // resets the count of substrings
 
2418                 // substringsEndPositions[0] = splitScanner.startPosition;
 
2419                 // // substring ends on operator start
 
2420                 // position = splitScanner.currentPosition;
 
2421                 // // next substring will start from operator end
 
2422                 // splitOperatorsCount = 1; // resets the count of split operators
 
2423                 // splitOperators[0] = currentToken;
 
2426                 // if ((openParenthesisPositionCount == splitTokenDepth &&
 
2427                 // splitTokenPriority == getTokenPriority(currentToken))
 
2428                 // && splitTokenType != TokenNameEQUAL
 
2429                 // && currentToken != TokenNameEQUAL) {
 
2430                 // // fix for 1FG0BCN: LFCOM:WIN98 - Missing one indentation after
 
2432                 // // take only the 1st = into account.
 
2433                 // // if another token with the same priority is found,
 
2434                 // // push the start position of the substring and
 
2435                 // // push the token into the stack.
 
2436                 // // create a new array object if the current one is full.
 
2437                 // if (substringsCount == substringsStartPositions.length) {
 
2440                 // substringsStartPositions,
 
2442                 // (substringsStartPositions = new int[substringsCount * 2]),
 
2443                 // 0, substringsCount);
 
2444                 // System.arraycopy(substringsEndPositions, 0,
 
2445                 // (substringsEndPositions = new int[substringsCount * 2]),
 
2446                 // 0, substringsCount);
 
2448                 // if (splitOperatorsCount == splitOperators.length) {
 
2449                 // System.arraycopy(splitOperators, 0,
 
2450                 // (splitOperators = new int[splitOperatorsCount * 2]), 0,
 
2451                 // splitOperatorsCount);
 
2453                 // substringsStartPositions[substringsCount] = position;
 
2454                 // substringsEndPositions[substringsCount++] =
 
2455                 // splitScanner.startPosition;
 
2456                 // // substring ends on operator start
 
2457                 // position = splitScanner.currentPosition;
 
2458                 // // next substring will start from operator end
 
2459                 // splitOperators[splitOperatorsCount++] = currentToken;
 
2463                 // case TokenNameCOLON :
 
2465                 // // see 1FK7C5R, we only split on a colon, when it is associated
 
2466                 // // with a question-mark.
 
2467                 // // indeed it might appear also behind a case statement, and we do
 
2468                 // // not to break at this point.
 
2469                 // if ((splitOperatorsCount == 0)
 
2470                 // || splitOperators[splitOperatorsCount - 1] != TokenNameQUESTION) {
 
2473                 // case TokenNameextends :
 
2474                 // case TokenNameimplements :
 
2475                 // //case TokenNamethrows :
 
2476                 // case TokenNameDOT :
 
2478                 // case TokenNameMULTIPLY :
 
2480                 // case TokenNameDIVIDE :
 
2482                 // case TokenNameREMAINDER :
 
2484                 // case TokenNamePLUS :
 
2485                 // // + (15.17, 15.17.2)
 
2486                 // case TokenNameMINUS :
 
2488                 // case TokenNameLEFT_SHIFT :
 
2490                 // case TokenNameRIGHT_SHIFT :
 
2492                 // // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18)
 
2493                 // case TokenNameLESS :
 
2495                 // case TokenNameLESS_EQUAL :
 
2497                 // case TokenNameGREATER :
 
2499                 // case TokenNameGREATER_EQUAL :
 
2501                 // // case TokenNameinstanceof : // instanceof
 
2502                 // case TokenNameEQUAL_EQUAL :
 
2503                 // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
 
2504                 // case TokenNameEQUAL_EQUAL_EQUAL :
 
2505                 // // == (15.20, 15.20.1, 15.20.2, 15.20.3)
 
2506                 // case TokenNameNOT_EQUAL :
 
2507                 // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
 
2508                 // case TokenNameNOT_EQUAL_EQUAL :
 
2509                 // // != (15.20, 15.20.1, 15.20.2, 15.20.3)
 
2510                 // case TokenNameAND :
 
2511                 // // & (15.21, 15.21.1, 15.21.2)
 
2512                 // case TokenNameOR :
 
2513                 // // | (15.21, 15.21.1, 15.21.2)
 
2514                 // case TokenNameXOR :
 
2515                 // // ^ (15.21, 15.21.1, 15.21.2)
 
2516                 // case TokenNameAND_AND :
 
2518                 // case TokenNameOR_OR :
 
2520                 // case TokenNameQUESTION :
 
2522                 // case TokenNameMULTIPLY_EQUAL :
 
2524                 // case TokenNameDIVIDE_EQUAL :
 
2526                 // case TokenNameREMAINDER_EQUAL :
 
2528                 // case TokenNamePLUS_EQUAL :
 
2530                 // case TokenNameMINUS_EQUAL :
 
2532                 // case TokenNameLEFT_SHIFT_EQUAL :
 
2534                 // case TokenNameRIGHT_SHIFT_EQUAL :
 
2536                 // // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2)
 
2537                 // case TokenNameAND_EQUAL :
 
2539                 // case TokenNameXOR_EQUAL :
 
2541                 // case TokenNameOR_EQUAL :
 
2543                 // if ((openParenthesisPositionCount < splitTokenDepth ||
 
2544                 // (openParenthesisPositionCount == splitTokenDepth &&
 
2545                 // splitTokenPriority
 
2546                 // > getTokenPriority(currentToken)))
 
2547                 // && !((currentToken == TokenNamePLUS || currentToken ==
 
2548                 // TokenNameMINUS) && (previousToken == TokenNameLBRACE
 
2549                 // || previousToken == TokenNameLBRACKET || splitScanner.startPosition
 
2551                 // // the current token is better than the one we currently have
 
2552                 // // (in level or in priority if same level)
 
2553                 // // reset the substringsCount
 
2554                 // splitTokenDepth = openParenthesisPositionCount;
 
2555                 // splitTokenType = currentToken;
 
2556                 // splitTokenPriority = getTokenPriority(currentToken);
 
2557                 // substringsStartPositions[0] = 0;
 
2558                 // // better token means the whole line until now is the first
 
2560                 // if (separateFirstArgumentOn(firstTokenOnLine)
 
2561                 // && openParenthesisPositionCount > 0) {
 
2562                 // substringsCount = 2; // resets the count of substrings
 
2563                 // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth -
 
2565                 // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth
 
2567                 // substringsEndPositions[1] = splitScanner.startPosition;
 
2568                 // splitOperatorsCount = 3; // resets the count of split operators
 
2569                 // splitOperators[0] = 0;
 
2570                 // splitOperators[1] = 0;
 
2571                 // splitOperators[2] = currentToken;
 
2572                 // position = splitScanner.currentPosition;
 
2573                 // // next substring will start from operator end
 
2575                 // substringsCount = 1; // resets the count of substrings
 
2576                 // substringsEndPositions[0] = splitScanner.startPosition;
 
2577                 // // substring ends on operator start
 
2578                 // position = splitScanner.currentPosition;
 
2579                 // // next substring will start from operator end
 
2580                 // splitOperatorsCount = 2; // resets the count of split operators
 
2581                 // splitOperators[0] = 0;
 
2582                 // // nothing for first operand since operator will be inserted in
 
2583                 // // front of the second operand
 
2584                 // splitOperators[1] = currentToken;
 
2587                 // if (openParenthesisPositionCount == splitTokenDepth
 
2588                 // && splitTokenPriority == getTokenPriority(currentToken)) {
 
2589                 // // if another token with the same priority is found,
 
2590                 // // push the start position of the substring and
 
2591                 // // push the token into the stack.
 
2592                 // // create a new array object if the current one is full.
 
2593                 // if (substringsCount == substringsStartPositions.length) {
 
2596                 // substringsStartPositions,
 
2598                 // (substringsStartPositions = new int[substringsCount * 2]),
 
2599                 // 0, substringsCount);
 
2600                 // System.arraycopy(substringsEndPositions, 0,
 
2601                 // (substringsEndPositions = new int[substringsCount * 2]),
 
2602                 // 0, substringsCount);
 
2604                 // if (splitOperatorsCount == splitOperators.length) {
 
2605                 // System.arraycopy(splitOperators, 0,
 
2606                 // (splitOperators = new int[splitOperatorsCount * 2]), 0,
 
2607                 // splitOperatorsCount);
 
2609                 // substringsStartPositions[substringsCount] = position;
 
2610                 // substringsEndPositions[substringsCount++] =
 
2611                 // splitScanner.startPosition;
 
2612                 // // substring ends on operator start
 
2613                 // position = splitScanner.currentPosition;
 
2614                 // // next substring will start from operator end
 
2615                 // splitOperators[splitOperatorsCount++] = currentToken;
 
2621                 // if (isComment(currentToken)) {
 
2622                 // lastCommentStartPosition = splitScanner.startPosition;
 
2624                 // lastCommentStartPosition = -1;
 
2627                 // } catch (InvalidInputException e) {
 
2630                 // // if the string cannot be split, return null.
 
2631                 // if (splitOperatorsCount == 0)
 
2633                 // // ## SPECIAL CASES BEGIN
 
2634                 // if (((splitOperatorsCount == 2 && splitOperators[1] == TokenNameDOT
 
2635                 // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1)
 
2636                 // || (splitOperatorsCount > 2 && splitOperators[1] == TokenNameDOT
 
2637                 // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1 &&
 
2638                 // lastOpenParenthesisPosition <= options.maxLineLength) ||
 
2639                 // (separateFirstArgumentOn(firstTokenOnLine)
 
2640                 // && splitTokenDepth > 0 && lastOpenParenthesisPosition > -1))
 
2641                 // && (lastOpenParenthesisPosition < splitScanner.source.length &&
 
2642                 // splitScanner.source[lastOpenParenthesisPosition] != ')')) {
 
2643                 // // fix for 1FH4J2H: LFCOM:WINNT - Formatter - Empty parenthesis
 
2645                 // // not be broken on two lines
 
2646                 // // only one split on a top level .
 
2647                 // // or more than one split on . and substring before open parenthesis
 
2650                 // // or split inside parenthesis and first token is not a for/while/if
 
2651                 // SplitLine sl = split(
 
2652                 // stringToSplit.substring(lastOpenParenthesisPosition),
 
2653                 // lastOpenParenthesisPosition);
 
2654                 // if (sl == null || sl.operators[0] != TokenNameCOMMA) {
 
2655                 // // trim() is used to remove the extra blanks at the end of the
 
2656                 // // substring. See PR 1FGYPI1
 
2657                 // return new SplitLine(new int[]{0, 0}, new String[]{
 
2658                 // stringToSplit.substring(0, lastOpenParenthesisPosition).trim(),
 
2659                 // stringToSplit.substring(lastOpenParenthesisPosition)}, new int[]{
 
2660                 // offsetInGlobalLine,
 
2661                 // lastOpenParenthesisPosition + offsetInGlobalLine});
 
2663                 // // right substring can be split and is split on comma
 
2664                 // // copy substrings and operators
 
2665                 // // except if the 1st string is empty.
 
2666                 // int startIndex = (sl.substrings[0].length() == 0) ? 1 : 0;
 
2667                 // int subStringsLength = sl.substrings.length + 1 - startIndex;
 
2668                 // String[] result = new String[subStringsLength];
 
2669                 // int[] startIndexes = new int[subStringsLength];
 
2670                 // int operatorsLength = sl.operators.length + 1 - startIndex;
 
2671                 // int[] operators = new int[operatorsLength];
 
2672                 // result[0] = stringToSplit.substring(0, lastOpenParenthesisPosition);
 
2673                 // operators[0] = 0;
 
2674                 // System.arraycopy(sl.startSubstringsIndexes, startIndex, startIndexes,
 
2675                 // 1, subStringsLength - 1);
 
2676                 // for (int i = subStringsLength - 1; i >= 0; i--) {
 
2677                 // startIndexes[i] += offsetInGlobalLine;
 
2679                 // System.arraycopy(sl.substrings, startIndex, result, 1,
 
2680                 // subStringsLength - 1);
 
2681                 // System.arraycopy(sl.operators, startIndex, operators, 1,
 
2682                 // operatorsLength - 1);
 
2683                 // return new SplitLine(operators, result, startIndexes);
 
2686                 // // if the last token is a comment and the substring before the
 
2689                 // // split before the comment and return the result.
 
2690                 // if (lastCommentStartPosition > -1
 
2691                 // && lastCommentStartPosition < options.maxLineLength
 
2692                 // && splitTokenPriority > 50) {
 
2693                 // int end = lastCommentStartPosition;
 
2694                 // int start = lastCommentStartPosition;
 
2695                 // if (stringToSplit.charAt(end - 1) == ' ') {
 
2698                 // if (start != end && stringToSplit.charAt(start) == ' ') {
 
2701                 // return new SplitLine(new int[]{0, 0}, new String[]{
 
2702                 // stringToSplit.substring(0, end), stringToSplit.substring(start)},
 
2703                 // new int[]{0, start});
 
2705                 // if (position != stringToSplit.length()) {
 
2706                 // if (substringsCount == substringsStartPositions.length) {
 
2707                 // System.arraycopy(substringsStartPositions, 0,
 
2708                 // (substringsStartPositions = new int[substringsCount * 2]), 0,
 
2709                 // substringsCount);
 
2710                 // System.arraycopy(substringsEndPositions, 0,
 
2711                 // (substringsEndPositions = new int[substringsCount * 2]), 0,
 
2712                 // substringsCount);
 
2714                 // // avoid empty extra substring, e.g. line terminated with a
 
2716                 // substringsStartPositions[substringsCount] = position;
 
2717                 // substringsEndPositions[substringsCount++] = stringToSplit.length();
 
2719                 // if (splitOperatorsCount == splitOperators.length) {
 
2720                 // System.arraycopy(splitOperators, 0,
 
2721                 // (splitOperators = new int[splitOperatorsCount * 2]), 0,
 
2722                 // splitOperatorsCount);
 
2724                 // splitOperators[splitOperatorsCount] = 0;
 
2725                 // // the last element of the stack is the position of the end of
 
2727                 // // +1 because the substring method excludes the last character
 
2728                 // String[] result = new String[substringsCount];
 
2729                 // for (int i = 0; i < substringsCount; i++) {
 
2730                 // int start = substringsStartPositions[i];
 
2731                 // int end = substringsEndPositions[i];
 
2732                 // if (stringToSplit.charAt(start) == ' ') {
 
2734                 // substringsStartPositions[i]++;
 
2736                 // if (end != start && stringToSplit.charAt(end - 1) == ' ') {
 
2739                 // result[i] = stringToSplit.substring(start, end);
 
2740                 // substringsStartPositions[i] += offsetInGlobalLine;
 
2742                 // if (splitOperatorsCount > substringsCount) {
 
2743                 // System.arraycopy(substringsStartPositions, 0,
 
2744                 // (substringsStartPositions = new int[splitOperatorsCount]), 0,
 
2745                 // substringsCount);
 
2746                 // System.arraycopy(substringsEndPositions, 0,
 
2747                 // (substringsEndPositions = new int[splitOperatorsCount]), 0,
 
2748                 // substringsCount);
 
2749                 // for (int i = substringsCount; i < splitOperatorsCount; i++) {
 
2750                 // substringsStartPositions[i] = position;
 
2751                 // substringsEndPositions[i] = position;
 
2753                 // System.arraycopy(splitOperators, 0,
 
2754                 // (splitOperators = new int[splitOperatorsCount]), 0,
 
2755                 // splitOperatorsCount);
 
2757                 // System.arraycopy(substringsStartPositions, 0,
 
2758                 // (substringsStartPositions = new int[substringsCount]), 0,
 
2759                 // substringsCount);
 
2760                 // System.arraycopy(substringsEndPositions, 0,
 
2761                 // (substringsEndPositions = new int[substringsCount]), 0,
 
2762                 // substringsCount);
 
2763                 // System.arraycopy(splitOperators, 0,
 
2764                 // (splitOperators = new int[substringsCount]), 0, substringsCount);
 
2766                 // SplitLine splitLine = new SplitLine(splitOperators, result,
 
2767                 // substringsStartPositions);
 
2768                 // return splitLine;
 
2771         private void updateMappedPositions(int startPosition) {
 
2772                 if (positionsToMap == null) {
 
2775                 char[] source = scanner.source;
 
2776                 int sourceLength = source.length;
 
2777                 while (indexToMap < positionsToMap.length
 
2778                                 && positionsToMap[indexToMap] <= startPosition) {
 
2779                         int posToMap = positionsToMap[indexToMap];
 
2780                         if (posToMap < 0 || posToMap >= sourceLength) {
 
2781                                 // protection against out of bounds position
 
2782                                 if (posToMap == sourceLength) {
 
2783                                         mappedPositions[indexToMap] = formattedSource.length();
 
2785                                 indexToMap = positionsToMap.length; // no more mapping
 
2788                         if (CharOperation.isWhitespace(source[posToMap])) {
 
2789                                 mappedPositions[indexToMap] = startPosition + globalDelta
 
2792                                 if (posToMap == sourceLength - 1) {
 
2793                                         mappedPositions[indexToMap] = startPosition + globalDelta
 
2796                                         mappedPositions[indexToMap] = posToMap + globalDelta
 
2804         private void updateMappedPositionsWhileSplitting(int startPosition,
 
2806                 if (mappedPositions == null || mappedPositions.length == indexInMap)
 
2808                 while (indexInMap < mappedPositions.length
 
2809                                 && startPosition <= mappedPositions[indexInMap]
 
2810                                 && mappedPositions[indexInMap] < endPosition
 
2811                                 && indexInMap < indexToMap) {
 
2812                         mappedPositions[indexInMap] += splitDelta;
 
2817         private int getLength(String s, int tabDepth) {
 
2819                 for (int i = 0; i < tabDepth; i++) {
 
2820                         length += options.tabSize;
 
2822                 for (int i = 0, max = s.length(); i < max; i++) {
 
2823                         char currentChar = s.charAt(i);
 
2824                         switch (currentChar) {
 
2826                                 length += options.tabSize;
 
2836          * Sets the initial indentation level
 
2838          * @param indentationLevel
 
2839          *            new indentation level
 
2843         public void setInitialIndentationLevel(int newIndentationLevel) {
 
2844                 this.initialIndentationLevel = currentLineIndentationLevel = indentationLevel = newIndentationLevel;