Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/port80/eclipse/util/JavaCodeFormatter.java


1   /**
2    * Modifed from org.eclipse.jdt.internal.formatter.CodeFormatter.
3    * . But don't add space after '#'.
4    * . Has a custom default format options.
5    * . Clear line buffer before format so that formatter can be reused to format another string.
6    */
7   package com.port80.eclipse.util;
8   
9   import java.io.BufferedReader;
10  import java.io.IOException;
11  import java.io.StringReader;
12  import java.util.HashMap;
13  import java.util.Hashtable;
14  import java.util.Locale;
15  import java.util.Map;
16  
17  import org.eclipse.jdt.core.ICodeFormatter;
18  import org.eclipse.jdt.core.compiler.ITerminalSymbols;
19  import org.eclipse.jdt.core.compiler.InvalidInputException;
20  import org.eclipse.jdt.internal.compiler.ConfigurableOption;
21  import org.eclipse.jdt.internal.formatter.impl.FormatterOptions;
22  import org.eclipse.jdt.internal.formatter.impl.SplitLine;
23  
24  /** <h2>How to format a piece of code ?</h2>
25   * <ul><li>Create an instance of <code>CodeFormatter</code>
26   * <li>Use the method <code>void format(aString)</code>
27   * on this instance to format <code>aString</code>.
28   * It will return the formatted string.</ul>
29  */
30  public class JavaCodeFormatter implements IJavaCodeSymbol, ICodeFormatter, ICodeFragmentFormatter {
31  
32    ////////////////////////////////////////////////////////////////////////
33  
34    private static final int DEFAULT_LINEWIDTH = 80;
35    private static final int DEFAULT_TABWIDTH = 8;
36    private static final Map DEFAULT_OPTIONS = new HashMap();
37    static {
38      DEFAULT_OPTIONS.put(FormatterOptions.OPTION_InsertNewLineInEmptyBlock, FormatterOptions.DO_NOT_INSERT);
39      DEFAULT_OPTIONS.put(FormatterOptions.OPTION_CompactAssignment, FormatterOptions.NORMAL);
40      DEFAULT_OPTIONS.put(FormatterOptions.OPTION_TabulationSize, String.valueOf(DEFAULT_TABWIDTH));
41      DEFAULT_OPTIONS.put(
42        FormatterOptions.OPTION_SplitLineExceedingLength,
43        String.valueOf(DEFAULT_LINEWIDTH));
44    }
45  
46    ////////////////////////////////////////////////////////////////////////
47  
48    public JavaCodeFormatter() {
49      this(DEFAULT_OPTIONS);
50    }
51  
52    public JavaCodeFormatter(int linewidth, int tabwidth) {
53      this(DEFAULT_OPTIONS);
54      init(linewidth, tabwidth);
55    }
56  
57    public JavaCodeFormatter(int linewidth, int tabwidth, boolean with_preprocessor) {
58      this(DEFAULT_OPTIONS);
59      init(linewidth, tabwidth);
60      withPreprocessor = with_preprocessor;
61    }
62  
63    public void init(int linewidth, int tabwidth) {
64      Map opts = new HashMap(DEFAULT_OPTIONS);
65      opts.put(FormatterOptions.OPTION_SplitLineExceedingLength, String.valueOf(linewidth));
66      opts.put(FormatterOptions.OPTION_TabulationSize, String.valueOf(tabwidth));
67      this.options = new FormatterOptions(opts);
68    }
69  
70    public int getIndentLevel() {
71      return indentationLevel;
72    }
73    
74    ////////////////////////////////////////////////////////////////////////
75  
76    public FormatterOptions options;
77  
78    /** 
79     * Represents a block in the <code>constructions</code> stack.
80     */
81    public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE;
82  
83    /** 
84     * Represents a block following a control statement in the <code>constructions</code> stack.
85     */
86    public static final int NONINDENT_BLOCK = -100;
87  
88    /** 
89     * Contains the formatted output.
90     */
91    StringBuffer formattedSource;
92  
93    /** 
94     * Contains the current line.<br>
95     * Will be dumped at the next "newline"
96     */
97    StringBuffer currentLineBuffer;
98  
99    /** 
100    * Used during the formatting to get each token.
101    */
102   JavaCodeScanner scanner;
103 
104   /** 
105    * Contains the tokens responsible for the current indentation level
106    * and the blocks not closed yet.
107    */
108   private int[] constructions;
109 
110   /** 
111    * Index in the <code>constructions</code> array.
112    */
113   private int constructionsCount;
114 
115   /** 
116    * Level of indentation of the current token (number of tab char put in front of it).
117    */
118   private int indentationLevel;
119 
120   /** 
121    * Regular level of indentation of all the lines
122    */
123   private int initialIndentationLevel;
124 
125   /** 
126    * Used to split a line.
127    */
128   JavaCodeScanner splitScanner;
129 
130   /** 
131    * To remember the offset between the beginning of the line and the
132    * beginning of the comment.
133    */
134   int currentCommentOffset;
135   int currentLineIndentationLevel;
136   int maxLineSize = 30;
137   private boolean containsOpenCloseBraces;
138   private int indentationLevelForOpenCloseBraces;
139 
140   /**
141    * Collections of positions to map
142    */
143   private int[] positionsToMap;
144 
145   /**
146    * Collections of mapped positions
147    */
148   private int[] mappedPositions;
149 
150   private int indexToMap;
151 
152   private int indexInMap;
153 
154   private int globalDelta;
155 
156   private int lineDelta;
157 
158   private int splitDelta;
159 
160   private int beginningOfLineIndex;
161 
162   private int multipleLineCommentCounter;
163 
164   private boolean withPreprocessor;
165   private boolean isPreprocessor;
166 
167   /** 
168    * Creates a new instance of Code Formatter using the given settings.
169    * 
170    * @deprecated backport 1.0 internal functionality
171    */
172   public JavaCodeFormatter(ConfigurableOption[] settings) {
173     this(convertConfigurableOptions(settings));
174   }
175 
176   //  /** 
177   //   * Creates a new instance of Code Formatter using the FormattingOptions object
178   //   * given as argument
179   //   * @deprecated Use JavaCodeFormatter(ConfigurableOption[]) instead
180   //   */
181   //  public JavaCodeFormatter() {
182   //    this((Map) null);
183   //  }
184 
185   /** 
186    * Creates a new instance of Code Formatter using the given settings.
187    */
188   public JavaCodeFormatter(Map settings) {
189     this(settings, false);
190   }
191 
192   public JavaCodeFormatter(Map settings, boolean with_preprocessor) {
193     withPreprocessor = with_preprocessor;
194     // initialize internal state
195     constructionsCount = 0;
196     constructions = new int[10];
197     currentLineIndentationLevel = indentationLevel = initialIndentationLevel;
198     currentCommentOffset = -1;
199 
200     // initialize primary and secondary scanners
201     scanner = new JavaCodeScanner(true, true); // regular scanner for forming lines
202     scanner.recordLineSeparator = true;
203     // to remind of the position of the beginning of the line.
204     splitScanner = new JavaCodeScanner(true, true);
205     // secondary scanner to split long lines formed by primary scanning
206 
207     // initialize current line buffer
208     currentLineBuffer = new StringBuffer();
209     this.options = new FormatterOptions(settings);
210   }
211 
212   /**
213    * Returns true if a lineSeparator has to be inserted before <code>operator</code>
214    * false otherwise.
215    */
216   private static boolean breakLineBeforeOperator(int operator) {
217     switch (operator) {
218       case TokenNameCOMMA :
219       case TokenNameSEMICOLON :
220       case TokenNameEQUAL :
221         return false;
222       default :
223         return true;
224     }
225   }
226 
227   /** 
228    * @deprecated backport 1.0 internal functionality
229    */
230   private static Map convertConfigurableOptions(ConfigurableOption[] settings) {
231     Hashtable options = new Hashtable(10);
232 
233     for (int i = 0; i < settings.length; i++) {
234       if (settings[i].getComponentName().equals(JavaCodeFormatter.class.getName())) {
235         String optionName = settings[i].getOptionName();
236         int valueIndex = settings[i].getCurrentValueIndex();
237 
238         if (optionName.equals("newline.openingBrace")) { //$NON-NLS-1$
239           options.put("org.eclipse.jdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
240 
241         } else if (optionName.equals("newline.controlStatement")) { //$NON-NLS-1$
242           options.put("org.eclipse.jdt.core.formatter.newline.controlStatement", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
243 
244         } else if (optionName.equals("newline.clearAll")) { //$NON-NLS-1$
245           options.put("org.eclipse.jdt.core.formatter.newline.clearAll", valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
246 
247         } else if (optionName.equals("newline.elseIf")) { //$NON-NLS-1$
248           options.put("org.eclipse.jdt.core.formatter.newline.elseIf", valueIndex == 0 ? "do not insert" : "insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
249 
250         } else if (optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$
251           options.put("org.eclipse.jdt.core.formatter.newline.emptyBlock", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
252 
253         } else if (optionName.equals("lineSplit")) { //$NON-NLS-1$
254           options.put("org.eclipse.jdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
255 
256         } else if (optionName.equals("style.assignment")) { //$NON-NLS-1$
257           options.put("org.eclipse.jdt.core.formatter.style.assignment", valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
258 
259         } else if (optionName.equals("tabulation.char")) { //$NON-NLS-1$
260           options.put("org.eclipse.jdt.core.formatter.tabulation.char", valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
261 
262         } else if (optionName.equals("tabulation.size")) { //$NON-NLS-1$
263           options.put("org.eclipse.jdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$
264         }
265       }
266     }
267 
268     return options;
269   }
270 
271   /** 
272    * Returns the end of the source code.
273    */
274   private final String copyRemainingSource() {
275     char str[] = scanner.source;
276     int startPosition = scanner.startPosition;
277     int length = str.length - startPosition;
278     StringBuffer bufr = new StringBuffer(length);
279     if (startPosition < str.length) {
280       bufr.append(str, startPosition, length);
281     }
282     return (bufr.toString());
283   }
284 
285   /**
286    * Inserts <code>tabCount</code> tab character or their equivalent number of spaces.
287    */
288   private void dumpTab(int tabCount) {
289     if (options.indentWithTab) {
290       for (int j = 0; j < tabCount; j++) {
291         formattedSource.append('\t');
292         increaseSplitDelta(1);
293       }
294     } else {
295       for (int i = 0, max = options.tabSize * tabCount; i < max; i++) {
296         formattedSource.append(' ');
297         increaseSplitDelta(1);
298       }
299     }
300   }
301 
302   /**
303    * Dumps <code>currentLineBuffer</code> into the formatted string.
304    */
305   private void flushBuffer() {
306     String currentString = currentLineBuffer.toString();
307     splitDelta = 0;
308     beginningOfLineIndex = formattedSource.length();
309     if (containsOpenCloseBraces) {
310       containsOpenCloseBraces = false;
311       outputLine(currentString, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0);
312       indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
313     } else {
314       outputLine(currentString, false, currentLineIndentationLevel, 0, -1, null, 0);
315     }
316     int scannerSourceLength = scanner.source.length;
317     if (scannerSourceLength > 2) {
318       if (scanner.source[scannerSourceLength - 1] == '\n'
319         && scanner.source[scannerSourceLength - 2] == '\r') {
320         formattedSource.append(options.lineSeparatorSequence);
321         increaseGlobalDelta(options.lineSeparatorSequence.length - 2);
322       } else if (scanner.source[scannerSourceLength - 1] == '\n') {
323         formattedSource.append(options.lineSeparatorSequence);
324         increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
325       } else if (scanner.source[scannerSourceLength - 1] == '\r') {
326         formattedSource.append(options.lineSeparatorSequence);
327         increaseGlobalDelta(options.lineSeparatorSequence.length - 1);
328       }
329     }
330     updateMappedPositions(scanner.startPosition);
331   }
332 
333   /** 
334    * Formats the input string.
335    */
336   private void format() {
337     int token = 0;
338     int previousToken = 0;
339     int previousCompilableToken = 0;
340     int indentationOffset = 0;
341     int newLinesInWhitespace = 0;
342 
343     // number of new lines in the previous whitespace token
344     // (used to leave blank lines before comments)
345     int pendingNewLines = 0;
346     boolean expectingOpenBrace = false;
347     boolean clearNonBlockIndents = false;
348     // true if all indentations till the 1st { (usefull after } or ;)
349     boolean pendingSpace = true;
350     boolean pendingNewlineAfterParen = false;
351     // true when a cr is to be put after a ) (in conditional statements)
352     boolean inAssignment = false;
353     boolean inArrayAssignment = false;
354     boolean inThrowsClause = false;
355     boolean inClassOrInterfaceHeader = false;
356 
357     // openBracketCount is used to count the number of open brackets not closed yet.
358     int openBracketCount = 0;
359     int unarySignModifier = 0;
360 
361     // openParenthesis[0] is used to count the parenthesis not belonging to a condition
362     // (eg foo();). parenthesis in for (...) are count elsewhere in the array.
363     int openParenthesisCount = 1;
364     int[] openParenthesis = new int[10];
365 
366     // tokenBeforeColon is used to know what token goes along with the current :
367     // it can be case or ?
368     int tokenBeforeColonCount = 0;
369     int[] tokenBeforeColon = new int[10];
370 
371     constructionsCount = 0; // initializes the constructions count.
372 
373     // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise.
374     int nlicsToken = 0;
375 
376     // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and else 
377     boolean specialElse = false;
378 
379     // OPTION (IndentationLevel): initial indentation level may be non-zero.
380     currentLineIndentationLevel += constructionsCount;
381     containsOpenCloseBraces = false;
382     indentationLevelForOpenCloseBraces = 0;
383 
384     // An InvalidInputException exception might cause the termination of this loop.
385     try {
386       while (true) {
387         // Get the next token.  Catch invalid input and output it
388         // with minimal formatting, also catch end of input and
389         // exit the loop.
390         try {
391           token = scanner.getNextToken();
392         } catch (InvalidInputException e) {
393           if (!handleInvalidToken(e)) {
394             throw e;
395           }
396           token = 0;
397         }
398         if (token == JavaCodeScanner.TokenNameEOF)
399           break;
400 
401         /* ## MODIFYING the indentation level before generating new lines
402         and indentation in the output string
403         */
404 
405         // Removes all the indentations made by statements not followed by a block
406         // except if the current token is ELSE, CATCH or if we are in a switch/case
407         if (clearNonBlockIndents && (token != JavaCodeScanner.TokenNameWHITESPACE)) {
408           switch (token) {
409             case TokenNameelse :
410               if (constructionsCount > 0
411                 && constructions[constructionsCount - 1]
412                   == TokenNameelse) {
413                 pendingNewLines = 1;
414                 specialElse = true;
415               }
416               indentationLevel += popInclusiveUntil(TokenNameif);
417               break;
418             case TokenNamecatch :
419               indentationLevel += popInclusiveUntil(TokenNamecatch);
420               break;
421             case TokenNamefinally :
422               indentationLevel += popInclusiveUntil(TokenNamecatch);
423               break;
424             case TokenNamewhile :
425               if (nlicsToken == TokenNamedo) {
426                 indentationLevel += pop(TokenNamedo);
427                 break;
428               }
429             default :
430               indentationLevel += popExclusiveUntilBlockOrCase();
431               // clear until a CASE, DEFAULT or BLOCK is encountered.
432               // Thus, the indentationLevel is correctly cleared either
433               // in a switch/case statement or in any other situation.
434           }
435           clearNonBlockIndents = false;
436         }
437         //HACK to preserve linebreaks before preprocessor lines #define, ... etc. 
438         if (withPreprocessor && token == TokenNameHASH) {
439           if (newLinesInWhitespace > 0) {
440             pendingNewLines = newLinesInWhitespace;
441             newLinesInWhitespace = 0;
442             specialElse = true;
443             isPreprocessor = true;
444           }
445           if (previousToken == JavaCodeScanner.TokenNameEOF)
446             isPreprocessor = true;
447         }
448         // returns to the indentation level created by the SWITCH keyword
449         // if the current token is a CASE or a DEFAULT
450         if (token == TokenNamecase || token == TokenNamedefault) {
451           indentationLevel += pop(TokenNamecase);
452         }
453         if (token == JavaCodeScanner.TokenNamethrows) {
454           inThrowsClause = true;
455         }
456         if ((token == JavaCodeScanner.TokenNameclass
457           || token == JavaCodeScanner.TokenNameinterface)
458           && previousToken != JavaCodeScanner.TokenNameDOT) {
459           inClassOrInterfaceHeader = true;
460         }
461 
462         /* ## APPEND newlines and indentations to the output string
463         */
464         // Do not add a new line between ELSE and IF, if the option elseIfOnSameLine is true.
465         // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting
466         if (pendingNewlineAfterParen
467           && previousCompilableToken == TokenNameelse
468           && token == TokenNameif
469           && options.compactElseIfMode) {
470           pendingNewlineAfterParen = false;
471           pendingNewLines = 0;
472           indentationLevel += pop(TokenNameelse);
473           // because else if is now one single statement,
474           // the indentation level after it is increased by one and not by 2
475           // (else = 1 indent, if = 1 indent, but else if = 1 indent, not 2).
476         }
477         // Add a newline & indent to the formatted source string if
478         // a for/if-else/while statement was scanned and there is no block
479         // following it.
480         pendingNewlineAfterParen =
481           pendingNewlineAfterParen
482             || (previousCompilableToken == TokenNameRPAREN
483               && token == TokenNameLBRACE);
484         if (pendingNewlineAfterParen && token != JavaCodeScanner.TokenNameWHITESPACE) {
485           pendingNewlineAfterParen = false;
486 
487           // Do to add a newline & indent sequence if the current token is an
488           // open brace or a period or if the current token is a semi-colon and the
489           // previous token is a close paren.
490           // add a new line if a parenthesis belonging to a for() statement
491           // has been closed and the current token is not an opening brace
492           if (token != TokenNameLBRACE
493             && !isComment(token) // to avoid adding new line between else and a comment
494             && token != TokenNameDOT
495             && !(previousCompilableToken == TokenNameRPAREN
496               && token == TokenNameSEMICOLON)) {
497             newLine(1);
498             currentLineIndentationLevel = indentationLevel;
499             pendingNewLines = 0;
500             pendingSpace = false;
501           } else {
502             if (token == TokenNameLBRACE
503               && options.newLineBeforeOpeningBraceMode) {
504               newLine(1);
505               if (constructionsCount > 0
506                 && constructions[constructionsCount - 1] != BLOCK
507                 && constructions[constructionsCount - 1]
508                   != NONINDENT_BLOCK) {
509                 currentLineIndentationLevel = indentationLevel - 1;
510               } else {
511                 currentLineIndentationLevel = indentationLevel;
512               }
513               pendingNewLines = 0;
514               pendingSpace = false;
515             }
516           }
517         }
518         if (token == TokenNameLBRACE
519           && options.newLineBeforeOpeningBraceMode
520           && constructionsCount > 0
521           && constructions[constructionsCount - 1] == TokenNamedo) {
522           newLine(1);
523           currentLineIndentationLevel = indentationLevel - 1;
524           pendingNewLines = 0;
525           pendingSpace = false;
526         }
527         // see PR 1G5G8EC
528         if (token == TokenNameLBRACE && inThrowsClause) {
529           inThrowsClause = false;
530           if (options.newLineBeforeOpeningBraceMode) {
531             newLine(1);
532             currentLineIndentationLevel = indentationLevel;
533             pendingNewLines = 0;
534             pendingSpace = false;
535           }
536         }
537         // see PR 1G5G82G
538         if (token == TokenNameLBRACE && inClassOrInterfaceHeader) {
539           inClassOrInterfaceHeader = false;
540           if (options.newLineBeforeOpeningBraceMode) {
541             newLine(1);
542             currentLineIndentationLevel = indentationLevel;
543             pendingNewLines = 0;
544             pendingSpace = false;
545           }
546         }
547         // Add pending new lines to the formatted source string.
548         // Note: pending new lines are not added if the current token
549         // is a single line comment or whitespace.
550         // if the comment is between parenthesis, there is no blank line preservation
551         // (if it's a one-line comment, a blank line is added after it).
552         if (((pendingNewLines > 0 && (!isComment(token)))
553           || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token)))
554           || (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE))
555           && token != JavaCodeScanner.TokenNameWHITESPACE) {
556 
557           // Do not add newline & indent between an adjoining close brace and
558           // close paren.  Anonymous inner classes may use this form.
559           boolean closeBraceAndCloseParen =
560             previousToken == TokenNameRBRACE && token == TokenNameRPAREN;
561 
562           // OPTION (NewLineInCompoundStatement): do not add newline & indent
563           // between close brace and else, (do) while, catch, and finally if
564           // newlineInCompoundStatement is true.
565           boolean nlicsOption =
566             previousToken == TokenNameRBRACE
567               && !options.newlineInControlStatementMode
568               && (token == TokenNameelse
569                 || (token == TokenNamewhile && nlicsToken == TokenNamedo)
570                 || token == TokenNamecatch
571                 || token == TokenNamefinally);
572 
573           // Do not add a newline & indent between a close brace and semi-colon.
574           boolean semiColonAndCloseBrace =
575             previousToken == TokenNameRBRACE && token == TokenNameSEMICOLON;
576 
577           // Do not add a new line & indent between a multiline comment and a opening brace
578           boolean commentAndOpenBrace =
579             previousToken == JavaCodeScanner.TokenNameCOMMENT_BLOCK
580               && token == TokenNameLBRACE;
581 
582           // Do not add a newline & indent between a close brace and a colon (in array assignments, for example).
583           boolean commaAndCloseBrace =
584             previousToken == TokenNameRBRACE && token == TokenNameCOMMA;
585 
586           // Add a newline and indent, if appropriate.
587           if (specialElse
588             || (!commentAndOpenBrace
589               && !closeBraceAndCloseParen
590               && !nlicsOption
591               && !semiColonAndCloseBrace
592               && !commaAndCloseBrace)) {
593 
594             // if clearAllBlankLinesMode=false, leaves the blank lines
595             // inserted by the user
596             // if clearAllBlankLinesMode=true, removes all of then
597             // and insert only blank lines required by the formatting.
598             if (!options.clearAllBlankLinesMode) {
599               //  (isComment(token))
600               pendingNewLines =
601                 (pendingNewLines < newLinesInWhitespace)
602                   ? newLinesInWhitespace
603                   : pendingNewLines;
604               pendingNewLines = (pendingNewLines > 2) ? 2 : pendingNewLines;
605             }
606             if (previousCompilableToken == TokenNameLBRACE
607               && token == TokenNameRBRACE) {
608               containsOpenCloseBraces = true;
609               indentationLevelForOpenCloseBraces =
610                 currentLineIndentationLevel;
611               if (isComment(previousToken)) {
612                 newLine(pendingNewLines);
613               } else {
614                 /*  if (!(constructionsCount > 1
615                         && constructions[constructionsCount-1] == NONINDENT_BLOCK
616                         && (constructions[constructionsCount-2] == TokenNamefor 
617                          || constructions[constructionsCount-2] == TokenNamewhile))) {*/
618                 if (options.newLineInEmptyBlockMode) {
619                   if (inArrayAssignment) {
620                     newLine(1);
621                     // array assigment with an empty block
622                   } else {
623                     newLine(pendingNewLines);
624                   }
625                 }
626                 // }
627               }
628             } else {
629               // see PR 1FKKC3U: LFCOM:WINNT - Format problem with a comment before the ';'
630               if (!((previousToken == JavaCodeScanner.TokenNameCOMMENT_BLOCK
631                 || previousToken
632                   == JavaCodeScanner.TokenNameCOMMENT_JAVADOC)
633                 && token == TokenNameSEMICOLON)) {
634                 newLine(pendingNewLines);
635               }
636             }
637             if (((previousCompilableToken == TokenNameSEMICOLON)
638               || (previousCompilableToken == TokenNameLBRACE)
639               || (previousCompilableToken == TokenNameRBRACE)
640               || (isComment(previousToken)))
641               && (token == TokenNameRBRACE)) {
642               indentationOffset = -1;
643               indentationLevel += popExclusiveUntilBlock();
644             }
645             if (previousToken == JavaCodeScanner.TokenNameCOMMENT_LINE
646               && inAssignment) {
647               // PR 1FI5IPO
648               currentLineIndentationLevel++;
649             } else {
650               currentLineIndentationLevel =
651                 indentationLevel + indentationOffset;
652             }
653             pendingSpace = false;
654             indentationOffset = 0;
655           }
656           pendingNewLines = 0;
657           newLinesInWhitespace = 0;
658           specialElse = false;
659 
660           if (nlicsToken == TokenNamedo && token == TokenNamewhile) {
661             nlicsToken = 0;
662           }
663         }
664         switch (token) {
665           case TokenNameelse :
666           case TokenNamefinally :
667             expectingOpenBrace = true;
668             pendingNewlineAfterParen = true;
669             indentationLevel += pushControlStatement(token);
670             break;
671           case TokenNamecase :
672           case TokenNamedefault :
673             if (tokenBeforeColonCount == tokenBeforeColon.length) {
674               System.arraycopy(
675                 tokenBeforeColon,
676                 0,
677                 (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
678                 0,
679                 tokenBeforeColonCount);
680             }
681             tokenBeforeColon[tokenBeforeColonCount++] = TokenNamecase;
682             indentationLevel += pushControlStatement(TokenNamecase);
683             break;
684           case TokenNameQUESTION :
685             if (tokenBeforeColonCount == tokenBeforeColon.length) {
686               System.arraycopy(
687                 tokenBeforeColon,
688                 0,
689                 (tokenBeforeColon = new int[tokenBeforeColonCount * 2]),
690                 0,
691                 tokenBeforeColonCount);
692             }
693             tokenBeforeColon[tokenBeforeColonCount++] = token;
694             break;
695           case TokenNameswitch :
696           case TokenNamefor :
697           case TokenNameif :
698           case TokenNamewhile :
699             if (openParenthesisCount == openParenthesis.length) {
700               System.arraycopy(
701                 openParenthesis,
702                 0,
703                 (openParenthesis = new int[openParenthesisCount * 2]),
704                 0,
705                 openParenthesisCount);
706             }
707             openParenthesis[openParenthesisCount++] = 0;
708             expectingOpenBrace = true;
709 
710             indentationLevel += pushControlStatement(token);
711             break;
712           case TokenNametry :
713             pendingNewlineAfterParen = true;
714           case TokenNamecatch :
715             // several CATCH statements can be contiguous.
716             // a CATCH is encountered pop until first CATCH (if a CATCH follows a TRY it works the same way,
717             // as CATCH and TRY are the same token in the stack).
718             expectingOpenBrace = true;
719             indentationLevel += pushControlStatement(TokenNamecatch);
720             break;
721 
722           case TokenNamedo :
723             expectingOpenBrace = true;
724             indentationLevel += pushControlStatement(token);
725             nlicsToken = token;
726             break;
727           case TokenNamenew :
728             break;
729           case TokenNameLPAREN :
730             if (previousToken == TokenNamesynchronized) {
731               indentationLevel += pushControlStatement(previousToken);
732             } else {
733               // Put a space between the previous and current token if the
734               // previous token was not a keyword, open paren, logical
735               // compliment (eg: !), semi-colon, open brace, close brace,
736               // super, or this.
737               if (previousCompilableToken != TokenNameLBRACKET
738                 && previousToken != TokenNameIdentifier
739                 && previousToken != 0
740                 && previousToken != TokenNameNOT
741                 && previousToken != TokenNameLPAREN
742                 && previousToken != TokenNameTWIDDLE
743                 && previousToken != TokenNameSEMICOLON
744                 && previousToken != TokenNameLBRACE
745                 && previousToken != TokenNameRBRACE
746               && previousToken != TokenNameHASH
747               && previousToken != TokenNameEACH
748                 && previousToken != TokenNamesuper
749                 && previousToken != TokenNamethis) {
750                 space();
751               }
752               // If in a for/if/while statement, increase the parenthesis count
753               // for the current openParenthesisCount
754               // else increase the count for stand alone parenthesis.
755               if (openParenthesisCount > 0)
756                 openParenthesis[openParenthesisCount - 1]++;
757               else
758                 openParenthesis[0]++;
759 
760               pendingSpace = false;
761             }
762             break;
763           case TokenNameRPAREN :
764 
765             // Decrease the parenthesis count
766             // if there is no more unclosed parenthesis,
767             // a new line and indent may be append (depending on the next token).
768             if ((openParenthesisCount > 1)
769               && (openParenthesis[openParenthesisCount - 1] > 0)) {
770               openParenthesis[openParenthesisCount - 1]--;
771               if (openParenthesis[openParenthesisCount - 1] <= 0) {
772                 pendingNewlineAfterParen = true;
773                 inAssignment = false;
774                 openParenthesisCount--;
775               }
776             } else {
777               openParenthesis[0]--;
778             }
779             pendingSpace = false;
780             break;
781           case TokenNameLBRACE :
782             if ((previousCompilableToken == TokenNameRBRACKET)
783               || (previousCompilableToken == TokenNameEQUAL)) {
784               //                  if (previousCompilableToken == TokenNameRBRACKET) {
785               inArrayAssignment = true;
786               inAssignment = false;
787             }
788             if (inArrayAssignment) {
789               indentationLevel += pushBlock();
790             } else {
791               // Add new line and increase indentation level after open brace.
792               pendingNewLines = 1;
793               indentationLevel += pushBlock();
794             }
795             break;
796           case TokenNameRBRACE :
797             if (previousCompilableToken == TokenNameRPAREN) {
798               pendingSpace = false;
799             }
800             if (inArrayAssignment) {
801               inArrayAssignment = false;
802               pendingNewLines = 1;
803               indentationLevel += popInclusiveUntilBlock();
804             } else {
805               pendingNewLines = 1;
806               indentationLevel += popInclusiveUntilBlock();
807 
808               if (previousCompilableToken == TokenNameRPAREN) {
809                 // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression
810                 currentLineBuffer.append(options.lineSeparatorSequence);
811                 increaseLineDelta(options.lineSeparatorSequence.length);
812               }
813               if (constructionsCount > 0) {
814                 switch (constructions[constructionsCount - 1]) {
815                   case TokenNamefor :
816                     //indentationLevel += popExclusiveUntilBlock();
817                     //break;
818                   case TokenNameswitch :
819                   case TokenNameif :
820                   case TokenNameelse :
821                   case TokenNametry :
822                   case TokenNamecatch :
823                   case TokenNamefinally :
824                   case TokenNamewhile :
825                   case TokenNamedo :
826                   case TokenNamesynchronized :
827                     clearNonBlockIndents = true;
828                   default :
829                     break;
830                 }
831               }
832             }
833             break;
834           case TokenNameLBRACKET :
835             openBracketCount++;
836             pendingSpace = false;
837             break;
838           case TokenNameRBRACKET :
839             openBracketCount -= (openBracketCount > 0) ? 1 : 0;
840             // if there is no left bracket to close, the right bracket is ignored.
841             pendingSpace = false;
842             break;
843           case TokenNameCOMMA :
844           case TokenNameDOT :
845             pendingSpace = false;
846             break;
847           case TokenNameSEMICOLON :
848 
849             // Do not generate line terminators in the definition of
850             // the for statement.
851             // if not in this case, jump a line and reduce indentation after the brace
852             // if the block it closes belongs to a conditional statement (if, while, do...).
853             if (openParenthesisCount <= 1) {
854               pendingNewLines = 1;
855               if (expectingOpenBrace) {
856                 clearNonBlockIndents = true;
857                 expectingOpenBrace = false;
858               }
859             }
860             inAssignment = false;
861             pendingSpace = false;
862             break;
863           case TokenNamePLUS_PLUS :
864           case TokenNameMINUS_MINUS :
865 
866             // Do not put a space between a post-increment/decrement
867             // and the identifier being modified.
868             if (previousToken == TokenNameIdentifier
869               || previousToken == TokenNameRBRACKET) {
870               pendingSpace = false;
871             }
872             break;
873           case TokenNamePLUS : // previously ADDITION
874           case TokenNameMINUS :
875 
876             // Handle the unary operators plus and minus via a flag
877             if (!isLiteralToken(previousToken)
878               && previousToken != TokenNameIdentifier
879               && previousToken != TokenNameRPAREN
880               && previousToken != TokenNameRBRACKET) {
881               unarySignModifier = 1;
882             }
883             break;
884           case TokenNameCOLON :
885             // In a switch/case statement, add a newline & indent
886             // when a colon is encountered.
887             if (tokenBeforeColonCount > 0) {
888               if (tokenBeforeColon[tokenBeforeColonCount - 1]
889                 == TokenNamecase) {
890                 pendingNewLines = 1;
891               }
892               tokenBeforeColonCount--;
893             }
894             break;
895           case TokenNameEQUAL :
896             inAssignment = true;
897             break;
898           case JavaCodeScanner.TokenNameCOMMENT_LINE :
899             pendingNewLines = 1;
900             if (inAssignment) {
901               currentLineIndentationLevel++;
902             }
903             break; // a line is always inserted after a one-line comment
904           case JavaCodeScanner.TokenNameCOMMENT_JAVADOC :
905           case JavaCodeScanner.TokenNameCOMMENT_BLOCK :
906             currentCommentOffset = getCurrentCommentOffset();
907             pendingNewLines = 1;
908             break;
909           case JavaCodeScanner.TokenNameWHITESPACE :
910 
911             // Count the number of line terminators in the whitespace so
912             // line spacing can be preserved near comments.
913             char[] source = scanner.source;
914             newLinesInWhitespace = 0;
915             for (int i = scanner.startPosition, max = scanner.currentPosition;
916               i < max;
917               i++) {
918               if (source[i] == '\r') {
919                 if (i < max - 1) {
920                   if (source[++i] == '\n') {
921                     newLinesInWhitespace++;
922                   } else {
923                     newLinesInWhitespace++;
924                   }
925                 } else {
926                   newLinesInWhitespace++;
927                 }
928               } else if (source[i] == '\n') {
929                 newLinesInWhitespace++;
930               }
931             }
932             increaseLineDelta(scanner.startPosition - scanner.currentPosition);
933             break;
934           default :
935             if ((token == TokenNameIdentifier)
936               || isLiteralToken(token)
937               || token == TokenNamesuper
938               || token == TokenNameLPAREN
939               || token == TokenNamethis) {
940 
941               // Do not put a space between a unary operator
942               // (eg: ++, --, +, -) and the identifier being modified.
943               if (previousToken == TokenNamePLUS_PLUS
944                 || previousToken == TokenNameMINUS_MINUS
945                 || previousToken == TokenNameHASH
946                 || previousToken == TokenNameEACH
947                 || (previousToken == TokenNamePLUS
948                   && unarySignModifier > 0)
949                 || (previousToken == TokenNameMINUS
950                   && unarySignModifier > 0)) {
951                 pendingSpace = false;
952               }
953               unarySignModifier = 0;
954             }
955             break;
956         }
957         // Do not output whitespace tokens.
958         if (token != JavaCodeScanner.TokenNameWHITESPACE) {
959 
960           /* Add pending space to the formatted source string.
961           Do not output a space under the following circumstances:
962           1) this is the first pass
963           2) previous token is an open paren
964           3) previous token is a period
965           4) previous token is the logical compliment (eg: !)
966           5) previous token is the bitwise compliment (eg: ~)
967           6) previous token is the open bracket (eg: [)
968           7) in an assignment statement, if the previous token is an 
969           open brace or the current token is a close brace
970           8) previous token is a single line comment
971           */
972           boolean openAndCloseBrace =
973             previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE;
974 
975           if (pendingSpace
976             && insertSpaceAfter(previousToken)
977             && !(inAssignment
978               && (previousToken == TokenNameLBRACE || token == TokenNameRBRACE))
979             && previousToken != JavaCodeScanner.TokenNameCOMMENT_LINE) {
980             if ((!(options.compactAssignmentMode && token == TokenNameEQUAL))
981               && !openAndCloseBrace)
982               space();
983           }
984           // Add the next token to the formatted source string.
985           outputCurrentToken(token);
986           if (token == JavaCodeScanner.TokenNameCOMMENT_LINE
987             && openParenthesisCount > 1) {
988             pendingNewLines = 0;
989             currentLineBuffer.append(options.lineSeparatorSequence);
990             increaseLineDelta(options.lineSeparatorSequence.length);
991           }
992           pendingSpace = true;
993         }
994         // Whitespace tokens do not need to be remembered.
995         if (token != JavaCodeScanner.TokenNameWHITESPACE) {
996           previousToken = token;
997           if (token != JavaCodeScanner.TokenNameCOMMENT_BLOCK
998             && token != JavaCodeScanner.TokenNameCOMMENT_LINE
999             && token != JavaCodeScanner.TokenNameCOMMENT_JAVADOC) {
1000            previousCompilableToken = token;
1001          }
1002        } else if (withPreprocessor && newLinesInWhitespace > 0 && isPreprocessor) {
1003          //HACK to preserve line break after a line with '#'.
1004          isPreprocessor = false;
1005          pendingSpace = false;
1006          pendingNewLines = 0;
1007          int level=currentLineIndentationLevel;
1008          newLine(newLinesInWhitespace);
1009          currentLineIndentationLevel=level;
1010          newLinesInWhitespace = 0;
1011          previousToken = JavaCodeScanner.TokenNameEOF;
1012        }
1013      }
1014      output(copyRemainingSource());
1015      flushBuffer(); // dump the last token of the source in the formatted output.
1016    } catch (InvalidInputException e) {
1017      output(copyRemainingSource());
1018      flushBuffer(); // dump the last token of the source in the formatted output.
1019    }
1020  }
1021
1022  /** 
1023   * Formats the char array <code>sourceString</code>,
1024   * and returns a string containing the formatted version.
1025   * @return the formatted ouput.
1026   */
1027  public String formatSourceString(String sourceString) {
1028    char[] sourceChars = sourceString.toCharArray();
1029    currentLineBuffer.setLength(0);
1030    formattedSource = new StringBuffer(sourceChars.length);
1031    scanner.setSource(sourceChars);
1032    format();
1033    if (formattedSource.length() > 0 && formattedSource.charAt(0) == '}')
1034      return formattedSource.substring(1);
1035    return formattedSource.toString();
1036  }
1037
1038  /** 
1039   * Formats the char array <code>sourceString</code>,
1040   * and returns a string containing the formatted version.
1041   * @param string the string to format
1042   * @param indentationLevel the initial indentation level
1043   * @return the formatted ouput.
1044   */
1045  public String format(String string, int indentationLevel) {
1046    return format(string, indentationLevel, (int[]) null);
1047  }
1048
1049  /** 
1050   * Formats the char array <code>sourceString</code>,
1051   * and returns a string containing the formatted version.
1052   * The positions array is modified to contain the mapped positions.
1053   * @param string the string to format
1054   * @param indentationLevel the initial indentation level
1055   * @param positions the array of positions to map
1056   * @return the formatted ouput.
1057   */
1058  public String format(String string, int indentationLevel, int[] positions) {
1059    return this.format(string, indentationLevel, positions, null);
1060  }
1061
1062  public String format(String string, int indentationLevel, int[] positions, String lineSeparator) {
1063    if (lineSeparator != null) {
1064      this.options.setLineSeparator(lineSeparator);
1065    }
1066    if (positions != null) {
1067      this.setPositionsToMap(positions);
1068      this.setInitialIndentationLevel(indentationLevel);
1069      String formattedString = this.formatSourceString(string);
1070      int[] mappedPositions = this.getMappedPositions();
1071      System.arraycopy(mappedPositions, 0, positions, 0, positions.length);
1072      return formattedString;
1073    } else {
1074      this.setInitialIndentationLevel(indentationLevel);
1075      return this.formatSourceString(string);
1076    }
1077  }
1078  /** 
1079   * Formats the char array <code>sourceString</code>,
1080   * and returns a string containing the formatted version. The initial indentation level is 0.
1081   * @param string the string to format
1082   * @return the formatted ouput.
1083   */
1084  public String format(String string) {
1085    return this.format(string, 0, (int[]) null);
1086  }
1087
1088  /** 
1089   * Formats a given source string, starting indenting it at a particular 
1090   * depth and using the given options
1091   * 
1092   * @deprecated backport 1.0 internal functionality
1093   */
1094  public static String format(String sourceString, int initialIndentationLevel, ConfigurableOption[] options) {
1095    JavaCodeFormatter formatter = new JavaCodeFormatter(options);
1096    formatter.setInitialIndentationLevel(initialIndentationLevel);
1097    return formatter.formatSourceString(sourceString);
1098  }
1099
1100  /**
1101   * Returns the number of characters and tab char between the beginning of the line
1102   * and the beginning of the comment.
1103   */
1104  private int getCurrentCommentOffset() {
1105    int linePtr = scanner.linePtr;
1106    // if there is no beginning of line, return 0.
1107    if (linePtr < 0)
1108      return 0;
1109    int offset = 0;
1110    int beginningOfLine = scanner.lineEnds[linePtr];
1111    int currentStartPosition = scanner.startPosition;
1112    char[] source = scanner.source;
1113
1114    // find the position of the beginning of the line containing the comment
1115    while (beginningOfLine > currentStartPosition) {
1116      if (linePtr > 0) {
1117        beginningOfLine = scanner.lineEnds[--linePtr];
1118      } else {
1119        beginningOfLine = 0;
1120        break;
1121      }
1122    }
1123    for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) {
1124      char currentCharacter = source[i];
1125      switch (currentCharacter) {
1126        case '\t' :
1127          offset += options.tabSize;
1128          break;
1129        case ' ' :
1130          offset++;
1131          break;
1132        case '\r' :
1133        case '\n' :
1134          break;
1135        default :
1136          return offset;
1137      }
1138    }
1139    return offset;
1140  }
1141
1142  /**
1143   * Returns an array of descriptions for the configurable options.
1144   * The descriptions may be changed and passed back to a different
1145   * compiler.
1146   * 
1147   * @deprecated backport 1.0 internal functionality
1148   */
1149  public static ConfigurableOption[] getDefaultOptions(Locale locale) {
1150    String componentName = JavaCodeFormatter.class.getName();
1151    FormatterOptions options = new FormatterOptions();
1152    return new ConfigurableOption[] { new ConfigurableOption(componentName, "newline.openingBrace", locale, options.newLineBeforeOpeningBraceMode ? 0 : 1), //$NON-NLS-1$
1153      new ConfigurableOption(componentName, "newline.controlStatement", locale, options.newlineInControlStatementMode ? 0 : 1), //$NON-NLS-1$
1154      new ConfigurableOption(componentName, "newline.clearAll", locale, options.clearAllBlankLinesMode ? 0 : 1), //$NON-NLS-1$
1155      new ConfigurableOption(componentName, "newline.elseIf", locale, options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$
1156      new ConfigurableOption(componentName, "newline.emptyBlock", locale, options.newLineInEmptyBlockMode ? 0 : 1), //$NON-NLS-1$
1157      new ConfigurableOption(componentName, "line.split", locale, options.maxLineLength), //$NON-NLS-1$
1158      new ConfigurableOption(componentName, "style.compactAssignment", locale, options.compactAssignmentMode ? 0 : 1), //$NON-NLS-1$
1159      new ConfigurableOption(componentName, "tabulation.char", locale, options.indentWithTab ? 0 : 1), //$NON-NLS-1$
1160      new ConfigurableOption(componentName, "tabulation.size", locale, options.tabSize) //$NON-NLS-1$
1161    };
1162  }
1163
1164  /**
1165   * Returns the array of mapped positions.
1166   * Returns null is no positions have been set.
1167   * @return int[]
1168   * @deprecated There is no need to retrieve the mapped positions anymore.
1169   */
1170  public int[] getMappedPositions() {
1171    return mappedPositions;
1172  }
1173
1174  /**
1175   * Returns the priority of the token given as argument<br>
1176   * The most prioritary the token is, the smallest the return value is.
1177   * @return the priority of <code>token</code>
1178   * @param token the token of which the priority is requested
1179   */
1180  private static int getTokenPriority(int token) {
1181    switch (token) {
1182      case TokenNameextends :
1183      case TokenNameimplements :
1184      case TokenNamethrows :
1185        return 10;
1186      case TokenNameSEMICOLON : // ;
1187        return 20;
1188      case TokenNameCOMMA : // ,
1189        return 25;
1190      case TokenNameEQUAL : // =
1191        return 30;
1192      case TokenNameAND_AND : // && 
1193      case TokenNameOR_OR : // || 
1194        return 40;
1195      case TokenNameQUESTION : // ? 
1196      case TokenNameCOLON : // :
1197        return 50; // it's better cutting on ?: than on ;
1198      case TokenNameEQUAL_EQUAL : // == 
1199      case TokenNameNOT_EQUAL : // != 
1200        return 60;
1201      case TokenNameLESS : // < 
1202      case TokenNameLESS_EQUAL : // <= 
1203      case TokenNameGREATER : // > 
1204      case TokenNameGREATER_EQUAL : // >= 
1205      case TokenNameinstanceof : // instanceof
1206        return 70;
1207      case TokenNamePLUS : // + 
1208      case TokenNameMINUS : // - 
1209        return 80;
1210      case TokenNameMULTIPLY : // * 
1211      case TokenNameDIVIDE : // / 
1212      case TokenNameREMAINDER : // % 
1213        return 90;
1214      case TokenNameLEFT_SHIFT : // << 
1215      case TokenNameRIGHT_SHIFT : // >> 
1216      case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> 
1217        return 100;
1218      case TokenNameAND : // &
1219      case TokenNameOR : // | 
1220      case TokenNameXOR : // ^ 
1221        return 110;
1222      case TokenNameMULTIPLY_EQUAL : // *= 
1223      case TokenNameDIVIDE_EQUAL : // /= 
1224      case TokenNameREMAINDER_EQUAL : // %= 
1225      case TokenNamePLUS_EQUAL : // += 
1226      case TokenNameMINUS_EQUAL : // -= 
1227      case TokenNameLEFT_SHIFT_EQUAL : // <<= 
1228      case TokenNameRIGHT_SHIFT_EQUAL : // >>= 
1229      case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>=
1230      case TokenNameAND_EQUAL : // &= 
1231      case TokenNameXOR_EQUAL : // ^= 
1232      case TokenNameOR_EQUAL : // |= 
1233        return 120;
1234      case TokenNameDOT : // .
1235        return 130;
1236      default :
1237        return Integer.MAX_VALUE;
1238    }
1239  }
1240
1241  /**
1242   * Handles the exception raised when an invalid token is encountered.
1243   * Returns true if the exception has been handled, false otherwise.
1244   */
1245  private boolean handleInvalidToken(Exception e) {
1246    if (e.getMessage().equals(JavaCodeScanner.INVALID_CHARACTER_CONSTANT)
1247      || e.getMessage().equals(JavaCodeScanner.INVALID_CHAR_IN_STRING)
1248      || e.getMessage().equals(JavaCodeScanner.INVALID_ESCAPE)) {
1249      return true;
1250    }
1251    return false;
1252  }
1253
1254  private final void increaseGlobalDelta(int offset) {
1255    globalDelta += offset;
1256  }
1257
1258  private final void increaseLineDelta(int offset) {
1259    lineDelta += offset;
1260  }
1261
1262  private final void increaseSplitDelta(int offset) {
1263    splitDelta += offset;
1264  }
1265
1266  /**
1267   * Returns true if a space has to be inserted after <code>operator</code>
1268   * false otherwise.
1269   */
1270  private boolean insertSpaceAfter(int token) {
1271    switch (token) {
1272      case TokenNameLPAREN :
1273      case TokenNameNOT :
1274      case TokenNameTWIDDLE :
1275      case TokenNameDOT :
1276      case 0 : // no token
1277      case TokenNameLBRACKET :
1278      case JavaCodeScanner.TokenNameCOMMENT_LINE :
1279      case JavaCodeScanner.TokenNameHASH :
1280      case JavaCodeScanner.TokenNameEACH :
1281        return false;
1282      default :
1283        return true;
1284    }
1285  }
1286
1287  /**
1288   * Returns true if a space has to be inserted before <code>operator</code>
1289   * false otherwise.<br>
1290   * Cannot be static as it uses the code formatter options
1291   * (to know if the compact assignment mode is on).
1292   */
1293  private boolean insertSpaceBefore(int token) {
1294    switch (token) {
1295      case TokenNameEQUAL :
1296        return (!options.compactAssignmentMode);
1297      default :
1298        return false;
1299    }
1300  }
1301
1302  private static boolean isComment(int token) {
1303    boolean result =
1304      token == JavaCodeScanner.TokenNameCOMMENT_BLOCK
1305        || token == JavaCodeScanner.TokenNameCOMMENT_LINE
1306        || token == JavaCodeScanner.TokenNameCOMMENT_JAVADOC;
1307    return result;
1308  }
1309
1310  private static boolean isLiteralToken(int token) {
1311    boolean result =
1312      token == TokenNameIntegerLiteral
1313        || token == TokenNameLongLiteral
1314        || token == TokenNameFloatingPointLiteral
1315        || token == TokenNameDoubleLiteral
1316        || token == TokenNameCharacterLiteral
1317        || token == TokenNameStringLiteral;
1318    return result;
1319  }
1320
1321  /**
1322   * If the length of <code>oneLineBuffer</code> exceeds <code>maxLineLength</code>,
1323   * it is split and the result is dumped in <code>formattedSource</code>
1324   * @param newLineCount the number of new lines to append
1325   */
1326  private void newLine(int newLineCount) {
1327
1328    // format current line
1329    splitDelta = 0;
1330    beginningOfLineIndex = formattedSource.length();
1331    String currentLine = currentLineBuffer.toString();
1332    if (containsOpenCloseBraces) {
1333      containsOpenCloseBraces = false;
1334      outputLine(currentLine, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0);
1335      indentationLevelForOpenCloseBraces = currentLineIndentationLevel;
1336    } else {
1337      outputLine(currentLine, false, currentLineIndentationLevel, 0, -1, null, 0);
1338    }
1339    // dump line break(s)
1340    for (int i = 0; i < newLineCount; i++) {
1341      formattedSource.append(options.lineSeparatorSequence);
1342      increaseSplitDelta(options.lineSeparatorSequence.length);
1343    }
1344    // reset formatter for next line
1345    int currentLength = currentLine.length();
1346    currentLineBuffer =
1347      new StringBuffer(currentLength > maxLineSize ? maxLineSize = currentLength : maxLineSize);
1348
1349    increaseGlobalDelta(splitDelta);
1350    increaseGlobalDelta(lineDelta);
1351    lineDelta = 0;
1352    currentLineIndentationLevel = initialIndentationLevel;
1353  }
1354
1355  private String operatorString(int operator) {
1356    switch (operator) {
1357      case TokenNameextends :
1358        return "extends"; //$NON-NLS-1$
1359
1360      case TokenNameimplements :
1361        return "implements"; //$NON-NLS-1$
1362
1363      case TokenNamethrows :
1364        return "throws"; //$NON-NLS-1$
1365
1366      case TokenNameSEMICOLON : // ;
1367        return ";"; //$NON-NLS-1$
1368
1369      case TokenNameCOMMA : // ,
1370        return ","; //$NON-NLS-1$
1371
1372      case TokenNameEQUAL : // =
1373        return "="; //$NON-NLS-1$
1374