Index: Scribe.java
===================================================================
--- Scribe.java	(.../trunk/eclipseformatter/Scribe.java)	(revision 49)
+++ Scribe.java	(.../branches/ef-changed/eclipseformatter/CodeFormatterVisitor.java)	(revision 49)
@@ -1,5 +1,11 @@
+/*
+ * This file has been modified to allow the code
+ * formatter to insert curly braces {}.
+ * See http://kruithof.xs4all.nl//eclipseform/eclipsewithbraces.html
+ * for more info.
+ */
 /*******************************************************************************
- * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * Copyright (c) 2002, 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,1554 +16,5276 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.formatter;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Map;
 
 import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
-import org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
+import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ArrayReference;
+import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.AssertStatement;
+import org.eclipse.jdt.internal.compiler.ast.Assignment;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.BinaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.Block;
+import org.eclipse.jdt.internal.compiler.ast.BreakStatement;
+import org.eclipse.jdt.internal.compiler.ast.CaseStatement;
+import org.eclipse.jdt.internal.compiler.ast.CastExpression;
+import org.eclipse.jdt.internal.compiler.ast.CharLiteral;
+import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
+import org.eclipse.jdt.internal.compiler.ast.Clinit;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.CompoundAssignment;
+import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ContinueStatement;
+import org.eclipse.jdt.internal.compiler.ast.DoStatement;
+import org.eclipse.jdt.internal.compiler.ast.DoubleLiteral;
+import org.eclipse.jdt.internal.compiler.ast.EmptyStatement;
+import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
+import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.FieldReference;
+import org.eclipse.jdt.internal.compiler.ast.FloatLiteral;
+import org.eclipse.jdt.internal.compiler.ast.ForStatement;
+import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
+import org.eclipse.jdt.internal.compiler.ast.IfStatement;
+import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.Initializer;
+import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
+import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
+import org.eclipse.jdt.internal.compiler.ast.LabeledStatement;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.LongLiteral;
+import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
+import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
+import org.eclipse.jdt.internal.compiler.ast.MessageSend;
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation;
+import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
+import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression;
+import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
+import org.eclipse.jdt.internal.compiler.ast.PostfixExpression;
+import org.eclipse.jdt.internal.compiler.ast.PrefixExpression;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
+import org.eclipse.jdt.internal.compiler.ast.SuperReference;
+import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
+import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement;
+import org.eclipse.jdt.internal.compiler.ast.ThisReference;
+import org.eclipse.jdt.internal.compiler.ast.ThrowStatement;
+import org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
+import org.eclipse.jdt.internal.compiler.ast.TryStatement;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.WhileStatement;
+import org.eclipse.jdt.internal.compiler.ast.Wildcard;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
+import org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
-import org.eclipse.jdt.internal.core.util.RecordedParsingInformation;
 import org.eclipse.jdt.internal.formatter.align.Alignment;
 import org.eclipse.jdt.internal.formatter.align.AlignmentException;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.jdt.internal.formatter.comment.CommentRegion;
 import org.eclipse.text.edits.TextEdit;
 
 /**
- * This class is responsible for dumping formatted source
+ * This class is responsible for formatting a valid java source code.
  * @since 2.1
  */
-public class Scribe {
-	private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+/*
+   <extension
+         id="org.eclipse.jdt.core.newformatter.codeformatter"
+         name="org.eclipse.jdt.core.newformatter.codeformatter"
+         point="org.eclipse.jdt.core.codeFormatter">
+      <codeFormatter
+            class="org.eclipse.jdt.internal.formatter.CodeFormatterVisitor">
+      </codeFormatter>
+   </extension>
+*/
+public class CodeFormatterVisitor extends ASTVisitor {
 
-	private static final int INITIAL_SIZE = 100;
-	
-	private boolean checkLineWrapping;
-	/** one-based column */
-	public int column;
-	private int[][] commentPositions;
+	public static class MultiFieldDeclaration extends FieldDeclaration {
 		
-	// Most specific alignment. 
-	public Alignment currentAlignment;
-	public int currentToken;
+		FieldDeclaration[] declarations;
+		
+		MultiFieldDeclaration(FieldDeclaration[] declarations){
+			this.declarations = declarations;
+			this.modifiers = declarations[0].modifiers; 
+		}
+	}
 	
-	// edits management
-	private OptimizedReplaceEdit[] edits;
-	public int editsIndex;
-	
-	public CodeFormatterVisitor formatter;
-	public int indentationLevel;	
-	public int lastNumberOfNewLines;
-	public int line;
-	
-	private int[] lineEnds;
-	private String lineSeparator;
-	public Alignment memberAlignment;
-	public boolean needSpace = false;
-	
-	public int nlsTagCounter;
-	public int pageWidth;
-	public boolean pendingSpace = false;
+	public static boolean DEBUG = false;
+	private static final int NO_MODIFIERS = 0;
+	/*
+	 * Set of expected tokens type for a single type reference.
+	 * This array needs to be SORTED.
+	 */
+	private static final int[] SINGLETYPEREFERENCE_EXPECTEDTOKENS = new int[] {
+		TerminalTokens.TokenNameIdentifier,
+		TerminalTokens.TokenNameboolean,
+		TerminalTokens.TokenNamebyte,
+		TerminalTokens.TokenNamechar,
+		TerminalTokens.TokenNamedouble,
+		TerminalTokens.TokenNamefloat,
+		TerminalTokens.TokenNameint,
+		TerminalTokens.TokenNamelong,
+		TerminalTokens.TokenNameshort,
+		TerminalTokens.TokenNamevoid
+	};
+	private static final int[] CLOSING_GENERICS_EXPECTEDTOKENS = new int[] {
+		TerminalTokens.TokenNameRIGHT_SHIFT,
+		TerminalTokens.TokenNameUNSIGNED_RIGHT_SHIFT,
+		TerminalTokens.TokenNameGREATER
+	};
+	private int chunkKind;
+	public int lastLocalDeclarationSourceStart;
+	private Scanner localScanner;
+	public DefaultCodeFormatterOptions preferences;
+	public Scribe scribe;
 
-	public Scanner scanner;
-	public int scannerEndPosition;
-	public int tabLength;	
-	public int indentationSize;	
-	private int textRegionEnd;
-	private int textRegionStart;
-	public int tabChar;
-	public int numberOfIndentations;
-	private boolean useTabsOnlyForLeadingIndents;
-
-    /** indent empty lines*/
-    private final boolean indentEmptyLines;
-    
-	Scribe(CodeFormatterVisitor formatter, Map settings, int offset, int length, CodeSnippetParsingUtil codeSnippetParsingUtil) {
+	public CodeFormatterVisitor(DefaultCodeFormatterOptions preferences, Map settings, int offset, int length, CodeSnippetParsingUtil codeSnippetParsingUtil) {
 		if (settings != null) {
-			Object sourceLevelOption = settings.get(JavaCore.COMPILER_SOURCE);
+			Object assertModeSetting = settings.get(JavaCore.COMPILER_SOURCE);
 			long sourceLevel = ClassFileConstants.JDK1_3;
-			if (JavaCore.VERSION_1_4.equals(sourceLevelOption)) {
+			if (JavaCore.VERSION_1_4.equals(assertModeSetting)) {
 				sourceLevel = ClassFileConstants.JDK1_4;
-			} else if (JavaCore.VERSION_1_5.equals(sourceLevelOption)) {
+			} else if (JavaCore.VERSION_1_5.equals(assertModeSetting)) {
 				sourceLevel = ClassFileConstants.JDK1_5;
-			}
-			this.scanner = new Scanner(true, true, false/*nls*/, sourceLevel/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
+			}		
+			this.localScanner = new Scanner(true, false, false/*nls*/, sourceLevel/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
 		} else {
-			this.scanner = new Scanner(true, true, false/*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
+			this.localScanner = new Scanner(true, false, false/*nls*/, ClassFileConstants.JDK1_3/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
 		}
-		this.formatter = formatter;
-		this.pageWidth = formatter.preferences.page_width;
-		this.tabLength = formatter.preferences.tab_size;
-		this.indentationLevel= 0; // initialize properly
-		this.numberOfIndentations = 0;
-		this.useTabsOnlyForLeadingIndents = formatter.preferences.use_tabs_only_for_leading_indentations;
-        this.indentEmptyLines = formatter.preferences.indent_empty_lines;
-		this.tabChar = formatter.preferences.tab_char;
-		if (this.tabChar == DefaultCodeFormatterOptions.MIXED) {
-			this.indentationSize = formatter.preferences.indentation_size;
-		} else {
-			this.indentationSize = this.tabLength;
-		}
-		this.lineSeparator = formatter.preferences.line_separator;
-		this.indentationLevel = formatter.preferences.initial_indentation_level * this.indentationSize;
-		this.textRegionStart = offset;
-		this.textRegionEnd = offset + length - 1;
-		if (codeSnippetParsingUtil != null) {
-			final RecordedParsingInformation information = codeSnippetParsingUtil.recordedParsingInformation;
-			if (information != null) {
-				this.lineEnds = information.lineEnds;
-				this.commentPositions = information.commentPositions;
-			}
-		}
-		reset();
+		
+		this.preferences = preferences;
+		this.scribe = new Scribe(this, settings, offset, length, codeSnippetParsingUtil);
 	}
 	
-	private final void addDeleteEdit(int start, int end) {
-		if (this.edits.length == this.editsIndex) {
-			// resize
-			resize();
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#acceptProblem(org.eclipse.jdt.core.compiler.IProblem)
+	 */
+	public void acceptProblem(IProblem problem) {
+		super.acceptProblem(problem);
+	}
+
+	private BinaryExpressionFragmentBuilder buildFragments(BinaryExpression binaryExpression, BlockScope scope) {
+		BinaryExpressionFragmentBuilder builder = new BinaryExpressionFragmentBuilder();
+
+		switch((binaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
+			case OperatorIds.MULTIPLY :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameMULTIPLY));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.PLUS :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNamePLUS));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.DIVIDE :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameDIVIDE));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.REMAINDER :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameREMAINDER));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.XOR :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameXOR));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.MINUS :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameMINUS));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.OR :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameOR));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.AND :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameAND));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.AND_AND :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameAND_AND));
+				binaryExpression.right.traverse(builder, scope);
+				break;
+			case OperatorIds.OR_OR :
+				binaryExpression.left.traverse(builder, scope);
+				builder.operatorsList.add(new Integer(TerminalTokens.TokenNameOR_OR));
+				binaryExpression.right.traverse(builder, scope);
+				break;
 		}
-		addOptimizedReplaceEdit(start, end - start + 1, EMPTY_STRING);
+
+		return builder;
 	}
 
-	public final void addInsertEdit(int insertPosition, String insertedString) {
-		if (this.edits.length == this.editsIndex) {
-			// resize
-			resize();
+	private CascadingMethodInvocationFragmentBuilder buildFragments(MessageSend messageSend, BlockScope scope) {
+		CascadingMethodInvocationFragmentBuilder builder = new CascadingMethodInvocationFragmentBuilder();
+
+		messageSend.traverse(builder, scope);
+		return builder;
+	}	
+	public boolean checkChunkStart(int kind) {
+		if (this.chunkKind != kind) {
+			this.chunkKind = kind;
+			return true;
 		}
-		addOptimizedReplaceEdit(insertPosition, 0, insertedString);
+		return false;
 	}
+	
+	private boolean commentStartsBlock(int start, int end) {
+		this.localScanner.resetTo(start, end);
+		try {
+			if (this.localScanner.getNextToken() ==  TerminalTokens.TokenNameLBRACE) {
+				switch(this.localScanner.getNextToken()) {
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						return true;
+				}
+			}
+		} catch(InvalidInputException e) {
+			// ignore
+		}
+		return false;
+	}
 
-	private final void addOptimizedReplaceEdit(int offset, int length, String replacement) {
-		if (this.editsIndex > 0) {
-			// try to merge last two edits
-			final OptimizedReplaceEdit previous = this.edits[this.editsIndex-1];
-			final int previousOffset = previous.offset;
-			final int previousLength = previous.length;
-			final int endOffsetOfPreviousEdit = previousOffset + previousLength;
-			final int replacementLength = replacement.length();
-			final String previousReplacement = previous.replacement;
-			final int previousReplacementLength = previousReplacement.length();
-			if (previousOffset == offset && previousLength == length && (replacementLength == 0 || previousReplacementLength == 0)) {
-				if (this.currentAlignment != null) {
-					final Location location = this.currentAlignment.location;
-					if (location.editsIndex == this.editsIndex) {
-						location.editsIndex--;
-						location.textEdit = previous;
+	private ASTNode[] computeMergedMemberDeclarations(ASTNode[] nodes){
+		ArrayList mergedNodes = new ArrayList();
+		for (int i = 0, max = nodes.length; i < max; i++) {
+			ASTNode currentNode = nodes[i];
+			if (currentNode instanceof FieldDeclaration) {
+				FieldDeclaration currentField = (FieldDeclaration) currentNode;
+				if (mergedNodes.size() == 0) {
+					// first node
+					mergedNodes.add(currentNode);
+				} else {
+					// we need to check if the previous merged node is a field declaration
+					ASTNode previousMergedNode = (ASTNode) mergedNodes.get(mergedNodes.size() - 1);
+					if (previousMergedNode instanceof MultiFieldDeclaration) {
+						// we merge the current node
+						MultiFieldDeclaration multiFieldDeclaration = (MultiFieldDeclaration) previousMergedNode;
+						int length = multiFieldDeclaration.declarations.length;
+						System.arraycopy(multiFieldDeclaration.declarations, 0, multiFieldDeclaration.declarations= new FieldDeclaration[length+1], 0, length);
+						multiFieldDeclaration.declarations[length] = currentField;
+					} else if (previousMergedNode instanceof FieldDeclaration) {
+						// need to check we need to create a multiple field declaration
+						if (currentField.declarationSourceStart == ((FieldDeclaration) previousMergedNode).declarationSourceStart) {
+							// we create a multi field declaration
+							mergedNodes.set(mergedNodes.size() - 1, new MultiFieldDeclaration(new FieldDeclaration[]{ (FieldDeclaration)previousMergedNode, currentField}));
+						} else {
+							mergedNodes.add(currentNode);
+						}
+					} else {
+						mergedNodes.add(currentNode);
 					}
 				}
-				this.editsIndex--;
-				return;
+			} else {
+				mergedNodes.add(currentNode);
 			}
-			if (endOffsetOfPreviousEdit == offset) {
-				if (length != 0) {
-					if (replacementLength != 0) {
-						this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength + length, previousReplacement + replacement);
-					} else if (previousLength + length == previousReplacementLength) {
-						// check the characters. If they are identical, we can get rid of the previous edit
-						boolean canBeRemoved = true;
-						loop: for (int i = previousOffset; i < previousOffset + previousReplacementLength; i++) {
-							if (scanner.source[i] != previousReplacement.charAt(i - previousOffset)) {
-								this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousReplacementLength, previousReplacement);
-								canBeRemoved = false;
-								break loop;
-							}
+		}
+		if (mergedNodes.size() != nodes.length) {
+			ASTNode[] result = new ASTNode[mergedNodes.size()];
+			mergedNodes.toArray(result);
+			return result;
+		} else {
+			return nodes;
+		}
+	}
+	
+	private ASTNode[] computeMergedMemberDeclarations(TypeDeclaration typeDeclaration){
+		
+		int fieldIndex = 0, fieldCount = (typeDeclaration.fields == null) ? 0 : typeDeclaration.fields.length;
+		FieldDeclaration field = fieldCount == 0 ? null : typeDeclaration.fields[fieldIndex];
+		int fieldStart = field == null ? Integer.MAX_VALUE : field.declarationSourceStart;
+
+		int methodIndex = 0, methodCount = (typeDeclaration.methods == null) ? 0 : typeDeclaration.methods.length;
+		AbstractMethodDeclaration method = methodCount == 0 ? null : typeDeclaration.methods[methodIndex];
+		int methodStart = method == null ? Integer.MAX_VALUE : method.declarationSourceStart;
+
+		int typeIndex = 0, typeCount = (typeDeclaration.memberTypes == null) ? 0 : typeDeclaration.memberTypes.length;
+		TypeDeclaration type = typeCount == 0 ? null : typeDeclaration.memberTypes[typeIndex];
+		int typeStart = type == null ? Integer.MAX_VALUE : type.declarationSourceStart;
+	
+		final int memberLength = fieldCount+methodCount+typeCount;
+		ASTNode[] members = new ASTNode[memberLength];
+		if (memberLength != 0) {
+			int index = 0;
+			int previousFieldStart = -1;
+			do {
+				if (fieldStart < methodStart && fieldStart < typeStart) {
+					if (field.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
+						// filter out enum constants
+						previousFieldStart = fieldStart;
+						if (++fieldIndex < fieldCount) { // find next field if any
+							fieldStart = (field = typeDeclaration.fields[fieldIndex]).declarationSourceStart;
+						} else {
+							fieldStart = Integer.MAX_VALUE;
 						}
-						if (canBeRemoved) {
-							if (this.currentAlignment != null) {
-								final Location location = this.currentAlignment.location;
-								if (location.editsIndex == this.editsIndex) {
-									location.editsIndex--;
-									location.textEdit = previous;
-								}
-							}
-							this.editsIndex--;
+						continue;
+					}
+					// next member is a field
+					if (fieldStart == previousFieldStart){ 
+						ASTNode previousMember = members[index - 1];
+						if (previousMember instanceof MultiFieldDeclaration) {
+							MultiFieldDeclaration multiField = (MultiFieldDeclaration) previousMember;
+							int length = multiField.declarations.length;
+							System.arraycopy(multiField.declarations, 0, multiField.declarations=new FieldDeclaration[length+1], 0, length);
+							multiField.declarations[length] = field;
+						} else {
+							members[index - 1] = new MultiFieldDeclaration(new FieldDeclaration[]{ (FieldDeclaration)previousMember, field});
 						}
 					} else {
-						this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength + length, previousReplacement);
+						members[index++] = field;					
 					}
+					previousFieldStart = fieldStart;
+					if (++fieldIndex < fieldCount) { // find next field if any
+						fieldStart = (field = typeDeclaration.fields[fieldIndex]).declarationSourceStart;
+					} else {
+						fieldStart = Integer.MAX_VALUE;
+					}
+				} else if (methodStart < fieldStart && methodStart < typeStart) {
+					// next member is a method
+					if (!method.isDefaultConstructor() && !method.isClinit()) {
+						members[index++] = method;					
+					}
+					if (++methodIndex < methodCount) { // find next method if any
+						methodStart = (method = typeDeclaration.methods[methodIndex]).declarationSourceStart;
+					} else {
+						methodStart = Integer.MAX_VALUE;
+					}
 				} else {
-					if (replacementLength != 0) {
-						this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength, previousReplacement + replacement);
+					// next member is a type
+					members[index++] = type;
+					if (++typeIndex < typeCount) { // find next type if any
+						typeStart = (type = typeDeclaration.memberTypes[typeIndex]).declarationSourceStart;
+					} else {
+						typeStart = Integer.MAX_VALUE;
 					}
 				}
-			} else {
-				this.edits[this.editsIndex++] = new OptimizedReplaceEdit(offset, length, replacement);
+			} while ((fieldIndex < fieldCount) || (typeIndex < typeCount) || (methodIndex < methodCount));
+			
+			if (members.length != index) {
+				System.arraycopy(members, 0, members=new ASTNode[index], 0, index);
 			}
+		}
+		return members;
+	}
+	
+	private boolean dumpBinaryExpression(
+		BinaryExpression binaryExpression,
+		int operator,
+		BlockScope scope) {
+
+		final int numberOfParens = (binaryExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(binaryExpression, numberOfParens);
+		}	
+		BinaryExpressionFragmentBuilder builder = buildFragments(binaryExpression, scope);
+		final int fragmentsSize = builder.size();
+		
+		if ((builder.realFragmentsSize() > 1 || builder.size() > 4) && numberOfParens == 0) {
+			this.scribe.printComment();
+			Alignment binaryExpressionAlignment = this.scribe.createAlignment("binaryExpressionAlignment", this.preferences.alignment_for_binary_expression, Alignment.R_OUTERMOST, fragmentsSize, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+			this.scribe.enterAlignment(binaryExpressionAlignment);
+			boolean ok = false;
+			ASTNode[] fragments = builder.fragments();
+			int[] operators = builder.operators();
+			do {
+				try {
+					for (int i = 0; i < fragmentsSize - 1; i++) {
+						ASTNode fragment = fragments[i];
+						fragment.traverse(this, scope);
+						this.scribe.printTrailingComment();
+						if (this.scribe.lastNumberOfNewLines == 1) {
+							// a new line has been inserted by printTrailingComment()
+							this.scribe.indentationLevel = binaryExpressionAlignment.breakIndentationLevel;
+						}
+						this.scribe.alignFragment(binaryExpressionAlignment, i);
+						this.scribe.printNextToken(operators[i], this.preferences.insert_space_before_binary_operator);
+						if (operators[i] == TerminalTokens.TokenNameMINUS && isNextToken(TerminalTokens.TokenNameMINUS)) {
+							// the next character is a minus (unary operator)
+							this.scribe.space();
+						}
+						if (this.preferences.insert_space_after_binary_operator) {
+							this.scribe.space();
+						}
+					}
+					fragments[fragmentsSize - 1].traverse(this, scope);
+					this.scribe.printTrailingComment();
+					ok = true;
+				} catch(AlignmentException e){
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);		
+			this.scribe.exitAlignment(binaryExpressionAlignment, true);
 		} else {
-			this.edits[this.editsIndex++] = new OptimizedReplaceEdit(offset, length, replacement);
+			binaryExpression.left.traverse(this, scope);
+			this.scribe.printNextToken(operator, this.preferences.insert_space_before_binary_operator);
+			if (operator == TerminalTokens.TokenNameMINUS && isNextToken(TerminalTokens.TokenNameMINUS)) {
+				// the next character is a minus (unary operator)
+				this.scribe.space();
+			}
+			if (this.preferences.insert_space_after_binary_operator) {
+				this.scribe.space();
+			}
+			binaryExpression.right.traverse(this, scope);
+		}	
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(binaryExpression, numberOfParens);
 		}
+		return false;
 	}
+
+	private boolean dumpEqualityExpression(
+		BinaryExpression binaryExpression,
+		int operator,
+		BlockScope scope) {
 	
-	public final void addReplaceEdit(int start, int end, String replacement) {
-		if (this.edits.length == this.editsIndex) {
-			// resize
-			resize();
+		final int numberOfParens = (binaryExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+	
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(binaryExpression, numberOfParens);
+		}	
+		binaryExpression.left.traverse(this, scope);
+		this.scribe.printNextToken(operator, this.preferences.insert_space_before_binary_operator);
+		if (this.preferences.insert_space_after_binary_operator) {
+			this.scribe.space();
 		}
-		addOptimizedReplaceEdit(start,  end - start + 1, replacement);
+		binaryExpression.right.traverse(this, scope);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(binaryExpression, numberOfParens);
+		}
+		return false;
 	}
 
-	public void alignFragment(Alignment alignment, int fragmentIndex){
-		alignment.fragmentIndex = fragmentIndex;
-		alignment.checkColumn();
-		alignment.performFragmentEffect();
+	private final TextEdit failedToFormat() {
+		if (DEBUG) {
+			System.out.println("COULD NOT FORMAT \n" + this.scribe.scanner); //$NON-NLS-1$
+			System.out.println(this.scribe);
+		}
+		return null;
 	}
+
+	private void format(
+		AbstractMethodDeclaration methodDeclaration,
+		ClassScope scope,
+		boolean isChunkStart,
+		boolean isFirstClassBodyDeclaration) {
+
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			final int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+		}
+		final int newLinesBeforeMethod = this.preferences.blank_lines_before_method;
+		if (newLinesBeforeMethod > 0 && !isFirstClassBodyDeclaration) {
+			this.scribe.printEmptyLines(newLinesBeforeMethod);
+		} else if (this.scribe.line != 0 || this.scribe.column != 1) {
+			this.scribe.printNewLine();
+		}
+		methodDeclaration.traverse(this, scope);
+	}
+
+	private void format(FieldDeclaration fieldDeclaration, ASTVisitor visitor, MethodScope scope, boolean isChunkStart, boolean isFirstClassBodyDeclaration) {
+		
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+			final int newLinesBeforeField = this.preferences.blank_lines_before_field;
+			if (newLinesBeforeField > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeField);
+			}
+		}
+		Alignment memberAlignment = this.scribe.getMemberAlignment();
 	
-	public void checkNLSTag(int sourceStart) {
-		if (hasNLSTag(sourceStart)) {
-			this.nlsTagCounter++;
+        this.scribe.printComment();
+		this.scribe.printModifiers(fieldDeclaration.annotations, this);
+		this.scribe.space();
+		/*
+		 * Field type
+		 */
+		fieldDeclaration.type.traverse(this, scope);
+		
+		/*
+		 * Field name
+		 */
+		this.scribe.alignFragment(memberAlignment, 0);
+	
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
+	
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = getDimensions();
+		if (extraDimensions != 0) {
+			 for (int i = 0; i < extraDimensions; i++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
 		}
+	
+		/*
+		 * Field initialization
+		 */
+		final Expression initialization = fieldDeclaration.initialization;
+		if (initialization != null) {
+			this.scribe.alignFragment(memberAlignment, 1);
+			this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+			if (this.preferences.insert_space_after_assignment_operator) {
+				this.scribe.space();
+			}
+			Alignment assignmentAlignment = this.scribe.createAlignment("fieldDeclarationAssignmentAlignment", this.preferences.alignment_for_assignment, Alignment.R_OUTERMOST, 1, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+			this.scribe.enterAlignment(assignmentAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(assignmentAlignment, 0);
+					initialization.traverse(this, scope);
+					ok = true;
+				} catch(AlignmentException e){
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);		
+			this.scribe.exitAlignment(assignmentAlignment, true);			
+		}
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+
+		if (memberAlignment != null) {
+			this.scribe.alignFragment(memberAlignment, 2);
+			this.scribe.printTrailingComment();
+		} else {
+			this.scribe.space();
+			this.scribe.printTrailingComment();
+		}
 	}
-	public void consumeNextToken() {
-		printComment();
+	
+	private void format(MultiFieldDeclaration multiFieldDeclaration, ASTVisitor visitor, MethodScope scope, boolean isChunkStart, boolean isFirstClassBodyDeclaration) {
+	
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+			final int newLinesBeforeField = this.preferences.blank_lines_before_field;
+			if (newLinesBeforeField > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeField);
+			}
+		}
+		Alignment fieldAlignment = this.scribe.getMemberAlignment();
+	
+        this.scribe.printComment();
+		this.scribe.printModifiers(multiFieldDeclaration.annotations, this);
+		this.scribe.space();
+	
+		multiFieldDeclaration.declarations[0].type.traverse(this, scope);
+	
+		final int multipleFieldDeclarationsLength = multiFieldDeclaration.declarations.length;
+
+		Alignment multiFieldDeclarationsAlignment =this.scribe.createAlignment(
+				"multiple_field",//$NON-NLS-1$
+				this.preferences.alignment_for_multiple_fields,
+				multipleFieldDeclarationsLength - 1,
+				this.scribe.scanner.currentPosition);
+		this.scribe.enterAlignment(multiFieldDeclarationsAlignment);
+	
+		boolean ok = false;
+		do {
+			try {
+				for (int i = 0, length = multipleFieldDeclarationsLength; i < length; i++) {
+					FieldDeclaration fieldDeclaration = multiFieldDeclaration.declarations[i];
+					/*
+					 * Field name
+					 */
+					if (i == 0) {
+						this.scribe.alignFragment(fieldAlignment, 0);
+						this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false);
+					}
+			
+					/*
+					 * Check for extra dimensions
+					 */
+					int extraDimensions = getDimensions();
+					if (extraDimensions != 0) {
+						 for (int index = 0; index < extraDimensions; index++) {
+						 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+						 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+						 }
+					}
+				
+					/*
+					 * Field initialization
+					 */
+					final Expression initialization = fieldDeclaration.initialization;
+					if (initialization != null) {
+						if (i == 0) {
+							this.scribe.alignFragment(fieldAlignment, 1);
+						}
+						this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+						if (this.preferences.insert_space_after_assignment_operator) {
+							this.scribe.space();
+						}
+						initialization.traverse(this, scope);
+					}
+					
+					if (i != length - 1) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_multiple_field_declarations);
+						this.scribe.printTrailingComment();
+						this.scribe.alignFragment(multiFieldDeclarationsAlignment, i);
+
+						if (this.preferences.insert_space_after_comma_in_multiple_field_declarations) {
+							this.scribe.space();
+						}
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.alignFragment(fieldAlignment, 2);
+						this.scribe.printTrailingComment();
+					}
+				}
+				ok = true;
+			} catch (AlignmentException e) {
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);
+		this.scribe.exitAlignment(multiFieldDeclarationsAlignment, true);				
+	}
+	
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, ASTNode[] nodes) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		if (nodes == null) {
+			return null;
+		}
+
+		this.lastLocalDeclarationSourceStart = -1;
 		try {
-			this.currentToken = this.scanner.getNextToken();
-			addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
+			formatClassBodyDeclarations(nodes);
+		} catch(AbortFormatting e){
+			return failedToFormat();
 		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
 	}
-	public Alignment createAlignment(String name, int mode, int count, int sourceRestart){
-		return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart);
+
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, CompilationUnitDeclaration compilationUnitDeclaration) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		if (compilationUnitDeclaration == null || compilationUnitDeclaration.ignoreFurtherInvestigation) {
+			return failedToFormat();
+		}
+
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		this.lastLocalDeclarationSourceStart = -1;
+		try {
+			compilationUnitDeclaration.traverse(this, compilationUnitDeclaration.scope);
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
 	}
 
-	public Alignment createAlignment(String name, int mode, int count, int sourceRestart, boolean adjust){
-		return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart, adjust);
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, ConstructorDeclaration constructorDeclaration) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		if (constructorDeclaration == null) {
+			return null;
+		}
+
+		this.lastLocalDeclarationSourceStart = -1;
+		try {
+			ExplicitConstructorCall explicitConstructorCall = constructorDeclaration.constructorCall;
+			if (explicitConstructorCall != null && !explicitConstructorCall.isImplicitSuper()) {
+				explicitConstructorCall.traverse(this, null);
+			}
+			Statement[] statements = constructorDeclaration.statements;
+			if (statements != null) {
+				formatStatements(null, statements, false);
+			}
+			if (hasComments()) {
+				this.scribe.printNewLine();
+			}
+			this.scribe.printComment();
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
 	}
+
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, Expression expression) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		long startTime = System.currentTimeMillis();
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.localScanner.setSource(compilationUnitSource);
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		if (expression == null) {
+			return null;
+		}
+
+		this.lastLocalDeclarationSourceStart = -1;
+		try {
+			expression.traverse(this, (BlockScope) null);
+			this.scribe.printComment();
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return this.scribe.getRootEdit();
+	}
 	
-	public Alignment createAlignment(String name, int mode, int tieBreakRule, int count, int sourceRestart){
-		return createAlignment(name, mode, tieBreakRule, count, sourceRestart, this.formatter.preferences.continuation_indentation, false);
-	}
+	/**
+	 * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, String, int, int, int, String)
+	 */
+	public TextEdit format(String string, CommentRegion region) {
+		// reset the scribe
+		this.scribe.reset();
+		
+		if (region == null) {
+			return failedToFormat();
+		}
 
-	public Alignment createAlignment(String name, int mode, int count, int sourceRestart, int continuationIndent, boolean adjust){
-		return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart, continuationIndent, adjust);
+		long startTime = 0;
+		if (DEBUG){
+			startTime = System.currentTimeMillis();
+		}
+
+		final char[] compilationUnitSource = string.toCharArray();
+		
+		this.scribe.initializeScanner(compilationUnitSource);
+
+		TextEdit result = null;
+		try {
+			result = region.format(this.preferences.initial_indentation_level, true);
+		} catch(AbortFormatting e){
+			return failedToFormat();
+		}
+		if (DEBUG){
+			System.out.println("Formatting time: " + (System.currentTimeMillis() - startTime));  //$NON-NLS-1$
+		}
+		return result;
 	}
 
-	public Alignment createAlignment(String name, int mode, int tieBreakRule, int count, int sourceRestart, int continuationIndent, boolean adjust){
-		Alignment alignment = new Alignment(name, mode, tieBreakRule, this, count, sourceRestart, continuationIndent);
-		// adjust break indentation
-		if (adjust && this.memberAlignment != null) {
-			Alignment current = this.memberAlignment;
-			while (current.enclosing != null) {
-				current = current.enclosing;
+	private void format(TypeDeclaration typeDeclaration){
+        /*
+         * Print comments to get proper line number
+         */
+        this.scribe.printComment();
+        final int line = this.scribe.line; 
+        
+        this.scribe.printModifiers(typeDeclaration.annotations, this);
+		/*
+		 * Type name
+		 */
+        switch(TypeDeclaration.kind(typeDeclaration.modifiers)) {
+        	case TypeDeclaration.CLASS_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameclass, true); 
+        		break;
+        	case TypeDeclaration.INTERFACE_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameinterface, true); 
+        		break;
+        	case TypeDeclaration.ENUM_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameenum, true); 
+        		break;
+        	case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				this.scribe.printNextToken(TerminalTokens.TokenNameAT, this.preferences.insert_space_before_at_in_annotation_type_declaration);
+				this.scribe.printNextToken(TerminalTokens.TokenNameinterface, this.preferences.insert_space_after_at_in_annotation_type_declaration); 
+        		break;
+        }
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+
+		TypeParameter[] typeParameters = typeDeclaration.typeParameters;
+		if (typeParameters != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_parameters); 
+			if (this.preferences.insert_space_after_opening_angle_bracket_in_type_parameters) {
+				this.scribe.space();
 			}
-			if ((current.mode & Alignment.M_MULTICOLUMN) != 0) {
-				final int indentSize = this.indentationSize;
-				switch(current.chunkKind) {
-					case Alignment.CHUNK_METHOD :
-					case Alignment.CHUNK_TYPE :
-						if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-							alignment.breakIndentationLevel = this.indentationLevel + indentSize;
+			int length = typeParameters.length;
+			for (int i = 0; i < length - 1; i++) {
+				typeParameters[i].traverse(this, typeDeclaration.scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_parameters);
+				if (this.preferences.insert_space_after_comma_in_type_parameters) {
+					this.scribe.space();
+				}				
+			}
+			typeParameters[length - 1].traverse(this, typeDeclaration.scope);
+			if (isClosingGenericToken()) {
+				this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_parameters); 
+			}
+			if (this.preferences.insert_space_after_closing_angle_bracket_in_type_parameters) {
+				this.scribe.space();
+			}
+		}
+		/* 
+		 * Superclass 
+		 */
+		final TypeReference superclass = typeDeclaration.superclass;
+		if (superclass != null) {
+			Alignment superclassAlignment =this.scribe.createAlignment(
+					"superclass", //$NON-NLS-1$
+					this.preferences.alignment_for_superclass_in_type_declaration,
+					2,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(superclassAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(superclassAlignment, 0);
+					this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);
+					this.scribe.alignFragment(superclassAlignment, 1);
+					this.scribe.space();
+					superclass.traverse(this, typeDeclaration.scope);
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(superclassAlignment, true); 
+		}
+
+		/* 
+		 * Super Interfaces 
+		 */
+		final TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
+		if (superInterfaces != null) {
+			int alignment_for_superinterfaces;
+			int kind = TypeDeclaration.kind(typeDeclaration.modifiers);
+			switch(kind) {
+				case TypeDeclaration.ENUM_DECL :
+					alignment_for_superinterfaces = this.preferences.alignment_for_superinterfaces_in_enum_declaration;
+					break;
+				default:
+					alignment_for_superinterfaces = this.preferences.alignment_for_superinterfaces_in_type_declaration;
+					break;
+			}
+			int superInterfaceLength = superInterfaces.length;
+			Alignment interfaceAlignment =this.scribe.createAlignment(
+					"superInterfaces",//$NON-NLS-1$
+					alignment_for_superinterfaces,
+					superInterfaceLength+1,  // implements token is first fragment
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(interfaceAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(interfaceAlignment, 0);
+					if (kind == TypeDeclaration.INTERFACE_DECL) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);
+					} else  {
+						this.scribe.printNextToken(TerminalTokens.TokenNameimplements, true);
+					}
+					for (int i = 0; i < superInterfaceLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_superinterfaces);
+							this.scribe.printTrailingComment();
+							this.scribe.alignFragment(interfaceAlignment, i+1);
+							if (this.preferences.insert_space_after_comma_in_superinterfaces) {
+								this.scribe.space();
+							}
+							superInterfaces[i].traverse(this, typeDeclaration.scope);
 						} else {
-							alignment.breakIndentationLevel = this.indentationLevel + continuationIndent * indentSize;
+							this.scribe.alignFragment(interfaceAlignment, i+1);
+							this.scribe.space();
+							superInterfaces[i].traverse(this, typeDeclaration.scope);
 						}
-						alignment.update();
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(interfaceAlignment, true);
+		}
+
+		/*
+		 * Type body
+		 */
+		String class_declaration_brace;
+		boolean space_before_opening_brace;
+		int kind = TypeDeclaration.kind(typeDeclaration.modifiers);
+		switch(kind) {
+			case TypeDeclaration.ENUM_DECL :
+				class_declaration_brace = this.preferences.brace_position_for_enum_declaration;
+				space_before_opening_brace = this.preferences.insert_space_before_opening_brace_in_enum_declaration;
+				break;
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				class_declaration_brace = this.preferences.brace_position_for_annotation_type_declaration;
+				space_before_opening_brace =  this.preferences.insert_space_before_opening_brace_in_annotation_type_declaration;
+				break;
+			default:
+				class_declaration_brace = this.preferences.brace_position_for_type_declaration;
+				space_before_opening_brace = this.preferences.insert_space_before_opening_brace_in_type_declaration;
+				break;
+		}
+        formatLeftCurlyBrace(line, class_declaration_brace);
+		formatTypeOpeningBrace(class_declaration_brace, space_before_opening_brace, typeDeclaration);
+		
+		boolean indent_body_declarations_compare_to_header;
+		switch(kind) {
+			case TypeDeclaration.ENUM_DECL :
+				indent_body_declarations_compare_to_header = this.preferences.indent_body_declarations_compare_to_enum_declaration_header;
+				break;
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				// TODO (olivier) might want to add an option for annotation type
+				indent_body_declarations_compare_to_header = this.preferences.indent_body_declarations_compare_to_type_header;
+				break;
+			default:
+				indent_body_declarations_compare_to_header = this.preferences.indent_body_declarations_compare_to_type_header;
+				break;
+		}		
+		if (indent_body_declarations_compare_to_header) {
+			this.scribe.indent();
+		}
+		
+		if (kind == TypeDeclaration.ENUM_DECL) {
+			FieldDeclaration[] fieldDeclarations = typeDeclaration.fields;
+			boolean hasConstants = false;
+			if (fieldDeclarations != null) {
+				int length = fieldDeclarations.length;
+				int enumConstantsLength = 0;
+				for (int i = 0; i < length; i++) {
+					FieldDeclaration fieldDeclaration = fieldDeclarations[i];
+					if (fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
+						enumConstantsLength++;
+					} else {
 						break;
-					case Alignment.CHUNK_FIELD :
-						if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-							alignment.breakIndentationLevel = current.originalIndentationLevel + indentSize;
-						} else {
-							alignment.breakIndentationLevel = current.originalIndentationLevel + continuationIndent * indentSize;
+					}
+				}
+				hasConstants = enumConstantsLength != 0;
+				if (enumConstantsLength > 1) {
+					Alignment enumConstantsAlignment = this.scribe.createAlignment(
+							"enumConstants",//$NON-NLS-1$
+							this.preferences.alignment_for_enum_constants,
+							enumConstantsLength,
+							this.scribe.scanner.currentPosition,
+							0, // we don't want to indent enum constants when splitting to a new line
+							false);
+					this.scribe.enterAlignment(enumConstantsAlignment);
+					boolean ok = false;
+					do {
+						try {
+							for (int i = 0; i < enumConstantsLength; i++) {
+								this.scribe.alignFragment(enumConstantsAlignment, i);
+								FieldDeclaration fieldDeclaration = fieldDeclarations[i];
+								fieldDeclaration.traverse(this, typeDeclaration.initializerScope);
+								if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+									this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_enum_declarations);
+									if (this.preferences.insert_space_after_comma_in_enum_declarations) {
+										this.scribe.space();
+									}
+									this.scribe.printTrailingComment();
+									if (fieldDeclaration.initialization instanceof QualifiedAllocationExpression) {
+										this.scribe.printNewLine();
+									}
+								}
+							}
+							ok = true;
+						} catch (AlignmentException e) {
+							this.scribe.redoAlignment(e);
 						}
-						alignment.update();
-						break;
+					} while (!ok);
+					this.scribe.exitAlignment(enumConstantsAlignment, true);
+				} else {
+					FieldDeclaration fieldDeclaration = fieldDeclarations[0];
+					fieldDeclaration.traverse(this, typeDeclaration.initializerScope);
+					if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_enum_declarations);
+						if (this.preferences.insert_space_after_comma_in_enum_declarations) {
+							this.scribe.space();
+						}
+						this.scribe.printTrailingComment();
+						if (fieldDeclaration.initialization instanceof QualifiedAllocationExpression) {
+							this.scribe.printNewLine();
+						}
+					}
 				}
+			}
+			if (isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+				this.scribe.printTrailingComment();
+			}
+			if (hasConstants) {
+				this.scribe.printNewLine();	
+			}
+		}
+
+		formatTypeMembers(typeDeclaration);
+		
+		if (indent_body_declarations_compare_to_header) {
+			this.scribe.unIndent();
+		}
+		
+		switch(kind) {
+			case TypeDeclaration.ENUM_DECL :
+				if (this.preferences.insert_new_line_in_empty_enum_declaration) {
+					this.scribe.printNewLine();
+				}
+				break;
+			case TypeDeclaration.ANNOTATION_TYPE_DECL :
+				// TODO (olivier) might want an option for annotation type
+				if (this.preferences.insert_new_line_in_empty_type_declaration) {
+					this.scribe.printNewLine();
+				}
+				break;
+			default :
+				if (this.preferences.insert_new_line_in_empty_type_declaration) {
+					this.scribe.printNewLine();
+				}
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		this.scribe.printTrailingComment();
+		if (class_declaration_brace.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+			this.scribe.unIndent();
+		}
+		if (hasComments()) {
+			this.scribe.printNewLine();
+		}
+	}
+
+	private void format(
+		TypeDeclaration memberTypeDeclaration,
+		ClassScope scope,
+		boolean isChunkStart,
+		boolean isFirstClassBodyDeclaration) {
+
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+			final int newLinesBeforeMember = this.preferences.blank_lines_before_member_type;
+			if (newLinesBeforeMember > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeMember);
+			}
+		}
+		memberTypeDeclaration.traverse(this, scope);
+	}
+	
+	private void formatAnonymousTypeDeclaration(TypeDeclaration typeDeclaration) {
+		/*
+		 * Type body
+		 */
+		String anonymous_type_declaration_brace_position = this.preferences.brace_position_for_anonymous_type_declaration;
+		
+		formatTypeOpeningBrace(anonymous_type_declaration_brace_position, this.preferences.insert_space_before_opening_brace_in_anonymous_type_declaration, typeDeclaration);
+		
+		this.scribe.indent();
+
+		formatTypeMembers(typeDeclaration);
+
+		this.scribe.unIndent();
+		if (this.preferences.insert_new_line_in_empty_anonymous_type_declaration) {
+			this.scribe.printNewLine();
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		if (anonymous_type_declaration_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+			this.scribe.unIndent();
+		}
+	}
+	
+	/**
+	 * @param block
+	 * @param scope
+	 * @param block_brace_position
+	 */
+	private void formatBlock(Block block, BlockScope scope, String block_brace_position, boolean insertSpaceBeforeOpeningBrace) {
+		formatOpeningBrace(block_brace_position, insertSpaceBeforeOpeningBrace);
+		final Statement[] statements = block.statements;
+		if (statements != null) {
+			this.scribe.printNewLine();
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			formatStatements(scope, statements, true);
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		} else if (this.preferences.insert_new_line_in_empty_block) {
+			this.scribe.printNewLine();
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		} else {
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.indent();
+			}
+			this.scribe.printComment();
+	
+			if (this.preferences.indent_statements_compare_to_block) {
+				this.scribe.unIndent();
+			}
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		this.scribe.printTrailingComment();
+		if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(block_brace_position)) {
+			this.scribe.unIndent();
+		}
+	}
+
+	private void formatCascadingMessageSends(CascadingMethodInvocationFragmentBuilder builder, BlockScope scope) {
+		int size = builder.size();
+		MessageSend[] fragments = builder.fragments();
+		Expression fragment = fragments[0].receiver;
+		int startingPositionInCascade = 1;
+		if (!fragment.isImplicitThis()) {
+			fragment.traverse(this, scope);
+		} else {
+			MessageSend currentMessageSend = fragments[1];
+			final int numberOfParens = (currentMessageSend.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(currentMessageSend, numberOfParens);
+			}
+			ASTNode[] arguments = currentMessageSend.arguments;
+			TypeReference[] typeArguments = currentMessageSend.typeArguments;
+			if (typeArguments != null) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+					if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+						this.scribe.space();
+					}
+					int length = typeArguments.length;
+					for (int i = 0; i < length - 1; i++) {
+						typeArguments[i].traverse(this, scope);
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+						if (this.preferences.insert_space_after_comma_in_type_arguments) {
+							this.scribe.space();
+						}				
+					}
+					typeArguments[length - 1].traverse(this, scope);
+					if (isClosingGenericToken()) {
+						this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+					}
+					if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+						this.scribe.space();
+					}
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier); // selector
+			this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+			if (arguments != null) {
+				if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+					this.scribe.space();
+				}
+				int argumentLength = arguments.length;
+				Alignment argumentsAlignment = this.scribe.createAlignment(
+						"messageArguments", //$NON-NLS-1$
+						this.preferences.alignment_for_arguments_in_method_invocation,
+						Alignment.R_OUTERMOST,
+						argumentLength,
+						this.scribe.scanner.currentPosition);
+				this.scribe.enterAlignment(argumentsAlignment);
+				boolean okForArguments = false;
+				do {
+					try {
+						for (int j = 0; j < argumentLength; j++) {
+							if (j > 0) {
+								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+								this.scribe.printTrailingComment();
+							}
+							this.scribe.alignFragment(argumentsAlignment, j);
+							if (j > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+								this.scribe.space();
+							}
+							arguments[j].traverse(this, scope);
+						}
+						okForArguments = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
+					}
+				} while (!okForArguments);
+				this.scribe.exitAlignment(argumentsAlignment, true);
+				this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation);
 			} else {
-				switch(current.mode & Alignment.SPLIT_MASK) {
-					case Alignment.M_COMPACT_SPLIT :
-					case Alignment.M_COMPACT_FIRST_BREAK_SPLIT :
-					case Alignment.M_NEXT_PER_LINE_SPLIT :
-					case Alignment.M_NEXT_SHIFTED_SPLIT :
-					case Alignment.M_ONE_PER_LINE_SPLIT :
-						final int indentSize = this.indentationSize;
-						switch(current.chunkKind) {
-							case Alignment.CHUNK_METHOD :
-							case Alignment.CHUNK_TYPE :
-								if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-									alignment.breakIndentationLevel = this.indentationLevel + indentSize;
-								} else {
-									alignment.breakIndentationLevel = this.indentationLevel + continuationIndent * indentSize;
+				this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation);
+			}
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(currentMessageSend, numberOfParens);
+			}
+			startingPositionInCascade = 2;
+		}
+		Alignment cascadingMessageSendAlignment =
+			this.scribe.createAlignment(
+				"cascadingMessageSendAlignment", //$NON-NLS-1$
+				this.preferences.alignment_for_selector_in_method_invocation,
+				Alignment.R_INNERMOST,
+				size,
+				this.scribe.scanner.currentPosition);
+		this.scribe.enterAlignment(cascadingMessageSendAlignment);
+		boolean ok = false;
+		do {
+			try {
+				this.scribe.alignFragment(cascadingMessageSendAlignment, 0);
+				this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+				for (int i = startingPositionInCascade; i < size; i++) {
+					MessageSend currentMessageSend = fragments[i];
+					final int numberOfParens = (currentMessageSend.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+					if (numberOfParens > 0) {
+						manageOpeningParenthesizedExpression(currentMessageSend, numberOfParens);
+					}
+					TypeReference[] typeArguments = currentMessageSend.typeArguments;
+					if (typeArguments != null) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+							if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+								this.scribe.space();
+							}
+							int length = typeArguments.length;
+							for (int j = 0; j < length - 1; j++) {
+								typeArguments[j].traverse(this, scope);
+								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+								if (this.preferences.insert_space_after_comma_in_type_arguments) {
+									this.scribe.space();
+								}				
+							}
+							typeArguments[length - 1].traverse(this, scope);
+							if (isClosingGenericToken()) {
+								this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+							}
+							if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+								this.scribe.space();
+							}
+					}
+					ASTNode[] arguments = currentMessageSend.arguments;
+					this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier); // selector
+					this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+					if (arguments != null) {
+						if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+							this.scribe.space();
+						}
+						int argumentLength = arguments.length;
+						Alignment argumentsAlignment = this.scribe.createAlignment(
+								"messageArguments", //$NON-NLS-1$
+								this.preferences.alignment_for_arguments_in_method_invocation,
+								Alignment.R_OUTERMOST,
+								argumentLength,
+								this.scribe.scanner.currentPosition);
+						this.scribe.enterAlignment(argumentsAlignment);
+						boolean okForArguments = false;
+						do {
+							try {
+								for (int j = 0; j < argumentLength; j++) {
+									if (j > 0) {
+										this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+										this.scribe.printTrailingComment();
+									}
+									this.scribe.alignFragment(argumentsAlignment, j);
+									if (j > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+										this.scribe.space();
+									}
+									arguments[j].traverse(this, scope);
 								}
-								alignment.update();
-								break;
-							case Alignment.CHUNK_FIELD :
-								if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
-									alignment.breakIndentationLevel = current.originalIndentationLevel + indentSize;
-								} else {
-									alignment.breakIndentationLevel = current.originalIndentationLevel + continuationIndent * indentSize;
+								okForArguments = true;
+							} catch (AlignmentException e) {
+								this.scribe.redoAlignment(e);
+							}
+						} while (!okForArguments);
+						this.scribe.exitAlignment(argumentsAlignment, true);
+						this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation);
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation);
+					}
+					if (numberOfParens > 0) {
+						manageClosingParenthesizedExpression(currentMessageSend, numberOfParens);
+					}
+					if (i < size - 1) {
+						this.scribe.alignFragment(cascadingMessageSendAlignment, i);
+						this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+					}
+				}
+				ok = true;
+			} catch(AlignmentException e){
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);		
+		this.scribe.exitAlignment(cascadingMessageSendAlignment, true);
+	}
+	
+	/*
+	 * Merged traversal of member (types, fields, methods)
+	 */
+	private void formatClassBodyDeclarations(ASTNode[] nodes) {
+		final int FIELD = 1, METHOD = 2, TYPE = 3;
+		this.scribe.lastNumberOfNewLines = 1;
+		ASTNode[] mergedNodes = computeMergedMemberDeclarations(nodes);
+		Alignment memberAlignment = this.scribe.createMemberAlignment("typeMembers", this.preferences.align_type_members_on_columns ? Alignment.M_MULTICOLUMN : Alignment.M_NO_ALIGNMENT, 4, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterMemberAlignment(memberAlignment);
+		boolean isChunkStart = false;
+		boolean ok = false;
+		int startIndex = 0;
+		do {
+			try {
+				for (int i = startIndex, max = mergedNodes.length; i < max; i++) {
+					ASTNode member = mergedNodes[i];
+					if (member instanceof FieldDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(FIELD, i, this.scribe.scanner.currentPosition);
+						if (member instanceof MultiFieldDeclaration){
+							MultiFieldDeclaration multiField = (MultiFieldDeclaration) member;
+							format(multiField, this, null, isChunkStart, i == 0);
+						} else if (member instanceof Initializer) {
+							int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+							if (newLineBeforeChunk > 0 && i != 0) {
+								this.scribe.printEmptyLines(newLineBeforeChunk);
+							} else if (i == 0) {
+								int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+								if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+									this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
 								}
-								alignment.update();
-								break;
+							}
+							Initializer initializer = (Initializer) member;
+							initializer.traverse(this, null);
+						} else {
+							FieldDeclaration field = (FieldDeclaration) member;
+							format(field, this, null, isChunkStart, i == 0);
 						}
-						break;
+					} else if (member instanceof AbstractMethodDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(METHOD, i, this.scribe.scanner.currentPosition);
+						format((AbstractMethodDeclaration) member, null, isChunkStart, i == 0);
+					} else {
+						isChunkStart = memberAlignment.checkChunkStart(TYPE, i, this.scribe.scanner.currentPosition);
+						format((TypeDeclaration)member, null, isChunkStart, i == 0);
+					}
+					if (isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.printTrailingComment();
+					}
+					if (i != max - 1) {
+						this.scribe.printNewLine();
+					}
 				}
+				ok = true;
+			} catch(AlignmentException e){
+				startIndex = memberAlignment.chunkStartIndex;
+				this.scribe.redoMemberAlignment(e);
 			}
+		} while (!ok);		
+		this.scribe.exitMemberAlignment(memberAlignment);
+		if (hasComments()) {
+			this.scribe.printNewLine();
 		}
-		return alignment; 
+		this.scribe.printComment();
 	}
 
-	public Alignment createMemberAlignment(String name, int mode, int count, int sourceRestart) {
-		Alignment mAlignment = createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart);
-		mAlignment.breakIndentationLevel = this.indentationLevel;
-		return mAlignment;
+	private void formatEmptyTypeDeclaration(boolean isFirst) {
+		boolean hasSemiColon = isNextToken(TerminalTokens.TokenNameSEMICOLON);
+		while(isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+			this.scribe.printComment();
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+		}
+		if (hasSemiColon && isFirst) {
+			this.scribe.printNewLine();
+		}
 	}
-	
-	public void enterAlignment(Alignment alignment){
-		alignment.enclosing = this.currentAlignment;
-		alignment.location.lastLocalDeclarationSourceStart = this.formatter.lastLocalDeclarationSourceStart;
-		this.currentAlignment = alignment;
+
+	private void formatGuardClauseBlock(Block block, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNameLBRACE, this.preferences.insert_space_before_opening_brace_in_block);
+		this.scribe.space();
+
+		final Statement[] statements = block.statements;
+		statements[0].traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, true);
+		this.scribe.printTrailingComment();
 	}
 
-	public void enterMemberAlignment(Alignment alignment) {
-		alignment.enclosing = this.memberAlignment;
-		alignment.location.lastLocalDeclarationSourceStart = this.formatter.lastLocalDeclarationSourceStart;
-		this.memberAlignment = alignment;
+    private void formatLeftCurlyBrace(final int line, final String bracePosition) {
+        /*
+         * deal with (quite unexpected) comments right before lcurly
+         */
+        this.scribe.printComment();
+        if (DefaultCodeFormatterConstants.NEXT_LINE_ON_WRAP.equals(bracePosition)
+                && (this.scribe.line > line || this.scribe.column >= this.preferences.page_width)) 
+        {
+            this.scribe.printNewLine();
+        }
+    }
+    
+	private void formatLocalDeclaration(LocalDeclaration localDeclaration, BlockScope scope, boolean insertSpaceBeforeComma, boolean insertSpaceAfterComma) {
+
+		if (!isMultipleLocalDeclaration(localDeclaration)) {
+			if (localDeclaration.modifiers != NO_MODIFIERS || localDeclaration.annotations != null) {
+		        this.scribe.printComment();
+				this.scribe.printModifiers(localDeclaration.annotations, this);
+				this.scribe.space();
+			}
+	
+			/*
+			 * Argument type 
+			 */		
+			if (localDeclaration.type != null) {
+				localDeclaration.type.traverse(this, scope);
+			}
+			/*
+			 * Print the argument name
+		 	*/
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+		} else {
+			/*
+			 * Print the argument name
+		 	*/
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false); 
+		}
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = getDimensions();
+		if (extraDimensions != 0) {
+			 for (int index = 0; index < extraDimensions; index++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
+		}
+	
+		final Expression initialization = localDeclaration.initialization;
+		if (initialization != null) {
+			/*
+			 * Print the method name
+			 */	
+			this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+			if (this.preferences.insert_space_after_assignment_operator) {
+				this.scribe.space();
+			}
+			Alignment assignmentAlignment = this.scribe.createAlignment("localDeclarationAssignmentAlignment", this.preferences.alignment_for_assignment, Alignment.R_OUTERMOST, 1, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+			this.scribe.enterAlignment(assignmentAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(assignmentAlignment, 0);
+					initialization.traverse(this, scope);
+					ok = true;
+				} catch(AlignmentException e){
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);		
+			this.scribe.exitAlignment(assignmentAlignment, true);			
+		}
+
+		if (isPartOfMultipleLocalDeclaration()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, insertSpaceBeforeComma); 
+			if (insertSpaceAfterComma) {
+				this.scribe.space();
+			}
+			this.scribe.printTrailingComment();
+		}
 	}
 
-	public void exitAlignment(Alignment alignment, boolean discardAlignment){
-		Alignment current = this.currentAlignment;
-		while (current != null){
-			if (current == alignment) break;
-			current = current.enclosing;
+	private void formatMessageSend(
+		MessageSend messageSend,
+		BlockScope scope,
+		Alignment messageAlignment) {
+
+		if (messageAlignment != null) {
+			this.scribe.alignFragment(messageAlignment, 0);
+			this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
 		}
-		if (current == null) {
-			throw new AbortFormatting("could not find matching alignment: "+alignment); //$NON-NLS-1$
+		TypeReference[] typeArguments = messageSend.typeArguments;
+		if (typeArguments != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+				int length = typeArguments.length;
+				for (int i = 0; i < length - 1; i++) {
+					typeArguments[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+					if (this.preferences.insert_space_after_comma_in_type_arguments) {
+						this.scribe.space();
+					}				
+				}
+				typeArguments[length - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+				}
+				if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
 		}
-		this.indentationLevel = alignment.location.outputIndentationLevel;
-		this.numberOfIndentations = alignment.location.numberOfIndentations;
-		this.formatter.lastLocalDeclarationSourceStart = alignment.location.lastLocalDeclarationSourceStart;	
-		if (discardAlignment){ 
-			this.currentAlignment = alignment.enclosing;
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier); // selector
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+
+		final Expression[] arguments = messageSend.arguments;
+		if (arguments != null) {
+			if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+				this.scribe.space();
+			}
+			int argumentsLength = arguments.length;
+			if (argumentsLength > 1) {
+				Alignment argumentsAlignment = this.scribe.createAlignment(
+						"messageArguments", //$NON-NLS-1$
+						this.preferences.alignment_for_arguments_in_method_invocation,
+						argumentsLength,
+						this.scribe.scanner.currentPosition);
+				this.scribe.enterAlignment(argumentsAlignment);
+				boolean ok = false;
+				do {
+					try {
+						for (int i = 0; i < argumentsLength; i++) {
+							if (i > 0) {
+								this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+								this.scribe.printTrailingComment();
+							}
+							this.scribe.alignFragment(argumentsAlignment, i);
+							if (i > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+								this.scribe.space();
+							}
+							arguments[i].traverse(this, scope);
+						}
+						ok = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
+					}
+				} while (!ok);
+				this.scribe.exitAlignment(argumentsAlignment, true);
+			} else {
+				for (int i = 0; i < argumentsLength; i++) {
+					if (i > 0) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_method_invocation_arguments);
+						this.scribe.printTrailingComment();
+					}
+					if (i > 0 && this.preferences.insert_space_after_comma_in_method_invocation_arguments) {
+						this.scribe.space();
+					}
+					arguments[i].traverse(this, scope);
+				}
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation);
 		}
 	}
+
+	private void formatMethodArguments(
+			AbstractMethodDeclaration methodDeclaration, 
+			boolean spaceBeforeOpenParen, 
+			boolean spaceBetweenEmptyParameters,
+			boolean spaceBeforeClosingParen, 
+			boolean spaceBeforeFirstParameter, 
+			boolean spaceBeforeComma, 
+			boolean spaceAfterComma,
+			int methodDeclarationParametersAlignment) {
+				
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, spaceBeforeOpenParen); 
+		
+		final Argument[] arguments = methodDeclaration.arguments;
+		if (arguments != null) {
+			if (spaceBeforeFirstParameter) {
+				this.scribe.space();
+			}
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment = this.scribe.createAlignment(
+					"methodArguments",//$NON-NLS-1$
+					methodDeclarationParametersAlignment,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
+						}
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && spaceAfterComma) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, methodDeclaration.scope);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+		
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBeforeClosingParen); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBetweenEmptyParameters); 
+		}	
+	}
+
+	private void formatEnumConstantArguments(
+			FieldDeclaration enumConstant,
+			boolean spaceBeforeOpenParen, 
+			boolean spaceBetweenEmptyParameters,
+			boolean spaceBeforeClosingParen, 
+			boolean spaceBeforeFirstParameter, 
+			boolean spaceBeforeComma, 
+			boolean spaceAfterComma,
+			int methodDeclarationParametersAlignment) {
+				
+		if (!isNextToken(TerminalTokens.TokenNameLPAREN)) {
+			return;
+		}
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, spaceBeforeOpenParen); 
+		final Expression[] arguments = ((AllocationExpression) enumConstant.initialization).arguments;
+		if (arguments != null) {
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment = this.scribe.createAlignment(
+					"enumConstantArguments",//$NON-NLS-1$
+					methodDeclarationParametersAlignment,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					if (spaceBeforeFirstParameter) {
+						this.scribe.space();
+					}
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
+						}
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && spaceAfterComma) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, (BlockScope) null);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+		
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBeforeClosingParen); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, spaceBetweenEmptyParameters); 
+		}	
+	}
+
+	private void formatNecessaryEmptyStatement() {
+		if (this.preferences.put_empty_statement_on_new_line) {
+			this.scribe.printNewLine();
+			this.scribe.indent();
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+			this.scribe.unIndent();
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+		}
+	}
 	
-	public void exitMemberAlignment(Alignment alignment){
-		Alignment current = this.memberAlignment;
-		while (current != null){
-			if (current == alignment) break;
-			current = current.enclosing;
+	private void formatOpeningBrace(String bracePosition, boolean insertSpaceBeforeBrace) {
+	
+		if (DefaultCodeFormatterConstants.NEXT_LINE.equals(bracePosition)) {
+			this.scribe.printNewLine();
+		} else if (DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(bracePosition)) {
+			this.scribe.printNewLine();
+			this.scribe.indent();
 		}
-		if (current == null) {
-			throw new AbortFormatting("could not find matching alignment: "+alignment); //$NON-NLS-1$
+		this.scribe.printNextToken(TerminalTokens.TokenNameLBRACE, insertSpaceBeforeBrace);
+
+		this.scribe.printTrailingComment();
+	}
+	private void formatStatements(BlockScope scope, final Statement[] statements, boolean insertNewLineAfterLastStatement) {
+		int statementsLength = statements.length;
+		for (int i = 0; i < statementsLength; i++) {
+			final Statement statement = statements[i];
+			if (i > 0 && (statements[i - 1] instanceof EmptyStatement) && !(statement instanceof EmptyStatement)) {
+				this.scribe.printNewLine();
+			}
+			statement.traverse(this, scope);
+			if (statement instanceof Expression) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+				this.scribe.printTrailingComment();
+				if (i != statementsLength - 1) {
+					if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+						this.scribe.printNewLine();
+					}
+				} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+					this.scribe.printNewLine();
+				}
+			} else if (statement instanceof LocalDeclaration) {
+				LocalDeclaration currentLocal = (LocalDeclaration) statement;
+				if (i < (statementsLength - 1)) {
+					/* 
+					 * We need to check that the next statement is a local declaration
+					 */
+					if (statements[i + 1] instanceof LocalDeclaration) {
+						LocalDeclaration nextLocal = (LocalDeclaration) statements[i + 1];
+						if (currentLocal.declarationSourceStart != nextLocal.declarationSourceStart) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+							this.scribe.printTrailingComment();
+							if (i != statementsLength - 1) {
+								if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+									this.scribe.printNewLine();
+								}
+							} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+								this.scribe.printNewLine();
+							}
+						}
+					} else {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.printTrailingComment();
+						if (i != statementsLength - 1) {
+							if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+								this.scribe.printNewLine();
+							}
+						} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+							this.scribe.printNewLine();
+						}
+					}
+				} else {
+					this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+					this.scribe.printTrailingComment();
+					if (i != statementsLength - 1) {
+						if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+							this.scribe.printNewLine();
+						}
+					} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+						this.scribe.printNewLine();
+					}
+				}
+			} else if (i != statementsLength - 1) {
+				if (!(statement instanceof EmptyStatement) && !(statements[i + 1] instanceof EmptyStatement)) {
+					this.scribe.printNewLine();
+				}
+			} else if (i == statementsLength - 1 && insertNewLineAfterLastStatement) {
+				this.scribe.printNewLine();
+			}
 		}
-		this.indentationLevel = current.location.outputIndentationLevel;
-		this.numberOfIndentations = current.location.numberOfIndentations;
-		this.formatter.lastLocalDeclarationSourceStart = alignment.location.lastLocalDeclarationSourceStart;	
-		this.memberAlignment = current.enclosing;
 	}
 	
-	public Alignment getAlignment(String name){
-		if (this.currentAlignment != null) {
-			return this.currentAlignment.getAlignment(name);
+	private void formatThrowsClause(
+		AbstractMethodDeclaration methodDeclaration,
+		boolean spaceBeforeComma,
+		boolean spaceAfterComma,
+		int alignmentForThrowsClause) {
+			
+		final TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions;
+		if (thrownExceptions != null) {
+			int thrownExceptionsLength = thrownExceptions.length;
+			Alignment throwsAlignment = this.scribe.createAlignment(
+					"throws",//$NON-NLS-1$
+					alignmentForThrowsClause,
+					thrownExceptionsLength, // throws is the first token
+					this.scribe.scanner.currentPosition);
+		
+			this.scribe.enterAlignment(throwsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					this.scribe.alignFragment(throwsAlignment, 0);
+					this.scribe.printNextToken(TerminalTokens.TokenNamethrows, true); 
+		
+					for (int i = 0; i < thrownExceptionsLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, spaceBeforeComma);
+							this.scribe.printTrailingComment();
+							this.scribe.alignFragment(throwsAlignment, i);
+							if (spaceAfterComma) {
+								this.scribe.space();
+							}
+						} else {
+							this.scribe.space();
+						}
+						thrownExceptions[i].traverse(this, methodDeclaration.scope);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(throwsAlignment, true);
 		}
-		return null;
 	}
-	
-	/** 
-	 * Answer actual indentation level based on true column position
-	 * @return int
+
+	/*
+	 * Merged traversal of member (types, fields, methods)
 	 */
-	public int getColumnIndentationLevel() {
-		return this.column - 1;
-	}	
+	private void formatTypeMembers(TypeDeclaration typeDeclaration) {
+		Alignment memberAlignment = this.scribe.createMemberAlignment("typeMembers", this.preferences.align_type_members_on_columns ? Alignment.M_MULTICOLUMN : Alignment.M_NO_ALIGNMENT, 3, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterMemberAlignment(memberAlignment);
+		ASTNode[] members = computeMergedMemberDeclarations(typeDeclaration);
+		boolean isChunkStart = false;
+		boolean ok = false;
+		int startIndex = 0;
+		do {
+			try {
+				for (int i = startIndex, max = members.length; i < max; i++) {
+					ASTNode member = members[i];
+					if (member instanceof FieldDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_FIELD, i, this.scribe.scanner.currentPosition);
+						if (member instanceof MultiFieldDeclaration) {
+							MultiFieldDeclaration multiField = (MultiFieldDeclaration) member;
+							
+							if (multiField.isStatic()) {
+								format(multiField, this, typeDeclaration.staticInitializerScope, isChunkStart, i == 0);
+							} else {
+								format(multiField, this, typeDeclaration.initializerScope, isChunkStart, i == 0);
+							}					
+						} else if (member instanceof Initializer) {
+							int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+							if (newLineBeforeChunk > 0 && i != 0) {
+								this.scribe.printEmptyLines(newLineBeforeChunk);
+							} else if (i == 0) {
+								int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+								if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+									this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+								}
+							}
+							Initializer initializer = (Initializer) member;
+							if (initializer.isStatic()) {
+								initializer.traverse(this, typeDeclaration.staticInitializerScope);
+							} else {
+								initializer.traverse(this, typeDeclaration.initializerScope);
+							}					
+						} else {
+							FieldDeclaration field = (FieldDeclaration) member;
+							if (field.isStatic()) {
+								format(field, this, typeDeclaration.staticInitializerScope, isChunkStart, i == 0);
+							} else {
+								format(field, this, typeDeclaration.initializerScope, isChunkStart, i == 0);
+							}					
+						}
+					} else if (member instanceof AbstractMethodDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_METHOD, i, this.scribe.scanner.currentPosition);
+						format((AbstractMethodDeclaration) member, typeDeclaration.scope, isChunkStart, i == 0);
+					} else if (member instanceof TypeDeclaration) {
+						isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_TYPE, i, this.scribe.scanner.currentPosition);
+						format((TypeDeclaration)member, typeDeclaration.scope, isChunkStart, i == 0);
+					}
+					if (isNextToken(TerminalTokens.TokenNameSEMICOLON)) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.printTrailingComment();
+					}
+					this.scribe.printNewLine();
+					// realign to the proper value
+					if (this.scribe.memberAlignment != null) {
+						// select the last alignment
+						this.scribe.indentationLevel = this.scribe.memberAlignment.originalIndentationLevel;
+					}
+				}
+				ok = true;
+			} catch(AlignmentException e){
+				startIndex = memberAlignment.chunkStartIndex;
+				this.scribe.redoMemberAlignment(e);
+			}
+		} while (!ok);
+		this.scribe.printComment();
+		this.scribe.exitMemberAlignment(memberAlignment);
+	}
+
+	private void formatTypeOpeningBraceForEnumConstant(String bracePosition, boolean insertSpaceBeforeBrace, TypeDeclaration typeDeclaration) {
+		int fieldCount = (typeDeclaration.fields == null) ? 0 : typeDeclaration.fields.length;
+		int methodCount = (typeDeclaration.methods == null) ? 0 : typeDeclaration.methods.length;
+		int typeCount = (typeDeclaration.memberTypes == null) ? 0 : typeDeclaration.memberTypes.length;
 	
-	public final int getCommentIndex(int position) {
-		if (this.commentPositions == null)
-			return -1;
-		int length = this.commentPositions.length;
-		if (length == 0) {
-			return -1;
+		if (methodCount == 1 && typeDeclaration.methods[0].isDefaultConstructor()) {
+			methodCount = 0;
 		}
-		int g = 0, d = length - 1;
-		int m = 0;
-		while (g <= d) {
-			m = (g + d) / 2;
-			int bound = this.commentPositions[m][1];
-			if (bound < 0) {
-				bound = -bound;
+		final int memberLength = fieldCount + methodCount+typeCount;
+
+		boolean insertNewLine = memberLength > 0;
+		
+		if (!insertNewLine) {
+			if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+				insertNewLine = this.preferences.insert_new_line_in_empty_enum_constant;
 			}
-			if (bound < position) {
-				g = m + 1;
-			} else if (bound > position) {
-				d = m - 1;
+		}
+	
+		formatOpeningBrace(bracePosition, insertSpaceBeforeBrace);
+		
+		if (insertNewLine) {
+			this.scribe.printNewLine();
+		}
+	}
+	private void formatTypeOpeningBrace(String bracePosition, boolean insertSpaceBeforeBrace, TypeDeclaration typeDeclaration) {
+		int fieldCount = (typeDeclaration.fields == null) ? 0 : typeDeclaration.fields.length;
+		int methodCount = (typeDeclaration.methods == null) ? 0 : typeDeclaration.methods.length;
+		int typeCount = (typeDeclaration.memberTypes == null) ? 0 : typeDeclaration.memberTypes.length;
+	
+		if (methodCount == 1 && typeDeclaration.methods[0].isDefaultConstructor()) {
+			methodCount = 0;
+		}
+		final int memberLength = fieldCount + methodCount + typeCount;
+
+		boolean insertNewLine = memberLength > 0;
+		
+		if (!insertNewLine) {
+			if (TypeDeclaration.kind(typeDeclaration.modifiers) == TypeDeclaration.ENUM_DECL) {
+				insertNewLine = this.preferences.insert_new_line_in_empty_enum_declaration;
+			} else if ((typeDeclaration.bits & ASTNode.IsAnonymousTypeMASK) != 0) {
+				insertNewLine = this.preferences.insert_new_line_in_empty_anonymous_type_declaration;
 			} else {
-				return m;
+				insertNewLine = this.preferences.insert_new_line_in_empty_type_declaration;
 			}
 		}
-		return -(g + 1);
+	
+		formatOpeningBrace(bracePosition, insertSpaceBeforeBrace);
+		
+		if (insertNewLine) {
+			this.scribe.printNewLine();
+		}
 	}
+	private int getDimensions() {
 
-	public String getEmptyLines(int linesNumber) {
-		if (this.nlsTagCounter > 0) {
-			return EMPTY_STRING;
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		int dimensions = 0;
+		try {
+			int token;
+			while ((token = this.localScanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
+				switch(token) {
+					case TerminalTokens.TokenNameRBRACKET:
+						dimensions++;
+						break;
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+					case TerminalTokens.TokenNameLBRACKET :
+						break;
+					default:
+						return dimensions;
+				}
+			}
+		} catch(InvalidInputException e) {
+			// ignore
 		}
-		StringBuffer buffer = new StringBuffer();
-		if (lastNumberOfNewLines == 0) {
-			linesNumber++; // add an extra line breaks
-			for (int i = 0; i < linesNumber; i++) {
-                if (indentEmptyLines) printIndentationIfNecessary(buffer);
-				buffer.append(this.lineSeparator);
+		return dimensions;
+	}
+
+	private boolean hasComments() {
+
+		this.localScanner.resetTo(this.scribe.scanner.startPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			switch(this.localScanner.getNextToken()) {
+				case TerminalTokens.TokenNameCOMMENT_BLOCK :
+				case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+				case TerminalTokens.TokenNameCOMMENT_LINE :
+					return true;
 			}
-			lastNumberOfNewLines += linesNumber;
-			line += linesNumber;
-			column = 1;
-			needSpace = false;
-			this.pendingSpace = false;
-		} else if (lastNumberOfNewLines == 1) {
-			for (int i = 0; i < linesNumber; i++) {
-                if (indentEmptyLines) printIndentationIfNecessary(buffer);
-				buffer.append(this.lineSeparator);
+		} catch(InvalidInputException e) {
+			// ignore
+		}
+		return false;
+	}
+
+	private boolean isNextToken(int tokenName) {
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			int token = this.localScanner.getNextToken();
+			loop: while(true) {
+				switch(token) {
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						token = this.localScanner.getNextToken();
+						continue loop;
+					default:
+						break loop;
+				}
 			}
-			lastNumberOfNewLines += linesNumber;
-			line += linesNumber;
-			column = 1;
-			needSpace = false;
-			this.pendingSpace = false;
-		} else {
-			if ((lastNumberOfNewLines - 1) >= linesNumber) {
-				// there is no need to add new lines
-				return EMPTY_STRING;
+			return  token == tokenName;
+		} catch(InvalidInputException e) {
+			// ignore
+		}
+		return false;
+	}
+
+	private boolean isClosingGenericToken() {
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			int token = this.localScanner.getNextToken();
+			loop: while(true) {
+				switch(token) {
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						token = this.localScanner.getNextToken();
+						continue loop;
+					default:
+						break loop;
+				}
 			}
-			final int realNewLineNumber = linesNumber - lastNumberOfNewLines + 1;
-			for (int i = 0; i < realNewLineNumber; i++) {
-                if (indentEmptyLines) printIndentationIfNecessary(buffer);
-				buffer.append(this.lineSeparator);
+			switch(token) {
+				case TerminalTokens.TokenNameGREATER :
+				case TerminalTokens.TokenNameRIGHT_SHIFT :
+				case TerminalTokens.TokenNameUNSIGNED_RIGHT_SHIFT :
+					return true;
 			}
-			lastNumberOfNewLines += realNewLineNumber;
-			line += realNewLineNumber;
-			column = 1;
-			needSpace = false;
-			this.pendingSpace = false;
+		} catch(InvalidInputException e) {
+			// ignore
 		}
-		return String.valueOf(buffer);
+		return false;
 	}
 
-	public OptimizedReplaceEdit getLastEdit() {
-		if (this.editsIndex > 0) {
-			return this.edits[this.editsIndex - 1];
+	private boolean isGuardClause(Block block) {
+		return !commentStartsBlock(block.sourceStart, block.sourceEnd)
+				&& block.statements != null
+				&& block.statements.length == 1
+				&& (block.statements[0] instanceof ReturnStatement || block.statements[0] instanceof ThrowStatement);
+	}
+
+	private boolean isMultipleLocalDeclaration(LocalDeclaration localDeclaration) {
+
+		if (localDeclaration.declarationSourceStart == this.lastLocalDeclarationSourceStart) return true;
+		this.lastLocalDeclarationSourceStart = localDeclaration.declarationSourceStart;
+		return false;
+	}
+
+	private boolean isPartOfMultipleLocalDeclaration() {
+		this.localScanner.resetTo(this.scribe.scanner.currentPosition, this.scribe.scannerEndPosition - 1);
+		try {
+			int token;
+			while ((token = this.localScanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
+				switch(token) {
+					case TerminalTokens.TokenNameCOMMA ://90
+						return true;
+					case TerminalTokens.TokenNameCOMMENT_BLOCK :
+					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
+					case TerminalTokens.TokenNameCOMMENT_LINE :
+						break;
+					default:
+						return false;
+				}
+			}
+		} catch(InvalidInputException e) {
+			// ignore
 		}
-		return null;
+		return false;
 	}
-	
-	public final int getLineEnd(int lineNumber) {
-		if (this.lineEnds == null) 
-			return -1;
-		if (lineNumber >= this.lineEnds.length + 1) 
-			return this.scannerEndPosition;
-		if (lineNumber <= 0) 
-			return -1;
-		return this.lineEnds[lineNumber-1]; // next line start one character behind the lineEnd of the previous line	
+
+	private void manageClosingParenthesizedExpression(Expression expression, int numberOfParens) {
+		for (int i = 0; i < numberOfParens; i++) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_parenthesized_expression);
+		}
 	}
-	
-	Alignment getMemberAlignment() {
-		return this.memberAlignment;
+
+	private void manageOpeningParenthesizedExpression(Expression expression, int numberOfParens) {
+		for (int i = 0; i < numberOfParens; i++) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_parenthesized_expression);
+			if (this.preferences.insert_space_after_opening_paren_in_parenthesized_expression) {
+				this.scribe.space();
+			}
+		}
 	}
-	
-	public String getNewLine() {
-		if (this.nlsTagCounter > 0) {
-			return EMPTY_STRING;
+			
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.AllocationExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		AllocationExpression allocationExpression,
+		BlockScope scope) {
+		// 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
+
+		final int numberOfParens = (allocationExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(allocationExpression, numberOfParens);
 		}
-		if (lastNumberOfNewLines >= 1) {
-			column = 1; // ensure that the scribe is at the beginning of a new line
-			return EMPTY_STRING;
+		this.scribe.printNextToken(TerminalTokens.TokenNamenew);
+		TypeReference[] typeArguments = allocationExpression.typeArguments;
+		if (typeArguments != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+				int length = typeArguments.length;
+				for (int i = 0; i < length - 1; i++) {
+					typeArguments[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+					if (this.preferences.insert_space_after_comma_in_type_arguments) {
+						this.scribe.space();
+					}				
+				}
+				typeArguments[length - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+				}
+				if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+		} else {
+			this.scribe.space();
 		}
-		line++;
-		lastNumberOfNewLines = 1;
-		column = 1;
-		needSpace = false;
-		this.pendingSpace = false;
-		return this.lineSeparator;
+
+		allocationExpression.type.traverse(this, scope);
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+
+		final Expression[] arguments = allocationExpression.arguments;
+		if (arguments != null) {
+			if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+				this.scribe.space();
+			}			
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment =this.scribe.createAlignment(
+					"allocation",//$NON-NLS-1$
+					this.preferences.alignment_for_arguments_in_allocation_expression,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_allocation_expression);
+							this.scribe.printTrailingComment();
+						}
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && this.preferences.insert_space_after_comma_in_allocation_expression) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, scope);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation); 
+		}
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(allocationExpression, numberOfParens);
+		}
+		return false;
 	}
 
-	/** 
-	 * Answer next indentation level based on column estimated position
-	 * (if column is not indented, then use indentationLevel)
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
 	 */
-	public int getNextIndentationLevel(int someColumn) {
-		int indent = someColumn - 1;
-		if (indent == 0)
-			return this.indentationLevel;
-		if (this.tabChar == DefaultCodeFormatterOptions.TAB) {
-			if (this.useTabsOnlyForLeadingIndents) {
-				return indent;
+	public boolean visit(
+		AND_AND_Expression and_and_Expression,
+		BlockScope scope) {
+			
+		return dumpBinaryExpression(and_and_Expression, TerminalTokens.TokenNameAND_AND, scope);
+	}
+	public boolean visit(
+			AnnotationMethodDeclaration annotationTypeMemberDeclaration,
+			ClassScope scope) {        
+        /*
+         * Print comments to get proper line number
+         */
+        this.scribe.printComment();        
+        this.scribe.printModifiers(annotationTypeMemberDeclaration.annotations, this);
+		this.scribe.space();
+		/*
+		 * Print the method return type
+		 */	
+		final TypeReference returnType = annotationTypeMemberDeclaration.returnType;
+		final MethodScope annotationTypeMemberDeclarationScope = annotationTypeMemberDeclaration.scope;
+		
+		if (returnType != null) {
+			returnType.traverse(this, annotationTypeMemberDeclarationScope);
+		}
+		/*
+		 * Print the method name
+		 */
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_annotation_type_member_declaration); 
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_annotation_type_member_declaration); 
+
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = annotationTypeMemberDeclaration.extendedDimensions;
+		if (extraDimensions != 0) {
+			 for (int i = 0; i < extraDimensions; i++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
+		}
+
+		Expression defaultValue = annotationTypeMemberDeclaration.defaultValue;
+		if (defaultValue != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNamedefault, true);
+			this.scribe.space();
+			defaultValue.traverse(this, (BlockScope) null);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Argument, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(Argument argument, BlockScope scope) {
+
+		if (argument.modifiers != NO_MODIFIERS || argument.annotations != null) {
+	        this.scribe.printComment();
+			this.scribe.printModifiers(argument.annotations, this);
+			this.scribe.space();
+		}
+
+		/*
+		 * Argument type 
+		 */
+		if (argument.type != null) {
+			argument.type.traverse(this, scope);
+		}
+		
+		if (argument.isVarArgs()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameELLIPSIS, this.preferences.insert_space_before_ellipsis);
+			if (this.preferences.insert_space_after_ellipsis) {
+				this.scribe.space();
 			}
-			int rem = indent % this.indentationSize;
-			int addition = rem == 0 ? 0 : this.indentationSize - rem; // round to superior
-			return indent + addition;
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false);
 		} else {
-			return indent;
+			/*
+			 * Print the argument name
+			 */	
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
 		}
+
+
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = getDimensions();
+		if (extraDimensions != 0) {
+			 for (int i = 0; i < extraDimensions; i++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
+		}
+		
+		return false;
 	}
 
-	private String getPreserveEmptyLines(int count) {
-		if (count > 0) {
-			if (this.formatter.preferences.number_of_empty_lines_to_preserve != 0) {
-				int linesToPreserve = Math.min(count, this.formatter.preferences.number_of_empty_lines_to_preserve);
-				return this.getEmptyLines(linesToPreserve);
-			} else {
-				return getNewLine();
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		ArrayAllocationExpression arrayAllocationExpression,
+		BlockScope scope) {
+
+			final int numberOfParens = (arrayAllocationExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(arrayAllocationExpression, numberOfParens);
 			}
+			this.scribe.printNextToken(TerminalTokens.TokenNamenew);
+			this.scribe.space();
+			arrayAllocationExpression.type.traverse(this, scope);
+			
+			final Expression[] dimensions = arrayAllocationExpression.dimensions;
+			int dimensionsLength = dimensions.length;
+			for (int i = 0; i < dimensionsLength; i++) {
+				if (this.preferences.insert_space_before_opening_bracket_in_array_allocation_expression) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET, false);
+				if (dimensions[i] != null) {
+					if (this.preferences.insert_space_after_opening_bracket_in_array_allocation_expression) {
+						this.scribe.space();
+					}
+					dimensions[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET, this.preferences.insert_space_before_closing_bracket_in_array_allocation_expression);
+				} else {
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET, this.preferences.insert_space_between_empty_brackets_in_array_allocation_expression);
+				}
+			}
+			final ArrayInitializer initializer = arrayAllocationExpression.initializer;
+			if (initializer != null) {
+				initializer.traverse(this, scope);
+			}
+
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(arrayAllocationExpression, numberOfParens);
+			}
+			return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayInitializer, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ArrayInitializer arrayInitializer, BlockScope scope) {		final int numberOfParens = (arrayInitializer.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(arrayInitializer, numberOfParens);
 		}
-		return EMPTY_STRING;
-	}
-	
-	public TextEdit getRootEdit() {
-		MultiTextEdit edit = null;
-		int length = this.textRegionEnd - this.textRegionStart + 1;
-		if (this.textRegionStart <= 0) {
-			if (length <= 0) {
-				edit = new MultiTextEdit(0, 0);
+		
+		final Expression[] expressions = arrayInitializer.expressions;
+		if (expressions != null) {
+			String array_initializer_brace_position = this.preferences.brace_position_for_array_initializer;
+			formatOpeningBrace(array_initializer_brace_position, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+		
+			int expressionsLength = expressions.length;
+			final boolean insert_new_line_after_opening_brace = this.preferences.insert_new_line_after_opening_brace_in_array_initializer;
+			if (expressionsLength > 1) {
+				if (insert_new_line_after_opening_brace) {
+					this.scribe.printNewLine();
+				}
+				Alignment arrayInitializerAlignment =this.scribe.createAlignment(
+						"array_initializer",//$NON-NLS-1$
+						this.preferences.alignment_for_expressions_in_array_initializer,
+						Alignment.R_OUTERMOST,
+						expressionsLength,
+						this.scribe.scanner.currentPosition,
+						this.preferences.continuation_indentation_for_array_initializer,
+						true);
+				
+				if (insert_new_line_after_opening_brace) {
+				    arrayInitializerAlignment.fragmentIndentations[0] = arrayInitializerAlignment.breakIndentationLevel;
+				}
+				
+				this.scribe.enterAlignment(arrayInitializerAlignment);
+				boolean ok = false;
+				do {
+					try {
+						this.scribe.alignFragment(arrayInitializerAlignment, 0);
+						if (this.preferences.insert_space_after_opening_brace_in_array_initializer) {
+							this.scribe.space();
+						}
+						expressions[0].traverse(this, scope);
+						for (int i = 1; i < expressionsLength; i++) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+							this.scribe.printTrailingComment();
+							this.scribe.alignFragment(arrayInitializerAlignment, i);
+							if (this.preferences.insert_space_after_comma_in_array_initializer) {
+								this.scribe.space();
+							}
+							expressions[i].traverse(this, scope);
+							if (i == expressionsLength - 1) {
+								if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+									this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+									this.scribe.printTrailingComment();
+								}
+							}
+						}
+						ok = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
+					}
+				} while (!ok);
+				this.scribe.exitAlignment(arrayInitializerAlignment, true);
 			} else {
-				edit = new MultiTextEdit(0, this.textRegionEnd + 1);
+				if (insert_new_line_after_opening_brace) {
+					this.scribe.printNewLine();
+					this.scribe.indent();
+				}
+				// we don't need to use an alignment
+				if (this.preferences.insert_space_after_opening_brace_in_array_initializer) {
+					this.scribe.space();
+				} else {
+					this.scribe.needSpace = false;
+				}
+				expressions[0].traverse(this, scope);
+				if (isNextToken(TerminalTokens.TokenNameCOMMA)) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_array_initializer);
+					this.scribe.printTrailingComment();
+				}
+				if (insert_new_line_after_opening_brace) {
+					this.scribe.unIndent();
+				}
 			}
+			if (this.preferences.insert_new_line_before_closing_brace_in_array_initializer) {
+				this.scribe.printNewLine();
+			} else if (this.preferences.insert_space_before_closing_brace_in_array_initializer) {
+				this.scribe.space();
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false); 
+			if (array_initializer_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+				this.scribe.unIndent();
+			}	
 		} else {
-			edit = new MultiTextEdit(this.textRegionStart, this.textRegionEnd - this.textRegionStart + 1);
-		}
-		for (int i= 0, max = this.editsIndex; i < max; i++) {
-			OptimizedReplaceEdit currentEdit = edits[i];
-			if (isValidEdit(currentEdit)) {
-				edit.addChild(new ReplaceEdit(currentEdit.offset, currentEdit.length, currentEdit.replacement));
+			boolean keepEmptyArrayInitializerOnTheSameLine = this.preferences.keep_empty_array_initializer_on_one_line;
+			String array_initializer_brace_position = this.preferences.brace_position_for_array_initializer;
+			if (keepEmptyArrayInitializerOnTheSameLine) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACE, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, this.preferences.insert_space_between_empty_braces_in_array_initializer); 
+			} else {
+				formatOpeningBrace(array_initializer_brace_position, this.preferences.insert_space_before_opening_brace_in_array_initializer);
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE, false); 
+				if (array_initializer_brace_position.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+					this.scribe.unIndent();
+				}
 			}
 		}
-		this.edits = null;
-		return edit;
+	
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayInitializer, numberOfParens);
+		}
+		return false;
 	}
 	
-	public void handleLineTooLong() {
-		// search for closest breakable alignment, using tiebreak rules
-		// look for outermost breakable one
-		int relativeDepth = 0, outerMostDepth = -1;
-		Alignment targetAlignment = this.currentAlignment;
-		while (targetAlignment != null){
-			if (targetAlignment.tieBreakRule == Alignment.R_OUTERMOST && targetAlignment.couldBreak()){
-				outerMostDepth = relativeDepth;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+		BlockScope scope) {
+
+			final int numberOfParens = (arrayQualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
 			}
-			targetAlignment = targetAlignment.enclosing;
-			relativeDepth++;
+			this.scribe.printArrayQualifiedReference(arrayQualifiedTypeReference.tokens.length, arrayQualifiedTypeReference.sourceEnd);
+			int dimensions = getDimensions();
+			if (dimensions != 0) {
+				for (int i = 0; i < dimensions; i++) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+				}
+			}
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
+			}
+			return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(
+		ArrayQualifiedTypeReference arrayQualifiedTypeReference,
+		ClassScope scope) {
+
+			final int numberOfParens = (arrayQualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
+			}
+			this.scribe.printArrayQualifiedReference(arrayQualifiedTypeReference.tokens.length, arrayQualifiedTypeReference.sourceEnd);
+			int dimensions = getDimensions();
+			if (dimensions != 0) {
+				for (int i = 0; i < dimensions; i++) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+					this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+				}
+			}
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(arrayQualifiedTypeReference, numberOfParens);
+			}
+			return false;
+	}
+
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ArrayReference arrayReference, BlockScope scope) {
+
+		final int numberOfParens = (arrayReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(arrayReference, numberOfParens);
 		}
-		if (outerMostDepth >= 0) {
-			throw new AlignmentException(AlignmentException.LINE_TOO_LONG, outerMostDepth);
+		arrayReference.receiver.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET, this.preferences.insert_space_before_opening_bracket_in_array_reference);
+		if (this.preferences.insert_space_after_opening_bracket_in_array_reference) {
+			this.scribe.space();
 		}
-		// look for innermost breakable one
-		relativeDepth = 0;
-		targetAlignment = this.currentAlignment;
-		while (targetAlignment != null){
-			if (targetAlignment.couldBreak()){
-				throw new AlignmentException(AlignmentException.LINE_TOO_LONG, relativeDepth);
+		arrayReference.position.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET, this.preferences.insert_space_before_closing_bracket_in_array_reference);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayReference, numberOfParens);
+		}
+		return false;
+	}
+	
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		ArrayTypeReference arrayTypeReference,
+		BlockScope scope) {
+
+		final int numberOfParens = (arrayTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
+		
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
 			}
-			targetAlignment = targetAlignment.enclosing;
-			relativeDepth++;
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			}
 		}
-		// did not find any breakable location - proceed
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
+		return false;
 	}
 
-	/*
-	 * Check if there is a NLS tag on this line. If yes, return true, returns false otherwise.
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
 	 */
-	private boolean hasNLSTag(int sourceStart) {
-		// search the last comment where commentEnd < current lineEnd
-		if (this.lineEnds == null) return false;
-		int index = Arrays.binarySearch(this.lineEnds, sourceStart);
-		int currentLineEnd = this.getLineEnd(-index);
-		if (currentLineEnd != -1) {
-			int commentIndex = getCommentIndex(currentLineEnd);
-			if (commentIndex < 0) {
-				commentIndex = -commentIndex - 2;
+	public boolean visit(
+		ArrayTypeReference arrayTypeReference,
+		ClassScope scope) {
+
+		final int numberOfParens = (arrayTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) { 
+			manageOpeningParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
 			}
-			if (commentIndex >= 0 && commentIndex < this.commentPositions.length) {
-				int start = this.commentPositions[commentIndex][0];
-				if (start < 0) {
-					start = -start;
-					// check that we are on the same line
-					int lineIndexForComment = Arrays.binarySearch(this.lineEnds, start);
-					if (lineIndexForComment == index) {
-						return CharOperation.indexOf(Scanner.TAG_PREFIX, this.scanner.source, true, start) != -1;
-					}
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
 				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
 			}
 		}
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(arrayTypeReference, numberOfParens);
+		}
 		return false;
 	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.AssertStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(AssertStatement assertStatement, BlockScope scope) {
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameassert);
+		this.scribe.space();
+		assertStatement.assertExpression.traverse(this, scope);
+		
+		if (assertStatement.exceptionArgument != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, this.preferences.insert_space_before_colon_in_assert);
+			if (this.preferences.insert_space_after_colon_in_assert) {
+				this.scribe.space();
+			}
+			assertStatement.exceptionArgument.traverse(this, scope);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);		
+		this.scribe.printTrailingComment();
+		return false;
+	}
 	
-	public void indent() {
-		this.indentationLevel += this.indentationSize;
-		this.numberOfIndentations++;
-	}	
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Assignment, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(Assignment assignment, BlockScope scope) {
 
+		final int numberOfParens = (assignment.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(assignment, numberOfParens);
+		}
+		assignment.lhs.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+		if (this.preferences.insert_space_after_assignment_operator) {
+			this.scribe.space();
+		}
+
+		Alignment assignmentAlignment = this.scribe.createAlignment("assignmentAlignment", this.preferences.alignment_for_assignment, Alignment.R_OUTERMOST, 1, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterAlignment(assignmentAlignment);
+		boolean ok = false;
+		do {
+			try {
+				this.scribe.alignFragment(assignmentAlignment, 0);
+				assignment.expression.traverse(this, scope);
+				ok = true;
+			} catch(AlignmentException e){
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);		
+		this.scribe.exitAlignment(assignmentAlignment, true);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(assignment, numberOfParens);
+		}
+		return false;
+	}
+
 	/**
-	 * @param compilationUnitSource
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.BinaryExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
 	 */
-	public void initializeScanner(char[] compilationUnitSource) {
-		this.scanner.setSource(compilationUnitSource);
-		this.scannerEndPosition = compilationUnitSource.length;
-		this.scanner.resetTo(0, this.scannerEndPosition);
-		this.edits = new OptimizedReplaceEdit[INITIAL_SIZE];
-	}	
+	public boolean visit(BinaryExpression binaryExpression, BlockScope scope) {
+
+		switch((binaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
+			case OperatorIds.AND :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameAND, scope);
+			case OperatorIds.DIVIDE :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameDIVIDE, scope);
+			case OperatorIds.GREATER :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameGREATER, scope);
+			case OperatorIds.GREATER_EQUAL :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameGREATER_EQUAL, scope);
+			case OperatorIds.LEFT_SHIFT :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameLEFT_SHIFT, scope);
+			case OperatorIds.LESS :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameLESS, scope);
+			case OperatorIds.LESS_EQUAL :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameLESS_EQUAL, scope);
+			case OperatorIds.MINUS :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameMINUS, scope);
+			case OperatorIds.MULTIPLY :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameMULTIPLY, scope);
+			case OperatorIds.OR :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameOR, scope);
+			case OperatorIds.PLUS :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNamePLUS, scope);
+			case OperatorIds.REMAINDER :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameREMAINDER, scope);
+			case OperatorIds.RIGHT_SHIFT :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameRIGHT_SHIFT, scope);
+			case OperatorIds.UNSIGNED_RIGHT_SHIFT :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameUNSIGNED_RIGHT_SHIFT, scope);
+			case OperatorIds.XOR :
+				return dumpBinaryExpression(binaryExpression, TerminalTokens.TokenNameXOR, scope);
+			default:
+				throw new IllegalStateException();
+		}
+	}
 	
-	private boolean isValidEdit(OptimizedReplaceEdit edit) {
-		final int editLength= edit.length;
-		final int editReplacementLength= edit.replacement.length();
-		final int editOffset= edit.offset;
-		if (editLength != 0) {
-			if (this.textRegionStart <= editOffset && (editOffset + editLength - 1) <= this.textRegionEnd) {
-				if (editReplacementLength != 0 && editLength == editReplacementLength) {
-					for (int i = editOffset, max = editOffset + editLength; i < max; i++) {
-						if (scanner.source[i] != edit.replacement.charAt(i - editOffset)) {
-							return true;
-						}
-					}
-					return false;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Block, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(Block block, BlockScope scope) {
+		formatBlock(block, scope, this.preferences.brace_position_for_block, this.preferences.insert_space_before_opening_brace_in_block);	
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.BreakStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(BreakStatement breakStatement, BlockScope scope) {
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNamebreak);
+		if (breakStatement.label != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.CaseStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(CaseStatement caseStatement, BlockScope scope) {		
+		if (caseStatement.constantExpression == null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNamedefault);
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, this.preferences.insert_space_before_colon_in_default);
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNamecase);
+			this.scribe.space();
+			caseStatement.constantExpression.traverse(this, scope);
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, this.preferences.insert_space_before_colon_in_case);
+		}
+		return false;
+	}
+
+
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.CastExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(CastExpression castExpression, BlockScope scope) {
+
+		final int numberOfParens = (castExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(castExpression, numberOfParens);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN);
+		if (this.preferences.insert_space_after_opening_paren_in_cast) {
+			this.scribe.space();
+		}
+		castExpression.type.traverse(this, scope);
+
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_cast);
+		if (this.preferences.insert_space_after_closing_paren_in_cast) {
+			this.scribe.space();
+		}
+		castExpression.expression.traverse(this, scope);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(castExpression, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.CharLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(CharLiteral charLiteral, BlockScope scope) {
+
+		final int numberOfParens = (charLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(charLiteral, numberOfParens);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameCharacterLiteral);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(charLiteral, numberOfParens);
+		}
+		return false;
+	}
+
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ClassLiteralAccess classLiteral, BlockScope scope) {
+
+		final int numberOfParens = (classLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(classLiteral, numberOfParens);
+		}
+		classLiteral.type.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+		this.scribe.printNextToken(TerminalTokens.TokenNameclass);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(classLiteral, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Clinit, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(Clinit clinit, ClassScope scope) {
+
+		return false;
+	}
+	
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration, org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope)
+	 */
+	public boolean visit(
+		CompilationUnitDeclaration compilationUnitDeclaration,
+		CompilationUnitScope scope) {
+		
+		// fake new line to handle empty lines before package declaration or import declarations
+		this.scribe.lastNumberOfNewLines = 1;
+		/* 
+		 * Package declaration
+		 */
+		final boolean hasPackage = compilationUnitDeclaration.currentPackage != null;
+		if (hasPackage) {
+			if (hasComments()) {
+				this.scribe.printComment();
+			}
+			int blankLinesBeforePackage = this.preferences.blank_lines_before_package;
+			if (blankLinesBeforePackage > 0) {
+				this.scribe.printEmptyLines(blankLinesBeforePackage);
+			}
+
+			this.scribe.printModifiers(compilationUnitDeclaration.currentPackage.annotations, this);
+			this.scribe.space();
+			// dump the package keyword
+			this.scribe.printNextToken(TerminalTokens.TokenNamepackage);
+			this.scribe.space();
+			this.scribe.printQualifiedReference(compilationUnitDeclaration.currentPackage.sourceEnd);
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+			int blankLinesAfterPackage = this.preferences.blank_lines_after_package;
+			if (blankLinesAfterPackage > 0) {
+				this.scribe.printEmptyLines(blankLinesAfterPackage);
+			} else {
+				this.scribe.printNewLine();
+			}			
+		} else {
+			this.scribe.printComment();
+		}
+		
+		/*
+		 * Import statements
+		 */
+		final ImportReference[] imports = compilationUnitDeclaration.imports;
+		if (imports != null) {
+			if (hasPackage) {
+				int blankLinesBeforeImports = this.preferences.blank_lines_before_imports;
+				if (blankLinesBeforeImports > 0) {
+					this.scribe.printEmptyLines(blankLinesBeforeImports);
+				}
+			}
+			int importLength = imports.length;
+			for (int i = 0; i < importLength; i++) {
+				imports[i].traverse(this, scope);
+			}			
+			
+			int blankLinesAfterImports = this.preferences.blank_lines_after_imports;
+			if (blankLinesAfterImports > 0) {
+				this.scribe.printEmptyLines(blankLinesAfterImports);
+			}
+		}
+
+		formatEmptyTypeDeclaration(true);
+		
+		int blankLineBetweenTypeDeclarations = this.preferences.blank_lines_between_type_declarations;
+		/*
+		 * Type declarations
+		 */
+		final TypeDeclaration[] types = compilationUnitDeclaration.types;
+		if (types != null) {
+			int typesLength = types.length;
+			for (int i = 0; i < typesLength - 1; i++) {
+				types[i].traverse(this, scope);
+				formatEmptyTypeDeclaration(false);
+				if (blankLineBetweenTypeDeclarations != 0) {
+					this.scribe.printEmptyLines(blankLineBetweenTypeDeclarations);
 				} else {
-					return true;
+					this.scribe.printNewLine();
 				}
-			} else if (editOffset + editLength == this.textRegionStart) {
-				int i = editOffset;
-				for (int max = editOffset + editLength; i < max; i++) {
-					int replacementStringIndex = i - editOffset;
-					if (replacementStringIndex >= editReplacementLength || scanner.source[i] != edit.replacement.charAt(replacementStringIndex)) {
-						break;
-					}
+			}
+			types[typesLength - 1].traverse(this, scope);
+		}
+		this.scribe.printEndOfCompilationUnit();
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.CompoundAssignment, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		CompoundAssignment compoundAssignment,
+		BlockScope scope) {
+			
+		final int numberOfParens = (compoundAssignment.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(compoundAssignment, numberOfParens);
+		}
+		compoundAssignment.lhs.traverse(this, scope);
+		
+		/*
+		 * Print the operator
+		 */
+		int operator;
+		switch(compoundAssignment.operator) {
+			case OperatorIds.PLUS :
+				operator = TerminalTokens.TokenNamePLUS_EQUAL;
+				break;
+			case OperatorIds.MINUS :
+				operator = TerminalTokens.TokenNameMINUS_EQUAL;
+				break;
+			case OperatorIds.MULTIPLY :
+				operator = TerminalTokens.TokenNameMULTIPLY_EQUAL;
+				break;
+			case OperatorIds.DIVIDE :
+				operator = TerminalTokens.TokenNameDIVIDE_EQUAL;
+				break;
+			case OperatorIds.AND :
+				operator = TerminalTokens.TokenNameAND_EQUAL;
+				break;
+			case OperatorIds.OR :
+				operator = TerminalTokens.TokenNameOR_EQUAL;
+				break;
+			case OperatorIds.XOR :
+				operator = TerminalTokens.TokenNameXOR_EQUAL;
+				break;
+			case OperatorIds.REMAINDER :
+				operator = TerminalTokens.TokenNameREMAINDER_EQUAL;
+				break;
+			case OperatorIds.LEFT_SHIFT :
+				operator = TerminalTokens.TokenNameLEFT_SHIFT_EQUAL;
+				break;
+			case OperatorIds.RIGHT_SHIFT :
+				operator = TerminalTokens.TokenNameRIGHT_SHIFT_EQUAL;
+				break;
+			default: // OperatorIds.UNSIGNED_RIGHT_SHIFT :
+				operator = TerminalTokens.TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL;
+		}
+		
+		this.scribe.printNextToken(operator, this.preferences.insert_space_before_assignment_operator);
+		if (this.preferences.insert_space_after_assignment_operator) {
+			this.scribe.space();
+		}
+		Alignment assignmentAlignment = this.scribe.createAlignment("compoundAssignmentAlignment", this.preferences.alignment_for_assignment, Alignment.R_OUTERMOST, 1, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterAlignment(assignmentAlignment);
+		boolean ok = false;
+		do {
+			try {
+				this.scribe.alignFragment(assignmentAlignment, 0);
+				compoundAssignment.expression.traverse(this, scope);
+				ok = true;
+			} catch(AlignmentException e){
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);		
+		this.scribe.exitAlignment(assignmentAlignment, true);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(compoundAssignment, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+     * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ConditionalExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+     */
+    public boolean visit(
+    	ConditionalExpression conditionalExpression,
+    	BlockScope scope) {
+    
+    	final int numberOfParens = (conditionalExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+    	if (numberOfParens > 0) {
+    		manageOpeningParenthesizedExpression(conditionalExpression, numberOfParens);
+    	}
+    	conditionalExpression.condition.traverse(this, scope);
+    
+    	Alignment conditionalExpressionAlignment =this.scribe.createAlignment(
+    			"conditionalExpression", //$NON-NLS-1$
+    			this.preferences.alignment_for_conditional_expression,
+    			2,
+    			this.scribe.scanner.currentPosition);
+    
+    	this.scribe.enterAlignment(conditionalExpressionAlignment);
+    	boolean ok = false;
+    	do {
+    		try {
+    			this.scribe.alignFragment(conditionalExpressionAlignment, 0);
+    			this.scribe.printNextToken(TerminalTokens.TokenNameQUESTION, this.preferences.insert_space_before_question_in_conditional);
+    
+    			if (this.preferences.insert_space_after_question_in_conditional) {
+    				this.scribe.space();
+    			}
+    			conditionalExpression.valueIfTrue.traverse(this, scope);
+    			this.scribe.printTrailingComment();
+    			this.scribe.alignFragment(conditionalExpressionAlignment, 1);
+    			this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, this.preferences.insert_space_before_colon_in_conditional);
+    
+    			if (this.preferences.insert_space_after_colon_in_conditional) {
+    				this.scribe.space();
+    			}
+    			conditionalExpression.valueIfFalse.traverse(this, scope);
+    
+    			ok = true;
+    		} catch (AlignmentException e) {
+    			this.scribe.redoAlignment(e);
+    		}
+    	} while (!ok);
+    	this.scribe.exitAlignment(conditionalExpressionAlignment, true);
+    		
+    	if (numberOfParens > 0) {
+    		manageClosingParenthesizedExpression(conditionalExpression, numberOfParens);
+    	}
+    	return false;	
+    }
+
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(
+		ConstructorDeclaration constructorDeclaration,
+		ClassScope scope) {
+			
+		if (constructorDeclaration.ignoreFurtherInvestigation) {
+			this.scribe.printComment();
+			this.scribe.scanner.resetTo(constructorDeclaration.declarationSourceEnd + 1, this.scribe.scannerEndPosition);
+			this.scribe.printTrailingComment();
+			return false;
+		}
+        /*
+         * Print comments to get proper line number
+         */
+        this.scribe.printComment();
+        final int line = this.scribe.line;
+		this.scribe.printModifiers(constructorDeclaration.annotations, this);
+		this.scribe.space();
+
+		TypeParameter[] typeParameters = constructorDeclaration.typeParameters;
+		if (typeParameters != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_parameters); 
+			if (this.preferences.insert_space_after_opening_angle_bracket_in_type_parameters) {
+				this.scribe.space();
+			}
+			int length = typeParameters.length;
+			for (int i = 0; i < length - 1; i++) {
+				typeParameters[i].traverse(this, constructorDeclaration.scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_parameters);
+				if (this.preferences.insert_space_after_comma_in_type_parameters) {
+					this.scribe.space();
+				}				
+			}
+			typeParameters[length - 1].traverse(this, constructorDeclaration.scope);
+			if (isClosingGenericToken()) {
+				this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_parameters); 
+			}
+			if (this.preferences.insert_space_after_closing_angle_bracket_in_type_parameters) {
+				this.scribe.space();
+			}
+		}
+
+		/*
+		 * Print the method name
+		 */	
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+
+		formatMethodArguments(
+			constructorDeclaration, 
+			this.preferences.insert_space_before_opening_paren_in_constructor_declaration,
+			this.preferences.insert_space_between_empty_parens_in_constructor_declaration,
+			this.preferences.insert_space_before_closing_paren_in_constructor_declaration,
+			this.preferences.insert_space_after_opening_paren_in_constructor_declaration,
+			this.preferences.insert_space_before_comma_in_constructor_declaration_parameters,
+			this.preferences.insert_space_after_comma_in_constructor_declaration_parameters,
+			this.preferences.alignment_for_parameters_in_constructor_declaration);
+
+		formatThrowsClause(
+				constructorDeclaration,
+				this.preferences.insert_space_before_comma_in_constructor_declaration_throws,
+				this.preferences.insert_space_after_comma_in_constructor_declaration_throws,
+				this.preferences.alignment_for_throws_clause_in_constructor_declaration);
+
+		if (!constructorDeclaration.isNative() && !constructorDeclaration.isAbstract()) {
+			/*
+			 * Method body
+			 */
+			String constructor_declaration_brace = this.preferences.brace_position_for_constructor_declaration;
+			formatLeftCurlyBrace(line, constructor_declaration_brace);
+			formatOpeningBrace(constructor_declaration_brace, this.preferences.insert_space_before_opening_brace_in_constructor_declaration);
+			final int numberOfBlankLinesAtBeginningOfMethodBody = this.preferences.blank_lines_at_beginning_of_method_body;
+			if (numberOfBlankLinesAtBeginningOfMethodBody > 0) {
+				this.scribe.printEmptyLines(numberOfBlankLinesAtBeginningOfMethodBody);
+			}
+			if (constructorDeclaration.constructorCall != null && !constructorDeclaration.constructorCall.isImplicitSuper()) {
+				this.scribe.printNewLine();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.indent();
 				}
-				if (i - editOffset != editReplacementLength && i != editOffset + editLength - 1) {
-					edit.offset = textRegionStart;
-					edit.length = 0;
-					edit.replacement = edit.replacement.substring(i - editOffset);
-					return true;
+				constructorDeclaration.constructorCall.traverse(this, constructorDeclaration.scope);
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.unIndent();
 				}
 			}
-		} else if (this.textRegionStart <= editOffset && editOffset <= this.textRegionEnd) {
-			return true;
-		} else if (editOffset == this.scannerEndPosition && editOffset == this.textRegionEnd + 1) {
-			return true;
+			final Statement[] statements = constructorDeclaration.statements;
+			if (statements != null) {
+				this.scribe.printNewLine();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.indent();
+				}
+				formatStatements(constructorDeclaration.scope, statements, true);
+				this.scribe.printComment();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.unIndent();
+				}
+			} else if (this.preferences.insert_new_line_in_empty_method_body) {
+				this.scribe.printNewLine();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.indent();
+				}
+				this.scribe.printComment();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.unIndent();
+				}
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+			this.scribe.printTrailingComment();
+			if (constructor_declaration_brace.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+				this.scribe.unIndent();
+			}
+		} else {
+			// no method body
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
 		}
 		return false;
 	}
 
-	private void preserveEmptyLines(int count, int insertPosition) {
-		if (count > 0) {
-			if (this.formatter.preferences.number_of_empty_lines_to_preserve != 0) {
-				int linesToPreserve = Math.min(count, this.formatter.preferences.number_of_empty_lines_to_preserve);
-				this.printEmptyLines(linesToPreserve, insertPosition);
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ContinueStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ContinueStatement continueStatement, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNamecontinue);
+		if (continueStatement.label != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
+	}
+
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.DoStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(DoStatement doStatement, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNamedo);
+		final int line = this.scribe.line;
+		
+		final Statement action = doStatement.action;
+		if (action != null) {
+			if (action instanceof Block) {
+				formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+				action.traverse(this, scope);
+			} else if (action instanceof EmptyStatement) {
+				/*
+				 * This is an empty statement
+				 */
+				formatNecessaryEmptyStatement();
 			} else {
-				printNewLine(insertPosition);
+				this.scribe.printNewLine();
+				/* Martijn Kruithof {} */
+				formatStatementAsBlock(scope, line, action);
 			}
+		} else {
+			/*
+			 * This is an empty statement
+			 */
+			formatNecessaryEmptyStatement(); 
 		}
+		
+		if (this.preferences.insert_new_line_before_while_in_do_statement) {
+			this.scribe.printNewLine();
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNamewhile, this.preferences.insert_space_after_closing_brace_in_block);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_while);
+		
+		if (this.preferences.insert_space_after_opening_paren_in_while) {
+			this.scribe.space();
+		}
+		
+		doStatement.condition.traverse(this, scope);
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_while);
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
 	}
 
-	private void print(char[] s, boolean considerSpaceIfAny) {
-		if (checkLineWrapping && s.length + column > this.pageWidth) {
-			handleLineTooLong();
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.DoubleLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(DoubleLiteral doubleLiteral, BlockScope scope) {
+
+		final int numberOfParens = (doubleLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(doubleLiteral, numberOfParens);
 		}
-		this.lastNumberOfNewLines = 0;
-		printIndentationIfNecessary();
-		if (considerSpaceIfAny) {
-			this.space();
+		Constant constant = doubleLiteral.constant;
+		if (constant != null && constant.doubleValue() < 0) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameMINUS);			
 		}
-		if (this.pendingSpace) {
-			this.addInsertEdit(this.scanner.getCurrentTokenStartPosition(), " "); //$NON-NLS-1$
+		this.scribe.printNextToken(TerminalTokens.TokenNameDoubleLiteral);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(doubleLiteral, numberOfParens);
 		}
-		this.pendingSpace = false;	
-		this.needSpace = false;		
-		column += s.length;
-		needSpace = true;
+		return false;
 	}
 
-	private void printBlockComment(char[] s, boolean isJavadoc) {
-		int currentTokenStartPosition = this.scanner.getCurrentTokenStartPosition();
-		int currentTokenEndPosition = this.scanner.getCurrentTokenEndPosition() + 1;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.EmptyStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(EmptyStatement statement, BlockScope scope) {
+		if (this.preferences.put_empty_statement_on_new_line) {
+			this.scribe.printNewLine();
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;	
+	}
+	// field is an enum constant
+	public boolean visit(FieldDeclaration enumConstant, MethodScope scope) {
+        /*
+         * Print comments to get proper line number
+         */
+        this.scribe.printComment();
+        final int line = this.scribe.line; 
+        
+        this.scribe.printModifiers(enumConstant.annotations, this);
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false); 
+		formatEnumConstantArguments(
+			enumConstant,
+			this.preferences.insert_space_before_opening_paren_in_enum_constant,
+			this.preferences.insert_space_between_empty_parens_in_enum_constant,
+			this.preferences.insert_space_before_closing_paren_in_enum_constant,
+			this.preferences.insert_space_after_opening_paren_in_enum_constant,
+			this.preferences.insert_space_before_comma_in_enum_constant_arguments,
+			this.preferences.insert_space_after_comma_in_enum_constant_arguments,
+			this.preferences.alignment_for_arguments_in_enum_constant);			
 		
-		this.scanner.resetTo(currentTokenStartPosition, currentTokenEndPosition - 1);
-		int currentCharacter;
-		boolean isNewLine = false;
-		int start = currentTokenStartPosition;
-		int nextCharacterStart = currentTokenStartPosition;
-		printIndentationIfNecessary();
-		if (this.pendingSpace) {
-			this.addInsertEdit(currentTokenStartPosition, " "); //$NON-NLS-1$
+		Expression initialization = enumConstant.initialization;
+		if (initialization instanceof QualifiedAllocationExpression) {
+			TypeDeclaration typeDeclaration = ((QualifiedAllocationExpression) initialization).anonymousType;
+			int fieldsCount = typeDeclaration.fields == null ? 0 : typeDeclaration.fields.length;
+			int methodsCount = typeDeclaration.methods == null ? 0 : typeDeclaration.methods.length;
+			int membersCount = typeDeclaration.memberTypes == null ? 0 : typeDeclaration.memberTypes.length;
+			
+			/*
+			 * Type body
+			 */
+			String enum_constant_brace = this.preferences.brace_position_for_enum_constant;
+	
+	        formatLeftCurlyBrace(line, enum_constant_brace);
+			formatTypeOpeningBraceForEnumConstant(enum_constant_brace, this.preferences.insert_space_before_opening_brace_in_enum_constant, typeDeclaration);
+			
+			if (this.preferences.indent_body_declarations_compare_to_enum_constant_header) {
+				this.scribe.indent();
+			}
+	
+			if (fieldsCount != 0 || methodsCount != 0 || membersCount != 0) {
+				formatTypeMembers(typeDeclaration);
+			}
+
+			if (this.preferences.indent_body_declarations_compare_to_enum_constant_header) {
+				this.scribe.unIndent();
+			}
+			
+			if (this.preferences.insert_new_line_in_empty_enum_constant) {
+				this.scribe.printNewLine();
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+			this.scribe.printTrailingComment();
+			if (enum_constant_brace.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+				this.scribe.unIndent();
+			}
+			if (hasComments()) {
+				this.scribe.printNewLine();
+			}
 		}
-		this.needSpace = false;		
-		this.pendingSpace = false;		
-		int previousStart = currentTokenStartPosition;
+		return false;
+	}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.EqualExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(EqualExpression equalExpression, BlockScope scope) {
 
-		while (nextCharacterStart <= currentTokenEndPosition && (currentCharacter = this.scanner.getNextChar()) != -1) {
-			nextCharacterStart = this.scanner.currentPosition;
+		if ((equalExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT == OperatorIds.EQUAL_EQUAL) {
+			return dumpEqualityExpression(equalExpression, TerminalTokens.TokenNameEQUAL_EQUAL, scope);
+		} else {
+			return dumpEqualityExpression(equalExpression, TerminalTokens.TokenNameNOT_EQUAL, scope);
+		}			
+	}
 
-			switch(currentCharacter) {
-				case '\r' :
-					start = previousStart;
-					isNewLine = true;
-					if (this.scanner.getNextChar('\n')) {
-						currentCharacter = '\n';
-						nextCharacterStart = this.scanner.currentPosition;
-					}
-					break;
-				case '\n' :
-					start = previousStart;
-					isNewLine = true;
-					break;
-				default:
-					if (isNewLine) {
-						if (Character.isWhitespace((char) currentCharacter)) {
-							int previousStartPosition = this.scanner.currentPosition;
-							while(currentCharacter != -1 && currentCharacter != '\r' && currentCharacter != '\n' && Character.isWhitespace((char) currentCharacter)) {
-								previousStart = nextCharacterStart;
-								previousStartPosition = this.scanner.currentPosition;
-								currentCharacter = this.scanner.getNextChar();
-								nextCharacterStart = this.scanner.currentPosition;
-							}
-							if (currentCharacter == '\r' || currentCharacter == '\n') {
-								nextCharacterStart = previousStartPosition;
-							}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		ExplicitConstructorCall explicitConstructor,
+		BlockScope scope) {
+
+		if (explicitConstructor.isImplicitSuper()) {
+			return false;
+		}
+		final Expression qualification = explicitConstructor.qualification;
+		if (qualification != null) {
+			qualification.traverse(this, scope);
+			this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+		}
+
+		TypeReference[] typeArguments = explicitConstructor.typeArguments;
+		if (typeArguments != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+				int length = typeArguments.length;
+				for (int i = 0; i < length - 1; i++) {
+					typeArguments[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+					if (this.preferences.insert_space_after_comma_in_type_arguments) {
+						this.scribe.space();
+					}				
+				}
+				typeArguments[length - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+				}
+				if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+		}
+		
+		if (explicitConstructor.isSuperAccess()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNamesuper);
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNamethis);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+		
+		final Expression[] arguments = explicitConstructor.arguments;
+		if (arguments != null) {
+			if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+				this.scribe.space();
+			}
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment =this.scribe.createAlignment(
+					"explicit_constructor_call",//$NON-NLS-1$
+					this.preferences.alignment_for_arguments_in_explicit_constructor_call,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
+			do {
+				try {
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_explicit_constructor_call_arguments);
+							this.scribe.printTrailingComment();
 						}
-						this.column = 1;
-						this.line++;
-
-						StringBuffer buffer = new StringBuffer();
-						buffer.append(this.lineSeparator);
-						printIndentationIfNecessary(buffer);
-						buffer.append(' ');
-				
-						addReplaceEdit(start, previousStart - 1, String.valueOf(buffer));
-					} else {
-						this.column += (nextCharacterStart - previousStart);
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && this.preferences.insert_space_after_comma_in_explicit_constructor_call_arguments) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, scope);
 					}
-					isNewLine = false;
-			}
-			previousStart = nextCharacterStart;
-			this.scanner.currentPosition = nextCharacterStart;
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation); 
 		}
-		this.lastNumberOfNewLines = 0;
-		needSpace = false;
-		this.scanner.resetTo(currentTokenEndPosition, this.scannerEndPosition - 1);
-		if (isJavadoc) {
-			printNewLine();
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
+	}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.FalseLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(FalseLiteral falseLiteral, BlockScope scope) {
+
+		final int numberOfParens = (falseLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(falseLiteral, numberOfParens);
 		}
+		this.scribe.printNextToken(TerminalTokens.TokenNamefalse);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(falseLiteral, numberOfParens);
+		}
+		return false;
 	}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.FieldReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(FieldReference fieldReference, BlockScope scope) {
+
+		final int numberOfParens = (fieldReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(fieldReference, numberOfParens);
+		}
+		fieldReference.receiver.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(fieldReference, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.FloatLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(FloatLiteral floatLiteral, BlockScope scope) {
+
+		final int numberOfParens = (floatLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(floatLiteral, numberOfParens);
+		}
+		Constant constant = floatLiteral.constant;
+		if (constant != null && floatLiteral.constant.floatValue() < 0) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameMINUS);			
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameFloatingPointLiteral);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(floatLiteral, numberOfParens);
+		}
+		return false;
+	}
+	public boolean visit(ForeachStatement forStatement, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNamefor);
+	    final int line = this.scribe.line;
+	    this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_for);
+		
+		if (this.preferences.insert_space_after_opening_paren_in_for) {
+			this.scribe.space();
+		}
+		formatLocalDeclaration(forStatement.elementVariable, scope, false, false);
+
+		this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, this.preferences.insert_space_before_colon_in_for);
+		if (this.preferences.insert_space_after_colon_in_for) {
+			this.scribe.space();
+		}
+		forStatement.collection.traverse(this, scope);
+
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_for);
+		
+		final Statement action = forStatement.action;
+		if (action != null) {
+			if (action instanceof Block) {
+	            formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+				action.traverse(this, scope);
+			} else if (action instanceof EmptyStatement) {
+				/*
+				 * This is an empty statement
+				 */
+				formatNecessaryEmptyStatement();
+			} else {
+                this.scribe.printNewLine();
+                /* Martijn Kruithof {} */
+                formatStatementAsBlock(scope, line, action);
+            }
+		} else {
+			/*
+			 * This is an empty statement
+			 */
+			formatNecessaryEmptyStatement(); 
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ForStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ForStatement forStatement, BlockScope scope) {
 	
-	public void printEndOfCompilationUnit() {
-		try {
-			// if we have a space between two tokens we ensure it will be dumped in the formatted string
-			int currentTokenStartPosition = this.scanner.currentPosition;
-			boolean hasComment = false;
-			boolean hasLineComment = false;
-			boolean hasWhitespace = false;
-			int count = 0;
-			while (true) {
-				this.currentToken = this.scanner.getNextToken();
-				switch(this.currentToken) {
-					case TerminalTokens.TokenNameWHITESPACE :
-						char[] whiteSpaces = this.scanner.getCurrentTokenSource();
-						count = 0;
-						for (int i = 0, max = whiteSpaces.length; i < max; i++) {
-							switch(whiteSpaces[i]) {
-								case '\r' :
-									if ((i + 1) < max) {
-										if (whiteSpaces[i + 1] == '\n') {
-											i++;
-										}
-									}
-									count++;
-									break;
-								case '\n' :
-									count++;
-							}
+		this.scribe.printNextToken(TerminalTokens.TokenNamefor);
+	    final int line = this.scribe.line;
+	    this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_for);
+		
+		if (this.preferences.insert_space_after_opening_paren_in_for) {
+			this.scribe.space();
+		}
+		final Statement[] initializations = forStatement.initializations;
+		if (initializations != null) {
+			int length = initializations.length;
+			for (int i = 0; i < length; i++) {
+				if (initializations[i] instanceof LocalDeclaration) {
+					formatLocalDeclaration((LocalDeclaration) initializations[i], scope, this.preferences.insert_space_before_comma_in_for_inits, this.preferences.insert_space_after_comma_in_for_inits);
+				} else {
+					initializations[i].traverse(this, scope);
+					if (i >= 0 && (i < length - 1)) {
+						this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_for_inits);
+						if (this.preferences.insert_space_after_comma_in_for_inits) {
+							this.scribe.space();
 						}
-						if (count == 0) {
-							hasWhitespace = true;
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						} else if (hasComment) {
-							if (count == 1) {
-								this.printNewLine(this.scanner.getCurrentTokenStartPosition());
-							} else {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							}
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						} else if (hasLineComment) {
-							this.preserveEmptyLines(count, this.scanner.getCurrentTokenStartPosition());
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						} else {
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						}
-						currentTokenStartPosition = this.scanner.currentPosition;						
-						break;
-					case TerminalTokens.TokenNameCOMMENT_LINE :
-						if (count >= 1) {
-							if (count > 1) {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							} else if (count == 1) {
-								printNewLine(this.scanner.getCurrentTokenStartPosition());
-							}
-						} else if (hasWhitespace) {
-							space();
-						} 
-						hasWhitespace = false;
-						this.printCommentLine(this.scanner.getRawTokenSource());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasLineComment = true;		
-						count = 0;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_BLOCK :
-						if (count >= 1) {
-							if (count > 1) {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							} else if (count == 1) {
-								printNewLine(this.scanner.getCurrentTokenStartPosition());
-							}
-						} else if (hasWhitespace) {
-							space();
-						} 
-						hasWhitespace = false;
-						this.printBlockComment(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasLineComment = false;
-						hasComment = true;
-						count = 0;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
-						if (count >= 1) {
-							if (count > 1) {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							} else if (count == 1) {
-								printNewLine(this.scanner.getCurrentTokenStartPosition());
-							}
-						} else if (hasWhitespace) {
-							space();
-						} 
-						hasWhitespace = false;
-						this.printBlockComment(this.scanner.getRawTokenSource(), true);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasLineComment = false;
-						hasComment = true;
-						count = 0;
-						break;
-					case TerminalTokens.TokenNameSEMICOLON :
-						char[] currentTokenSource = this.scanner.getRawTokenSource();
-						this.print(currentTokenSource, this.formatter.preferences.insert_space_before_semicolon);
-						break;
-					case TerminalTokens.TokenNameEOF :
-						if (count >= 1 || this.formatter.preferences.insert_new_line_at_end_of_file_if_missing) {
-							this.printNewLine(this.scannerEndPosition);
-						}
-						return;
-					default :
-						// step back one token
-						this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-						return;
+						this.scribe.printTrailingComment();
+					}				
 				}
 			}
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
 		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon_in_for);
+		final Expression condition = forStatement.condition;
+		if (condition != null) {
+			if (this.preferences.insert_space_after_semicolon_in_for) {
+				this.scribe.space();
+			}
+			condition.traverse(this, scope);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon_in_for);
+		final Statement[] increments = forStatement.increments;
+		if (increments != null) {
+			if (this.preferences.insert_space_after_semicolon_in_for) {
+				this.scribe.space();
+			}
+			for (int i = 0, length = increments.length; i < length; i++) {
+				increments[i].traverse(this, scope);
+				if (i != length - 1) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_for_increments);
+					if (this.preferences.insert_space_after_comma_in_for_increments) {
+						this.scribe.space();
+					}
+					this.scribe.printTrailingComment();
+				}
+			}
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_for);
+		
+		final Statement action = forStatement.action;
+		if (action != null) {
+			if (action instanceof Block) {
+	            formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+				action.traverse(this, scope);
+			} else if (action instanceof EmptyStatement) {
+				/*
+				 * This is an empty statement
+				 */
+				formatNecessaryEmptyStatement();
+			} else {
+				this.scribe.printNewLine();
+                /* Martijn Kruithof {} */
+                formatStatementAsBlock(scope, line, action);
+            }
+		} else {
+			/*
+			 * This is an empty statement
+			 */
+			formatNecessaryEmptyStatement(); 
+		}
+		return false;
 	}
 
-	public void printComment() {
-		try {
-			// if we have a space between two tokens we ensure it will be dumped in the formatted string
-			int currentTokenStartPosition = this.scanner.currentPosition;
-			boolean hasComment = false;
-			boolean hasLineComment = false;
-			boolean hasWhitespace = false;
-			int count = 0;
-			while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
-				switch(this.currentToken) {
-					case TerminalTokens.TokenNameWHITESPACE :
-						char[] whiteSpaces = this.scanner.getCurrentTokenSource();
-						count = 0;
-						for (int i = 0, max = whiteSpaces.length; i < max; i++) {
-							switch(whiteSpaces[i]) {
-								case '\r' :
-									if ((i + 1) < max) {
-										if (whiteSpaces[i + 1] == '\n') {
-											i++;
-										}
-									}
-									count++;
-									break;
-								case '\n' :
-									count++;
-							}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.IfStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(IfStatement ifStatement, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNameif);
+        final int line = this.scribe.line;
+        this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_if);
+		if (this.preferences.insert_space_after_opening_paren_in_if) {
+			this.scribe.space();
+		}
+		ifStatement.condition.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_if);
+
+		final Statement thenStatement = ifStatement.thenStatement;
+		final Statement elseStatement = ifStatement.elseStatement;
+
+		boolean thenStatementIsBlock = false;
+		if (thenStatement != null) {
+			if (thenStatement instanceof Block) {
+				thenStatementIsBlock = true;
+				if (isGuardClause((Block)thenStatement) && elseStatement == null && this.preferences.keep_guardian_clause_on_one_line) {
+					/* 
+					 * Need a specific formatting for guard clauses
+					 * guard clauses are block with a single return or throw
+					 * statement
+					 */
+					 formatGuardClauseBlock((Block) thenStatement, scope);
+				} else {
+                    formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+					thenStatement.traverse(this, scope);
+					if (elseStatement != null && (this.preferences.insert_new_line_before_else_in_if_statement)) {
+						this.scribe.printNewLine();
+					}
+				}
+			} else if (elseStatement == null && this.preferences.keep_simple_if_on_one_line) {
+				Alignment compactIfAlignment = this.scribe.createAlignment(
+						"compactIf", //$NON-NLS-1$
+						this.preferences.alignment_for_compact_if,
+						Alignment.R_OUTERMOST,
+						1,
+						this.scribe.scanner.currentPosition,
+						1,
+						false);
+				this.scribe.enterAlignment(compactIfAlignment);
+				boolean ok = false;
+				do {
+					try {
+						this.scribe.alignFragment(compactIfAlignment, 0);
+						this.scribe.space();
+						thenStatement.traverse(this, scope);
+						if (thenStatement instanceof Expression) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+							this.scribe.printTrailingComment();
 						}
-						if (count == 0) {
-							hasWhitespace = true;
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						} else if (hasComment) {
-							if (count == 1) {
-								this.printNewLine(this.scanner.getCurrentTokenStartPosition());
-							} else {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							}
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						} else if (hasLineComment) {
-							this.preserveEmptyLines(count, this.scanner.getCurrentTokenStartPosition());
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						} else if (count != 0 && this.formatter.preferences.number_of_empty_lines_to_preserve != 0) {
-							addReplaceEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition(), this.getPreserveEmptyLines(count - 1));
-						} else {
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						}
-						currentTokenStartPosition = this.scanner.currentPosition;						
-						break;
-					case TerminalTokens.TokenNameCOMMENT_LINE :
-						if (count >= 1) {
-							if (count > 1) {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							} else if (count == 1) {
-								printNewLine(this.scanner.getCurrentTokenStartPosition());
-							}
-						} else if (hasWhitespace) {
-							space();
-						} 
-						hasWhitespace = false;
-						this.printCommentLine(this.scanner.getRawTokenSource());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasLineComment = true;		
-						count = 0;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_BLOCK :
-						if (count >= 1) {
-							if (count > 1) {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							} else if (count == 1) {
-								printNewLine(this.scanner.getCurrentTokenStartPosition());
-							}
-						} else if (hasWhitespace) {
-							space();
-						} 
-						hasWhitespace = false;
-						this.printBlockComment(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasLineComment = false;
-						hasComment = true;
-						count = 0;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
-						if (count >= 1) {
-							if (count > 1) {
-								preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition());
-							} else if (count == 1) {
-								printNewLine(this.scanner.getCurrentTokenStartPosition());
-							}
-						} else if (hasWhitespace) {
-							space();
-						} 
-						hasWhitespace = false;
-						this.printBlockComment(this.scanner.getRawTokenSource(), true);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasLineComment = false;
-						hasComment = true;
-						count = 0;
-						break;
-					default :
-						// step back one token
-						this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-						return;
+						ok = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
+					}
+				} while (!ok);
+				this.scribe.exitAlignment(compactIfAlignment, true);				
+			} else if (this.preferences.keep_then_statement_on_same_line) {
+				this.scribe.space();
+				thenStatement.traverse(this, scope);
+				if (thenStatement instanceof Expression) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+					this.scribe.printTrailingComment();
 				}
+				if (elseStatement != null) {
+					this.scribe.printNewLine();
+				}
+			} else {
+				this.scribe.printTrailingComment();
+				this.scribe.printNewLine();
+                /* Martijn Kruithof {} */
+                formatStatementAsBlock(scope, line, thenStatement);
+                if (elseStatement != null) {
+					this.scribe.printNewLine();
+				}
 			}
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
 		}
+		
+		if (elseStatement != null) {
+			if (thenStatementIsBlock) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameelse, this.preferences.insert_space_after_closing_brace_in_block);
+			} else {
+				this.scribe.printNextToken(TerminalTokens.TokenNameelse, true);
+			}
+			if (elseStatement instanceof Block) {
+				elseStatement.traverse(this, scope);
+			} else if (elseStatement instanceof IfStatement) {
+				if (!this.preferences.compact_else_if) {
+					this.scribe.printNewLine();
+					this.scribe.indent();
+				}
+				this.scribe.space();				
+				elseStatement.traverse(this, scope);
+				if (!this.preferences.compact_else_if) {
+					this.scribe.unIndent();
+				}
+			} else if (this.preferences.keep_else_statement_on_same_line) {
+				this.scribe.space();
+				elseStatement.traverse(this, scope);
+				if (elseStatement instanceof Expression) {
+					this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+					this.scribe.printTrailingComment();
+				}
+			} else {
+				this.scribe.printNewLine();
+                /* Martijn Kruithof {} */
+                formatStatementAsBlock(scope, line, elseStatement);
+			}
+		}
+		return false;
 	}
 	
-	private void printCommentLine(char[] s) {
-		int currentTokenStartPosition = this.scanner.getCurrentTokenStartPosition();
-		int currentTokenEndPosition = this.scanner.getCurrentTokenEndPosition() + 1;
-		if (CharOperation.indexOf(Scanner.TAG_PREFIX, this.scanner.source, true, currentTokenStartPosition) != -1) {
-			this.nlsTagCounter = 0;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ImportReference, org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope)
+	 */
+	public boolean visit(
+		ImportReference importRef,
+		CompilationUnitScope scope) {
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameimport);
+		this.scribe.space();
+		if (importRef.isStatic()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNamestatic);
+			this.scribe.space();
 		}
-		this.scanner.resetTo(currentTokenStartPosition, currentTokenEndPosition - 1);
-		int currentCharacter;
-		int start = currentTokenStartPosition;
-		int nextCharacterStart = currentTokenStartPosition;
-		printIndentationIfNecessary();
-		if (this.pendingSpace) {
-			this.addInsertEdit(currentTokenStartPosition, " "); //$NON-NLS-1$
+		if (importRef.onDemand) {
+			this.scribe.printQualifiedReference(importRef.sourceEnd);
+			this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+			this.scribe.printNextToken(TerminalTokens.TokenNameMULTIPLY);			
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		} else {
+			this.scribe.printQualifiedReference(importRef.sourceEnd);
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
 		}
-		this.needSpace = false;		
-		this.pendingSpace = false;		
-		int previousStart = currentTokenStartPosition;
+		this.scribe.printTrailingComment();
+		this.scribe.printNewLine();
+		return false;
+	}
 
-		loop: while (nextCharacterStart <= currentTokenEndPosition && (currentCharacter = this.scanner.getNextChar()) != -1) {
-			nextCharacterStart = this.scanner.currentPosition;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.Initializer, org.eclipse.jdt.internal.compiler.lookup.MethodScope)
+	 */
+	public boolean visit(Initializer initializer, MethodScope scope) {
 
-			switch(currentCharacter) {
-				case '\r' :
-					start = previousStart;
-					break loop;
-				case '\n' :
-					start = previousStart;
-					break loop;
-			}
-			previousStart = nextCharacterStart;
+		if (initializer.isStatic()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNamestatic);
 		}
-		if (start != currentTokenStartPosition) {
-			addReplaceEdit(start, currentTokenEndPosition - 1, lineSeparator);
+		initializer.block.traverse(this, scope);
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		InstanceOfExpression instanceOfExpression,
+		BlockScope scope) {
+
+		final int numberOfParens = (instanceOfExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(instanceOfExpression, numberOfParens);
 		}
-		line++; 
-		column = 1;
-		needSpace = false;
-		this.pendingSpace = false;
-		lastNumberOfNewLines = 1;
-		// realign to the proper value
-		if (this.currentAlignment != null) {
-			if (this.memberAlignment != null) {
-				// select the last alignment
-				if (this.currentAlignment.location.inputOffset > this.memberAlignment.location.inputOffset) {
-					if (this.currentAlignment.couldBreak() && this.currentAlignment.wasSplit) {
-						this.currentAlignment.performFragmentEffect();
-					}
-				} else {
-					this.indentationLevel = Math.max(this.indentationLevel, this.memberAlignment.breakIndentationLevel);
-				}
-			} else if (this.currentAlignment.couldBreak() && this.currentAlignment.wasSplit) {
-				this.currentAlignment.performFragmentEffect();
-			}
+		instanceOfExpression.expression.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameinstanceof, true);
+		this.scribe.space();
+		instanceOfExpression.type.traverse(this, scope);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(instanceOfExpression, numberOfParens);
 		}
-		this.scanner.resetTo(currentTokenEndPosition, this.scannerEndPosition - 1);
+		return false;
 	}
-	public void printEmptyLines(int linesNumber) {
-		this.printEmptyLines(linesNumber, this.scanner.getCurrentTokenEndPosition() + 1);
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.IntLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(IntLiteral intLiteral, BlockScope scope) {
+
+		final int numberOfParens = (intLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(intLiteral, numberOfParens);
+		}
+		Constant constant = intLiteral.constant;
+		if (constant != null && constant.intValue() < 0) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameMINUS);			
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameIntegerLiteral);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(intLiteral, numberOfParens);
+		}
+		return false;
 	}
 
-	private void printEmptyLines(int linesNumber, int insertPosition) {
-        final String buffer = getEmptyLines(linesNumber);
-        if (EMPTY_STRING == buffer) return;
-        
-		addInsertEdit(insertPosition, buffer);
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.LabeledStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(LabeledStatement labeledStatement, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+		this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, this.preferences.insert_space_before_colon_in_labeled_statement);
+		if (this.preferences.insert_space_after_colon_in_labeled_statement) {
+			this.scribe.space();
+		}
+		final Statement statement = labeledStatement.statement;
+		statement.traverse(this, scope);
+		if (statement instanceof Expression) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
+		}
+		return false;
 	}
 
-	private void printIndentationIfNecessary() {
-		StringBuffer buffer = new StringBuffer();
-		printIndentationIfNecessary(buffer);
-		if (buffer.length() > 0) {
-			addInsertEdit(this.scanner.getCurrentTokenStartPosition(), buffer.toString());
-			this.pendingSpace = false;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.LocalDeclaration, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
+		formatLocalDeclaration(localDeclaration, scope, this.preferences.insert_space_before_comma_in_multiple_local_declarations, this.preferences.insert_space_after_comma_in_multiple_local_declarations);
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.LongLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(LongLiteral longLiteral, BlockScope scope) {
+
+		final int numberOfParens = (longLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(longLiteral, numberOfParens);
 		}
+		Constant constant = longLiteral.constant;
+		if (constant != null && constant.longValue() < 0) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameMINUS);			
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameLongLiteral);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(longLiteral, numberOfParens);
+		}
+		return false;
 	}
+	public boolean visit(MarkerAnnotation annotation, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameAT);
+		if (this.preferences.insert_space_after_at_in_annotation) {
+			this.scribe.space();
+		}
+		this.scribe.printQualifiedReference(annotation.sourceEnd);
+		return false;
+	}
+	public boolean visit(MarkerAnnotation annotation, CompilationUnitScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameAT);
+		if (this.preferences.insert_space_after_at_in_annotation) {
+			this.scribe.space();
+		}
+		this.scribe.printQualifiedReference(annotation.sourceEnd);
+		return false;
+	}
+	public boolean visit(MemberValuePair pair, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+		this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+		if (this.preferences.insert_space_after_assignment_operator) {
+			this.scribe.space();
+		}
+		pair.value.traverse(this, scope);	
+		return false;
+	}
+	public boolean visit(MemberValuePair pair, ClassScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+		this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+		if (this.preferences.insert_space_after_assignment_operator) {
+			this.scribe.space();
+		}
+		pair.value.traverse(this, scope);	
+		return false;
+	}
+	public boolean visit(MemberValuePair pair, CompilationUnitScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+		this.scribe.printNextToken(TerminalTokens.TokenNameEQUAL, this.preferences.insert_space_before_assignment_operator);
+		if (this.preferences.insert_space_after_assignment_operator) {
+			this.scribe.space();
+		}
+		pair.value.traverse(this, scope);	
+		return false;
+	}
 
-	private void printIndentationIfNecessary(StringBuffer buffer) {
-		switch(this.tabChar) {
-			case DefaultCodeFormatterOptions.TAB :
-				boolean useTabsForLeadingIndents = this.useTabsOnlyForLeadingIndents;
-				int numberOfLeadingIndents = this.numberOfIndentations;
-				int indentationsAsTab = 0;
-				if (useTabsForLeadingIndents) {
-					while (this.column <= this.indentationLevel) {
-						if (indentationsAsTab < numberOfLeadingIndents) {
-							buffer.append('\t');
-							indentationsAsTab++;
-							this.lastNumberOfNewLines = 0;
-							int complement = this.tabLength - ((this.column - 1) % this.tabLength); // amount of space
-							this.column += complement;
-							this.needSpace = false;
-						} else {
-							buffer.append(' ');
-							this.column++;
-							this.needSpace = false;
-						}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.MessageSend, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(MessageSend messageSend, BlockScope scope) {
+
+		final int numberOfParens = (messageSend.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(messageSend, numberOfParens);
+		}
+		CascadingMethodInvocationFragmentBuilder builder = buildFragments(messageSend, scope);
+		
+		if (builder.size() >= 3 && numberOfParens == 0) {
+			formatCascadingMessageSends(builder, scope);
+		} else {
+			Alignment messageAlignment = null;
+			if (!messageSend.receiver.isImplicitThis()) {
+				messageSend.receiver.traverse(this, scope);
+				messageAlignment = this.scribe.createAlignment(
+						"messageAlignment", //$NON-NLS-1$
+						this.preferences.alignment_for_selector_in_method_invocation,
+						1,
+						this.scribe.scanner.currentPosition);
+				this.scribe.enterAlignment(messageAlignment);
+				boolean ok = false;
+				do {
+					try {
+						formatMessageSend(messageSend, scope, messageAlignment);
+						ok = true;
+					} catch (AlignmentException e) {
+						this.scribe.redoAlignment(e);
 					}
-				} else {
-					while (this.column <= this.indentationLevel) {
-						buffer.append('\t');
-						this.lastNumberOfNewLines = 0;
-						int complement = this.tabLength - ((this.column - 1) % this.tabLength); // amount of space
-						this.column += complement;
-						this.needSpace = false;
-					}
+				} while (!ok);
+				this.scribe.exitAlignment(messageAlignment, true);
+			} else {
+				formatMessageSend(messageSend, scope, null);			
+			}
+		}
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(messageSend, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(
+		MethodDeclaration methodDeclaration,
+		ClassScope scope) {
+
+		if (methodDeclaration.ignoreFurtherInvestigation) {
+			this.scribe.printComment();
+			this.scribe.scanner.resetTo(methodDeclaration.declarationSourceEnd + 1, this.scribe.scannerEndPosition);
+			this.scribe.printTrailingComment();
+			return false;
+		}
+        
+        /*
+         * Print comments to get proper line number
+         */
+        this.scribe.printComment();
+        final int line = this.scribe.line;
+        
+        this.scribe.printModifiers(methodDeclaration.annotations, this);
+		this.scribe.space();
+		
+		TypeParameter[] typeParameters = methodDeclaration.typeParameters;
+		if (typeParameters != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_parameters); 
+			if (this.preferences.insert_space_after_opening_angle_bracket_in_type_parameters) {
+				this.scribe.space();
+			}
+			int length = typeParameters.length;
+			for (int i = 0; i < length - 1; i++) {
+				typeParameters[i].traverse(this, methodDeclaration.scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_parameters);
+				if (this.preferences.insert_space_after_comma_in_type_parameters) {
+					this.scribe.space();
+				}				
+			}
+			typeParameters[length - 1].traverse(this, methodDeclaration.scope);
+			if (isClosingGenericToken()) {
+				this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_parameters); 
+			}
+			if (this.preferences.insert_space_after_closing_angle_bracket_in_type_parameters) {
+				this.scribe.space();
+			}
+		}
+		
+		/*
+		 * Print the method return type
+		 */	
+		final TypeReference returnType = methodDeclaration.returnType;
+		final MethodScope methodDeclarationScope = methodDeclaration.scope;
+		
+		if (returnType != null) {
+			returnType.traverse(this, methodDeclarationScope);
+		}
+		/*
+		 * Print the method name
+		 */
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, true); 
+
+		formatMethodArguments(
+			methodDeclaration, 
+			this.preferences.insert_space_before_opening_paren_in_method_declaration,
+			this.preferences.insert_space_between_empty_parens_in_method_declaration,
+			this.preferences.insert_space_before_closing_paren_in_method_declaration,
+			this.preferences.insert_space_after_opening_paren_in_method_declaration,
+			this.preferences.insert_space_before_comma_in_method_declaration_parameters,
+			this.preferences.insert_space_after_comma_in_method_declaration_parameters,
+			this.preferences.alignment_for_parameters_in_method_declaration);
+
+		/*
+		 * Check for extra dimensions
+		 */
+		int extraDimensions = getDimensions();
+		if (extraDimensions != 0) {
+			 for (int i = 0; i < extraDimensions; i++) {
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+			 	this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			 }
+		}
+				
+		formatThrowsClause(
+			methodDeclaration,
+			this.preferences.insert_space_before_comma_in_method_declaration_throws,
+			this.preferences.insert_space_after_comma_in_method_declaration_throws,
+			this.preferences.alignment_for_throws_clause_in_method_declaration);
+
+		if (!methodDeclaration.isNative() && !methodDeclaration.isAbstract() && ((methodDeclaration.modifiers & CompilerModifiers.AccSemicolonBody) == 0)) {
+			/*
+			 * Method body
+			 */
+			String method_declaration_brace = this.preferences.brace_position_for_method_declaration;
+            formatLeftCurlyBrace(line, method_declaration_brace);
+			formatOpeningBrace(method_declaration_brace, this.preferences.insert_space_before_opening_brace_in_method_declaration);
+			final int numberOfBlankLinesAtBeginningOfMethodBody = this.preferences.blank_lines_at_beginning_of_method_body;
+			if (numberOfBlankLinesAtBeginningOfMethodBody > 0) {
+				this.scribe.printEmptyLines(numberOfBlankLinesAtBeginningOfMethodBody);
+			}
+			final Statement[] statements = methodDeclaration.statements;
+			if (statements != null) {
+				this.scribe.printNewLine();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.indent();
 				}
-				break;
-			case DefaultCodeFormatterOptions.SPACE :
-				while (this.column <= this.indentationLevel) {
-					buffer.append(' ');
-					this.column++;
-					this.needSpace = false;
+				formatStatements(methodDeclarationScope, statements, true);
+				this.scribe.printComment();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.unIndent();
 				}
-				break;
-			case DefaultCodeFormatterOptions.MIXED :
-				useTabsForLeadingIndents = this.useTabsOnlyForLeadingIndents;
-				numberOfLeadingIndents = this.numberOfIndentations;
-				indentationsAsTab = 0;
-				if (useTabsForLeadingIndents) {
-					final int columnForLeadingIndents = numberOfLeadingIndents * this.indentationSize;
-					while (this.column <= this.indentationLevel) {
-						if (this.column <= columnForLeadingIndents) {
-							if ((this.column - 1 + this.tabLength) <= this.indentationLevel) {
-								buffer.append('\t');
-								this.column += this.tabLength;
-							} else if ((this.column - 1 + this.indentationSize) <= this.indentationLevel) {
-								// print one indentation
-								for (int i = 0, max = this.indentationSize; i < max; i++) {
-									buffer.append(' ');
-									this.column++;
-								}
-							} else {
-								buffer.append(' ');
-								this.column++;
-							}
-						} else {
-							for (int i = this.column, max = this.indentationLevel; i <= max; i++) {
-								buffer.append(' ');
-								this.column++;
-							}
-						}
-						this.needSpace = false;
-					}
-				} else {
-					while (this.column <= this.indentationLevel) {
-						if ((this.column - 1 + this.tabLength) <= this.indentationLevel) {
-							buffer.append('\t');
-							this.column += this.tabLength;
-						} else if ((this.column - 1 + this.indentationSize) <= this.indentationLevel) {
-							// print one indentation
-							for (int i = 0, max = this.indentationSize; i < max; i++) {
-								buffer.append(' ');
-								this.column++;
-							}
-						} else {
-							buffer.append(' ');
-							this.column++;
-						}
-						this.needSpace = false;
-					}
+			} else if (this.preferences.insert_new_line_in_empty_method_body) {
+				this.scribe.printNewLine();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.indent();
 				}
-				break;
+				this.scribe.printComment();
+				if (this.preferences.indent_statements_compare_to_body) {
+					this.scribe.unIndent();
+				}
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+			this.scribe.printTrailingComment();
+			if (method_declaration_brace.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+				this.scribe.unIndent();
+			}
+		} else {
+			// no method body
+			this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+			this.scribe.printTrailingComment();
 		}
+		return false;
 	}
-
-	public void printModifiers(Annotation[] annotations, ASTVisitor visitor) {
-		try {
-			int annotationsLength = annotations != null ? annotations.length : 0;
-			int annotationsIndex = 0;
-			boolean isFirstModifier = true;
-			int currentTokenStartPosition = this.scanner.currentPosition;
-			boolean hasComment = false;
-			boolean hasModifiers = false;
-			while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
-				switch(this.currentToken) {
-					case TerminalTokens.TokenNamepublic :
-					case TerminalTokens.TokenNameprotected :
-					case TerminalTokens.TokenNameprivate :
-					case TerminalTokens.TokenNamestatic :
-					case TerminalTokens.TokenNameabstract :
-					case TerminalTokens.TokenNamefinal :
-					case TerminalTokens.TokenNamenative :
-					case TerminalTokens.TokenNamesynchronized :
-					case TerminalTokens.TokenNametransient :
-					case TerminalTokens.TokenNamevolatile :
-					case TerminalTokens.TokenNamestrictfp :
-						hasModifiers = true;
-						this.print(this.scanner.getRawTokenSource(), !isFirstModifier);
-						isFirstModifier = false;
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameAT :
-						hasModifiers = true;
-						if (!isFirstModifier) {
-							this.space();
-						}
-						this.scanner.resetTo(this.scanner.getCurrentTokenStartPosition(), this.scannerEndPosition - 1);
-						if (annotationsIndex < annotationsLength) {
-							annotations[annotationsIndex++].traverse(visitor, (BlockScope) null);
-							if (this.formatter.preferences.insert_new_line_after_annotation) {
-								this.printNewLine();
-							}
-						} else {
-							return;
-						}
-						isFirstModifier = false;
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_BLOCK :
-						this.printBlockComment(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasComment = true;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
-						this.printBlockComment(this.scanner.getRawTokenSource(), true);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasComment = true;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_LINE :
-						this.printCommentLine(this.scanner.getRawTokenSource());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameWHITESPACE :
-						addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						int count = 0;
-						char[] whiteSpaces = this.scanner.getCurrentTokenSource();
-						for (int i = 0, max = whiteSpaces.length; i < max; i++) {
-							switch(whiteSpaces[i]) {
-								case '\r' :
-									if ((i + 1) < max) {
-										if (whiteSpaces[i + 1] == '\n') {
-											i++;
-										}
-									}
-									count++;
-									break;
-								case '\n' :
-									count++;
-							}
-						}
-						if (count >= 1 && hasComment) {
-							printNewLine();
-						}
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasComment = false;
-						break;
-					default:
-						if (hasModifiers) {
-							this.space();
-						}
-						// step back one token
-						this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-						return;					
+	public boolean visit(NormalAnnotation annotation, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameAT);
+		if (this.preferences.insert_space_after_at_in_annotation) {
+			this.scribe.space();
+		}
+		this.scribe.printQualifiedReference(annotation.sourceEnd);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_annotation);
+		if (this.preferences.insert_space_after_opening_paren_in_annotation) {
+			this.scribe.space();
+		}
+		MemberValuePair[] memberValuePairs = annotation.memberValuePairs;
+		if (memberValuePairs != null) {
+			int length = memberValuePairs.length;
+			for (int i = 0; i < length - 1; i++) {
+				memberValuePairs[i].traverse(this, scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_annotation);
+				if (this.preferences.insert_space_after_comma_in_annotation) {
+					this.scribe.space();
 				}
 			}
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
+			memberValuePairs[length - 1].traverse(this, scope);
 		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_annotation);
+		return false;
 	}
-	
-	public void printNewLine() {
-		if (this.nlsTagCounter > 0) {
-			return;
+	public boolean visit(NormalAnnotation annotation, CompilationUnitScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameAT);
+		if (this.preferences.insert_space_after_at_in_annotation) {
+			this.scribe.space();
 		}
-		if (lastNumberOfNewLines >= 1) {
-			column = 1; // ensure that the scribe is at the beginning of a new line
-			return;
+		this.scribe.printQualifiedReference(annotation.sourceEnd);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_annotation);
+		if (this.preferences.insert_space_after_opening_paren_in_annotation) {
+			this.scribe.space();
 		}
-		addInsertEdit(this.scanner.getCurrentTokenEndPosition() + 1, this.lineSeparator);
-		line++;
-		lastNumberOfNewLines = 1;
-		column = 1;
-		needSpace = false;
-		this.pendingSpace = false;
+		MemberValuePair[] memberValuePairs = annotation.memberValuePairs;
+		if (memberValuePairs != null) {
+			int length = memberValuePairs.length;
+			for (int i = 0; i < length - 1; i++) {
+				memberValuePairs[i].traverse(this, scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_annotation);
+				if (this.preferences.insert_space_after_comma_in_annotation) {
+					this.scribe.space();
+				}
+			}
+			memberValuePairs[length - 1].traverse(this, scope);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_annotation);
+		return false;
 	}
 
-	public void printNewLine(int insertPosition) {
-		if (this.nlsTagCounter > 0) {
-			return;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.NullLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(NullLiteral nullLiteral, BlockScope scope) {
+
+		final int numberOfParens = (nullLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(nullLiteral, numberOfParens);
 		}
-		if (lastNumberOfNewLines >= 1) {
-			column = 1; // ensure that the scribe is at the beginning of a new line
-			return;
+		this.scribe.printNextToken(TerminalTokens.TokenNamenull);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(nullLiteral, numberOfParens);
 		}
-		addInsertEdit(insertPosition, this.lineSeparator);
-		line++;
-		lastNumberOfNewLines = 1;
-		column = 1;
-		needSpace = false;
-		this.pendingSpace = false;
+		return false;
 	}
 
-	public void printNextToken(int expectedTokenType){
-		printNextToken(expectedTokenType, false);
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(OR_OR_Expression or_or_Expression, BlockScope scope) {
+		return dumpBinaryExpression(or_or_Expression, TerminalTokens.TokenNameOR_OR, scope);
 	}
-
-	public void printNextToken(int expectedTokenType, boolean considerSpaceIfAny){
-		printComment();
-		try {
-			this.currentToken = this.scanner.getNextToken();
-			char[] currentTokenSource = this.scanner.getRawTokenSource();
-			if (expectedTokenType != this.currentToken) {
-				throw new AbortFormatting("unexpected token type, expecting:"+expectedTokenType+", actual:"+this.currentToken);//$NON-NLS-1$//$NON-NLS-2$
+	public boolean visit(
+			ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference,
+			BlockScope scope) {
+		final int numberOfParens = (parameterizedQualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(parameterizedQualifiedTypeReference, numberOfParens);
+		}
+		TypeReference[][] typeArguments = parameterizedQualifiedTypeReference.typeArguments;
+		int length = typeArguments.length;
+		for (int i = 0; i < length; i++) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+			TypeReference[] typeArgument = typeArguments[i];			
+			if (typeArgument != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_parameterized_type_reference);
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_parameterized_type_reference) {
+					this.scribe.space();
+				}
+				int typeArgumentLength = typeArgument.length;
+				for (int j = 0; j < typeArgumentLength - 1; j++) {
+					typeArgument[j].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_parameterized_type_reference);
+					if (this.preferences.insert_space_after_comma_in_parameterized_type_reference) {
+						this.scribe.space();
+					}			
+				}
+				typeArgument[typeArgumentLength - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_parameterized_type_reference);
+				}
 			}
-			this.print(currentTokenSource, considerSpaceIfAny);
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
+			if (i < length - 1) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+			}
 		}
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
+			}
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			}
+		}		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(parameterizedQualifiedTypeReference, numberOfParens);
+		}
+		return false;
 	}
+	public boolean visit(
+			ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference,
+			ClassScope scope) {
+		final int numberOfParens = (parameterizedQualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(parameterizedQualifiedTypeReference, numberOfParens);
+		}
+		TypeReference[][] typeArguments = parameterizedQualifiedTypeReference.typeArguments;
+		int length = typeArguments.length;
+		for (int i = 0; i < length; i++) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+			TypeReference[] typeArgument = typeArguments[i];			
+			if (typeArgument != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_parameterized_type_reference);
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_parameterized_type_reference) {
+					this.scribe.space();
+				}
+				int typeArgumentLength = typeArgument.length;
+				for (int j = 0; j < typeArgumentLength - 1; j++) {
+					typeArgument[j].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_parameterized_type_reference);
+					if (this.preferences.insert_space_after_comma_in_parameterized_type_reference) {
+						this.scribe.space();
+					}			
+				}
+				typeArgument[typeArgumentLength - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_parameterized_type_reference);
+				}
+			}
+			if (i < length - 1) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+			}
+		}
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
+			}
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			}
+		}		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(parameterizedQualifiedTypeReference, numberOfParens);
+		}
+		return false;
+	}
+	public boolean visit(
+			ParameterizedSingleTypeReference parameterizedSingleTypeReference,
+			BlockScope scope) {
+		final int numberOfParens = (parameterizedSingleTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(parameterizedSingleTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
 
-	public void printNextToken(int[] expectedTokenTypes) {
-		printNextToken(expectedTokenTypes, false);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_parameterized_type_reference);
+		if (this.preferences.insert_space_after_opening_angle_bracket_in_parameterized_type_reference) {
+			this.scribe.space();
+		}
+		TypeReference[] typeArguments = parameterizedSingleTypeReference.typeArguments;
+		int typeArgumentsLength = typeArguments.length;
+		for (int i = 0; i < typeArgumentsLength - 1; i++) {
+			typeArguments[i].traverse(this, scope);
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_parameterized_type_reference);
+			if (this.preferences.insert_space_after_comma_in_parameterized_type_reference) {
+				this.scribe.space();
+			}			
+		}
+		typeArguments[typeArgumentsLength - 1].traverse(this, scope);
+		if (isClosingGenericToken()) {
+			this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_parameterized_type_reference);
+		}
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
+			}
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			}
+		}		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(parameterizedSingleTypeReference, numberOfParens);
+		}
+		return false;
 	}
+	public boolean visit(
+			ParameterizedSingleTypeReference parameterizedSingleTypeReference,
+			ClassScope scope) {
+		final int numberOfParens = (parameterizedSingleTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(parameterizedSingleTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
 
-	public void printNextToken(int[] expectedTokenTypes, boolean considerSpaceIfAny){
-		printComment();
-		try {
-			this.currentToken = this.scanner.getNextToken();
-			char[] currentTokenSource = this.scanner.getRawTokenSource();
-			if (Arrays.binarySearch(expectedTokenTypes, this.currentToken) < 0) {
-				StringBuffer expectations = new StringBuffer(5);
-				for (int i = 0; i < expectedTokenTypes.length; i++){
-					if (i > 0) {
-						expectations.append(',');
-					}
-					expectations.append(expectedTokenTypes[i]);
-				}				
-				throw new AbortFormatting("unexpected token type, expecting:["+expectations.toString()+"], actual:"+this.currentToken);//$NON-NLS-1$//$NON-NLS-2$
+		this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_parameterized_type_reference);
+		if (this.preferences.insert_space_after_opening_angle_bracket_in_parameterized_type_reference) {
+			this.scribe.space();
+		}
+		TypeReference[] typeArguments = parameterizedSingleTypeReference.typeArguments;
+		int typeArgumentsLength = typeArguments.length;
+		for (int i = 0; i < typeArgumentsLength - 1; i++) {
+			typeArguments[i].traverse(this, scope);
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_parameterized_type_reference);
+			if (this.preferences.insert_space_after_comma_in_parameterized_type_reference) {
+				this.scribe.space();
+			}			
+		}
+		typeArguments[typeArgumentsLength - 1].traverse(this, scope);
+		if (isClosingGenericToken()) {
+			this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_parameterized_type_reference);
+		}
+		int dimensions = getDimensions();
+		if (dimensions != 0) {
+			if (this.preferences.insert_space_before_opening_bracket_in_array_type_reference) {
+				this.scribe.space();
 			}
-			this.print(currentTokenSource, considerSpaceIfAny);
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
+			for (int i = 0; i < dimensions; i++) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLBRACKET);
+				if (this.preferences.insert_space_between_brackets_in_array_type_reference) {
+					this.scribe.space();
+				}
+				this.scribe.printNextToken(TerminalTokens.TokenNameRBRACKET);
+			}
+		}		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(parameterizedSingleTypeReference, numberOfParens);
 		}
+		return false;
 	}
+	
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.PostfixExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		PostfixExpression postfixExpression,
+		BlockScope scope) {
 
-	public void printArrayQualifiedReference(int numberOfTokens, int sourceEnd) {
-		int currentTokenStartPosition = this.scanner.currentPosition;
-		int numberOfIdentifiers = 0;
-		try {
+		final int numberOfParens = (postfixExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(postfixExpression, numberOfParens);
+		}
+		postfixExpression.lhs.traverse(this, scope);
+		int operator = postfixExpression.operator == OperatorIds.PLUS 
+			? TerminalTokens.TokenNamePLUS_PLUS : TerminalTokens.TokenNameMINUS_MINUS;
+		this.scribe.printNextToken(operator, this.preferences.insert_space_before_postfix_operator);
+		if (this.preferences.insert_space_after_postfix_operator) {
+			this.scribe.space();
+		}
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(postfixExpression, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.PrefixExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(PrefixExpression prefixExpression, BlockScope scope) {
+
+		final int numberOfParens = (prefixExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(prefixExpression, numberOfParens);
+		}
+		int operator = prefixExpression.operator == OperatorIds.PLUS 
+			? TerminalTokens.TokenNamePLUS_PLUS : TerminalTokens.TokenNameMINUS_MINUS;
+		this.scribe.printNextToken(operator, this.preferences.insert_space_before_prefix_operator);
+		if (this.preferences.insert_space_after_prefix_operator) {
+			this.scribe.space();
+		}
+		prefixExpression.lhs.traverse(this, scope);
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(prefixExpression, numberOfParens);
+		}
+		return false;
+	}
+	
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		QualifiedAllocationExpression qualifiedAllocationExpression,
+		BlockScope scope) {
+			
+		final int numberOfParens = (qualifiedAllocationExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(qualifiedAllocationExpression, numberOfParens);
+		}
+		final Expression enclosingInstance = qualifiedAllocationExpression.enclosingInstance;
+		if (enclosingInstance != null) {
+			enclosingInstance.traverse(this, scope);
+			this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+		}
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNamenew);
+		// used for the new line on wrap style of formatting
+		TypeReference[] typeArguments = qualifiedAllocationExpression.typeArguments;
+		if (typeArguments != null) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameLESS, this.preferences.insert_space_before_opening_angle_bracket_in_type_arguments); 
+				if (this.preferences.insert_space_after_opening_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+				int length = typeArguments.length;
+				for (int i = 0; i < length - 1; i++) {
+					typeArguments[i].traverse(this, scope);
+					this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_type_arguments);
+					if (this.preferences.insert_space_after_comma_in_type_arguments) {
+						this.scribe.space();
+					}				
+				}
+				typeArguments[length - 1].traverse(this, scope);
+				if (isClosingGenericToken()) {
+					this.scribe.printNextToken(CLOSING_GENERICS_EXPECTEDTOKENS, this.preferences.insert_space_before_closing_angle_bracket_in_type_arguments); 
+				}
+				if (this.preferences.insert_space_after_closing_angle_bracket_in_type_arguments) {
+					this.scribe.space();
+				}
+		} else {
+			this.scribe.space();
+		}
+
+		final int line = this.scribe.line;
+		qualifiedAllocationExpression.type.traverse(this, scope);
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_method_invocation);
+
+		final Expression[] arguments = qualifiedAllocationExpression.arguments;
+		if (arguments != null) {
+			if (this.preferences.insert_space_after_opening_paren_in_method_invocation) {
+				this.scribe.space();
+			}
+			int argumentLength = arguments.length;
+			Alignment argumentsAlignment =this.scribe.createAlignment(
+					"allocation",//$NON-NLS-1$
+					this.preferences.alignment_for_arguments_in_qualified_allocation_expression,
+					argumentLength,
+					this.scribe.scanner.currentPosition);
+			this.scribe.enterAlignment(argumentsAlignment);
+			boolean ok = false;
 			do {
-				this.printComment();
-				switch(this.currentToken = this.scanner.getNextToken()) {
-					case TerminalTokens.TokenNameEOF :
-						return;
-					case TerminalTokens.TokenNameWHITESPACE :
-						addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_BLOCK :
-					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
-						this.printBlockComment(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_LINE :
-						this.printCommentLine(this.scanner.getRawTokenSource());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameIdentifier :
-						this.print(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						if (++ numberOfIdentifiers == numberOfTokens) {
-							this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-							return;
+				try {
+					for (int i = 0; i < argumentLength; i++) {
+						if (i > 0) {
+							this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, this.preferences.insert_space_before_comma_in_allocation_expression);
+							this.scribe.printTrailingComment();
 						}
-						break;						
-					case TerminalTokens.TokenNameDOT :
-						this.print(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					default:
-						this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-						return;
+						this.scribe.alignFragment(argumentsAlignment, i);
+						if (i > 0 && this.preferences.insert_space_after_comma_in_allocation_expression) {
+							this.scribe.space();
+						}
+						arguments[i].traverse(this, scope);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					this.scribe.redoAlignment(e);
 				}
-			} while (this.scanner.currentPosition <= sourceEnd);
-		} catch(InvalidInputException e) {
-			throw new AbortFormatting(e);
+			} while (!ok);
+			this.scribe.exitAlignment(argumentsAlignment, true);
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_method_invocation); 
+		} else {
+			this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_between_empty_parens_in_method_invocation);
 		}
+		final TypeDeclaration anonymousType = qualifiedAllocationExpression.anonymousType;
+		if (anonymousType != null) {
+			formatLeftCurlyBrace(line, this.preferences.brace_position_for_anonymous_type_declaration);
+			formatAnonymousTypeDeclaration(anonymousType);
+		}
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(qualifiedAllocationExpression, numberOfParens);
+		}
+		return false;
 	}
 
-	public void printQualifiedReference(int sourceEnd) {
-		int currentTokenStartPosition = this.scanner.currentPosition;
-		try {
-			do {
-				this.printComment();
-				switch(this.currentToken = this.scanner.getNextToken()) {
-					case TerminalTokens.TokenNameEOF :
-						return;
-					case TerminalTokens.TokenNameWHITESPACE :
-						addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_BLOCK :
-					case TerminalTokens.TokenNameCOMMENT_JAVADOC :
-						this.printBlockComment(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_LINE :
-						this.printCommentLine(this.scanner.getRawTokenSource());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					case TerminalTokens.TokenNameIdentifier :
-					case TerminalTokens.TokenNameDOT :
-						this.print(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						break;
-					default:
-						this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-						return;
-				}
-			} while (this.scanner.currentPosition <= sourceEnd);
-		} catch(InvalidInputException e) {
-			throw new AbortFormatting(e);
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		QualifiedNameReference qualifiedNameReference,
+		BlockScope scope) {
+
+		final int numberOfParens = (qualifiedNameReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(qualifiedNameReference, numberOfParens);
 		}
+		this.scribe.printQualifiedReference(qualifiedNameReference.sourceEnd);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(qualifiedNameReference, numberOfParens);
+		}
+		return false;
 	}
 
-	private void printRule(StringBuffer stringBuffer) {
-		for (int i = 0; i < this.pageWidth; i++){
-			if ((i % this.tabLength) == 0) { 
-				stringBuffer.append('+');
-			} else {
-				stringBuffer.append('-');
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		QualifiedSuperReference qualifiedSuperReference,
+		BlockScope scope) {
+
+		final int numberOfParens = (qualifiedSuperReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(qualifiedSuperReference, numberOfParens);
+		}
+		qualifiedSuperReference.qualification.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+		this.scribe.printNextToken(TerminalTokens.TokenNamesuper);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(qualifiedSuperReference, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		QualifiedThisReference qualifiedThisReference,
+		BlockScope scope) {
+
+		final int numberOfParens = (qualifiedThisReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(qualifiedThisReference, numberOfParens);
+		}
+		qualifiedThisReference.qualification.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameDOT);
+		this.scribe.printNextToken(TerminalTokens.TokenNamethis);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(qualifiedThisReference, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		QualifiedTypeReference qualifiedTypeReference,
+		BlockScope scope) {
+
+		final int numberOfParens = (qualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(qualifiedTypeReference, numberOfParens);
+		}
+		this.scribe.printQualifiedReference(qualifiedTypeReference.sourceEnd);
+		
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(qualifiedTypeReference, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(
+		QualifiedTypeReference qualifiedTypeReference,
+		ClassScope scope) {
+
+			final int numberOfParens = (qualifiedTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(qualifiedTypeReference, numberOfParens);
 			}
+			this.scribe.printQualifiedReference(qualifiedTypeReference.sourceEnd);
+			
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(qualifiedTypeReference, numberOfParens);
+			}
+			return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ReturnStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ReturnStatement returnStatement, BlockScope scope) {
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNamereturn);
+		final Expression expression = returnStatement.expression;
+		if (expression != null) {
+			this.scribe.space();
+			expression.traverse(this, scope);
 		}
-		stringBuffer.append(this.lineSeparator);
+		/*
+		 * Print the semi-colon
+		 */	
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
+	}
+	public boolean visit(SingleMemberAnnotation annotation, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameAT);
+		if (this.preferences.insert_space_after_at_in_annotation) {
+			this.scribe.space();
+		}
+		this.scribe.printQualifiedReference(annotation.sourceEnd);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_annotation);
+		if (this.preferences.insert_space_after_opening_paren_in_annotation) {
+			this.scribe.space();
+		}
+		annotation.memberValue.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_annotation);
+		return false;
+	}
+	public boolean visit(SingleMemberAnnotation annotation,
+			CompilationUnitScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameAT);
+		if (this.preferences.insert_space_after_at_in_annotation) {
+			this.scribe.space();
+		}
+		this.scribe.printQualifiedReference(annotation.sourceEnd);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_annotation);
+		if (this.preferences.insert_space_after_opening_paren_in_annotation) {
+			this.scribe.space();
+		}
+		annotation.memberValue.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_annotation);
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.SingleNameReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(SingleNameReference singleNameReference, BlockScope scope) {
+
+		final int numberOfParens = (singleNameReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(singleNameReference, numberOfParens);
+		}
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
 		
-		for (int i = 0; i < (pageWidth / tabLength); i++) {
-			stringBuffer.append(i);
-			stringBuffer.append('\t');
-		}			
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(singleNameReference, numberOfParens);
+		}
+		return false;
 	}
 
-	public void printTrailingComment() {
-		try {
-			// if we have a space between two tokens we ensure it will be dumped in the formatted string
-			int currentTokenStartPosition = this.scanner.currentPosition;
-			boolean hasWhitespaces = false;
-			boolean hasComment = false;
-			boolean hasLineComment = false;
-			while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
-				switch(this.currentToken) {
-					case TerminalTokens.TokenNameWHITESPACE :
-						int count = 0;
-						char[] whiteSpaces = this.scanner.getCurrentTokenSource();
-						for (int i = 0, max = whiteSpaces.length; i < max; i++) {
-							switch(whiteSpaces[i]) {
-								case '\r' :
-									if ((i + 1) < max) {
-										if (whiteSpaces[i + 1] == '\n') {
-											i++;
-										}
-									}
-									count++;
-									break;
-								case '\n' :
-									count++;
-							}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		SingleTypeReference singleTypeReference,
+		BlockScope scope) {
+
+		final int numberOfParens = (singleTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(singleTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(singleTypeReference, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(
+		SingleTypeReference singleTypeReference,
+		ClassScope scope) {
+
+		final int numberOfParens = (singleTypeReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(singleTypeReference, numberOfParens);
+		}
+		this.scribe.printNextToken(SINGLETYPEREFERENCE_EXPECTEDTOKENS);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(singleTypeReference, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.StringLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(StringLiteral stringLiteral, BlockScope scope) {
+		final int numberOfParens = (stringLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(stringLiteral, numberOfParens);
+		}
+		this.scribe.checkNLSTag(stringLiteral.sourceStart);
+		this.scribe.printNextToken(TerminalTokens.TokenNameStringLiteral);
+		this.scribe.printTrailingComment();
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(stringLiteral, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.NullLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(StringLiteralConcatenation stringLiteral, BlockScope scope) {
+		final int numberOfParens = (stringLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(stringLiteral, numberOfParens);
+		}
+
+		this.scribe.printComment();
+		ASTNode[] fragments = stringLiteral.literals;
+		int fragmentsSize = stringLiteral.counter;
+		Alignment binaryExpressionAlignment = this.scribe.createAlignment("binaryExpressionAlignment", this.preferences.alignment_for_binary_expression, Alignment.R_OUTERMOST, fragmentsSize, this.scribe.scanner.currentPosition); //$NON-NLS-1$
+		this.scribe.enterAlignment(binaryExpressionAlignment);
+		boolean ok = false;
+		do {
+			try {
+				for (int i = 0; i < fragmentsSize - 1; i++) {
+					ASTNode fragment = fragments[i];
+					fragment.traverse(this, scope);
+					this.scribe.printTrailingComment();
+					if (this.scribe.lastNumberOfNewLines == 1) {
+						// a new line has been inserted by printTrailingComment()
+						this.scribe.indentationLevel = binaryExpressionAlignment.breakIndentationLevel;
+					}
+					this.scribe.alignFragment(binaryExpressionAlignment, i);
+					this.scribe.printNextToken(TerminalTokens.TokenNamePLUS, this.preferences.insert_space_before_binary_operator);
+					if (this.preferences.insert_space_after_binary_operator) {
+						this.scribe.space();
+					}
+				}
+				fragments[fragmentsSize - 1].traverse(this, scope);
+				this.scribe.printTrailingComment();
+				ok = true;
+			} catch(AlignmentException e){
+				this.scribe.redoAlignment(e);
+			}
+		} while (!ok);		
+		this.scribe.exitAlignment(binaryExpressionAlignment, true);
+	
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(stringLiteral, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.SuperReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(SuperReference superReference, BlockScope scope) {
+
+		final int numberOfParens = (superReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(superReference, numberOfParens);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNamesuper);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(superReference, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.SwitchStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(SwitchStatement switchStatement, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameswitch);
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_switch);
+		
+		if (this.preferences.insert_space_after_opening_paren_in_switch) {
+			this.scribe.space();
+		}
+		
+		switchStatement.expression.traverse(this, scope);
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_switch);
+		/*
+		 * Type body
+		 */
+		String switch_brace = this.preferences.brace_position_for_switch;
+		formatOpeningBrace(switch_brace, this.preferences.insert_space_before_opening_brace_in_switch);
+		this.scribe.printNewLine();
+
+		if (this.preferences.indent_switchstatements_compare_to_switch) {
+			this.scribe.indent();
+		}
+		final Statement[] statements = switchStatement.statements;
+		boolean wasACase = false;
+		boolean wasAStatement = false;
+		if (statements != null) {
+			int statementsLength = statements.length;
+			for (int i = 0; i < statementsLength; i++) {
+				final Statement statement = statements[i];
+				if (statement instanceof CaseStatement) {
+					if (wasACase) {
+						this.scribe.printNewLine();
+					}
+					if ((wasACase && this.preferences.indent_switchstatements_compare_to_cases) 
+						|| (wasAStatement && this.preferences.indent_switchstatements_compare_to_cases)) {
+						this.scribe.unIndent();
+					}
+					statement.traverse(this, scope);
+					this.scribe.printTrailingComment();
+					wasACase = true;
+					wasAStatement = false;
+					if (this.preferences.indent_switchstatements_compare_to_cases) {
+						this.scribe.indent();
+					}
+				} else if (statement instanceof BreakStatement) {
+					if (this.preferences.indent_breaks_compare_to_cases) {
+						if (wasAStatement && !this.preferences.indent_switchstatements_compare_to_cases) {
+							this.scribe.indent();
 						}
-						if (hasLineComment) {
-							if (count >= 1) {
-								currentTokenStartPosition = this.scanner.getCurrentTokenStartPosition();
-								this.preserveEmptyLines(count, currentTokenStartPosition);
-								addDeleteEdit(currentTokenStartPosition, this.scanner.getCurrentTokenEndPosition());
-								this.scanner.resetTo(this.scanner.currentPosition, this.scannerEndPosition - 1);
-								return;
-							} else {
-								this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-								return;
+					} else {
+						if (wasAStatement) {
+							if (this.preferences.indent_switchstatements_compare_to_cases) {
+								this.scribe.unIndent();
 							}
-						} else if (count >= 1) {
-							if (hasComment) {
-								this.printNewLine(this.scanner.getCurrentTokenStartPosition());
-							}
-							this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-							return;
-						} else {
-							hasWhitespaces = true;
-							currentTokenStartPosition = this.scanner.currentPosition;						
-							addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
 						}
-						break;
-					case TerminalTokens.TokenNameCOMMENT_LINE :
-						if (hasWhitespaces) {
-							space();
+						if (wasACase && this.preferences.indent_switchstatements_compare_to_cases) {
+							this.scribe.unIndent();
 						}
-						this.printCommentLine(this.scanner.getRawTokenSource());
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasLineComment = true;
-						break;
-					case TerminalTokens.TokenNameCOMMENT_BLOCK :
-						if (hasWhitespaces) {
-							space();
+					}
+					if (wasACase) {
+						this.scribe.printNewLine();
+					}
+					statement.traverse(this, scope);
+					if (this.preferences.indent_breaks_compare_to_cases) {
+						this.scribe.unIndent();
+					}
+					wasACase = false;
+					wasAStatement = false;
+				} else if (statement instanceof Block) {
+					String bracePosition;
+					if (wasACase) {
+						if (this.preferences.indent_switchstatements_compare_to_cases) {
+							this.scribe.unIndent();
 						}
-						this.printBlockComment(this.scanner.getRawTokenSource(), false);
-						currentTokenStartPosition = this.scanner.currentPosition;
-						hasComment = true;
-						break;
-					default :
-						// step back one token
-						this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1);
-						return;
+						bracePosition =	this.preferences.brace_position_for_block_in_case;
+						formatBlock((Block) statement, scope, bracePosition, this.preferences.insert_space_after_colon_in_case);
+						if (this.preferences.indent_switchstatements_compare_to_cases) {
+							this.scribe.indent();
+						}
+					} else {
+						bracePosition =	this.preferences.brace_position_for_block;
+						formatBlock((Block) statement, scope, bracePosition, this.preferences.insert_space_before_opening_brace_in_block);
+					}
+					wasAStatement = true;
+					wasACase = false;
+				} else {
+					this.scribe.printNewLine();
+					statement.traverse(this, scope);
+					wasAStatement = true;
+					wasACase = false;
 				}
+				if (statement instanceof Expression) {
+					/*
+					 * Print the semi-colon
+					 */	
+					this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+					this.scribe.printTrailingComment();
+					this.scribe.printNewLine();
+				} else if (statement instanceof LocalDeclaration) {
+					LocalDeclaration currentLocal = (LocalDeclaration) statement;
+					if (i < (statementsLength - 1)) {
+						/* 
+						 * We need to check that the next statement is a local declaration
+						 */
+						if (statements[i + 1] instanceof LocalDeclaration) {
+							LocalDeclaration nextLocal = (LocalDeclaration) statements[i + 1];
+							if (currentLocal.declarationSourceStart != nextLocal.declarationSourceStart) {
+								/*
+								 * Print the semi-colon
+								 */	
+								this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+								this.scribe.printTrailingComment();
+								this.scribe.printNewLine();
+							}
+						} else {
+							/*
+							 * Print the semi-colon
+							 */	
+							this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+							this.scribe.printTrailingComment();
+							this.scribe.printNewLine();
+						}
+					} else {
+						/*
+						 * Print the semi-colon
+						 */	
+						this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+						this.scribe.printTrailingComment();
+						this.scribe.printNewLine();
+					}
+				} else if (!wasACase) {
+					this.scribe.printNewLine();
+				}
 			}
-		} catch (InvalidInputException e) {
-			throw new AbortFormatting(e);
+		}		
+		
+		if ((wasACase || wasAStatement) && this.preferences.indent_switchstatements_compare_to_cases) {
+			this.scribe.unIndent();
 		}
+		if (this.preferences.indent_switchstatements_compare_to_switch) {
+			this.scribe.unIndent();
+		}
+		this.scribe.printNewLine();
+		this.scribe.printNextToken(TerminalTokens.TokenNameRBRACE);
+		this.scribe.printTrailingComment();
+		if (switch_brace.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) {
+			this.scribe.unIndent();
+		}		
+		return false;
 	}
 
-	void redoAlignment(AlignmentException e){
-		if (e.relativeDepth > 0) { // if exception targets a distinct context
-			e.relativeDepth--; // record fact that current context got traversed
-			this.currentAlignment = this.currentAlignment.enclosing; // pop currentLocation
-			throw e; // rethrow
-		} 
-		// reset scribe/scanner to restart at this given location
-		this.resetAt(this.currentAlignment.location);
-		this.scanner.resetTo(this.currentAlignment.location.inputOffset, this.scanner.eofPosition);
-		// clean alignment chunkKind so it will think it is a new chunk again
-		this.currentAlignment.chunkKind = 0;
-	}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		SynchronizedStatement synchronizedStatement,
+		BlockScope scope) {
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNamesynchronized);
 
-	void redoMemberAlignment(AlignmentException e){
-		// reset scribe/scanner to restart at this given location
-		this.resetAt(this.memberAlignment.location);
-		this.scanner.resetTo(this.memberAlignment.location.inputOffset, this.scanner.eofPosition);
-		// clean alignment chunkKind so it will think it is a new chunk again
-		this.memberAlignment.chunkKind = 0;
-	}
+		final int line = this.scribe.line;
 
-	public void reset() {
-		this.checkLineWrapping = true;
-		this.line = 0;
-		this.column = 1;
-		this.editsIndex = 0;
-		this.nlsTagCounter = 0;
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_synchronized);
+		
+		if (this.preferences.insert_space_after_opening_paren_in_synchronized) {
+			this.scribe.space();
+		}
+		synchronizedStatement.expression.traverse(this, scope);
+	
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_synchronized);
+		
+		formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+		synchronizedStatement.block.traverse(this, scope);
+		return false;
 	}
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ThisReference, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ThisReference thisReference, BlockScope scope) {
 		
-	private void resetAt(Location location) {
-		this.line = location.outputLine;
-		this.column = location.outputColumn;
-		this.indentationLevel = location.outputIndentationLevel;
-		this.numberOfIndentations = location.numberOfIndentations;
-		this.lastNumberOfNewLines = location.lastNumberOfNewLines;
-		this.needSpace = location.needSpace;
-		this.pendingSpace = location.pendingSpace;
-		this.editsIndex = location.editsIndex;
-		this.nlsTagCounter = location.nlsTagCounter;
-		if (this.editsIndex > 0) {
-			this.edits[this.editsIndex - 1] = location.textEdit;
+		if (!thisReference.isImplicitThis()) {
+			final int numberOfParens = (thisReference.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+			if (numberOfParens > 0) {
+				manageOpeningParenthesizedExpression(thisReference, numberOfParens);
+			}
+			this.scribe.printNextToken(TerminalTokens.TokenNamethis);
+			
+			if (numberOfParens > 0) {
+				manageClosingParenthesizedExpression(thisReference, numberOfParens);
+			}
 		}
-		this.formatter.lastLocalDeclarationSourceStart = location.lastLocalDeclarationSourceStart;
+		return false;
 	}
 
-	private void resize() {
-		System.arraycopy(this.edits, 0, (this.edits = new OptimizedReplaceEdit[this.editsIndex * 2]), 0, this.editsIndex);
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.ThrowStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(ThrowStatement throwStatement, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNamethrow);
+		this.scribe.space();
+		throwStatement.exception.traverse(this, scope);
+		/*
+		 * Print the semi-colon
+		 */	
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, this.preferences.insert_space_before_semicolon);
+		this.scribe.printTrailingComment();
+		return false;
 	}
 
-	public void space() {
-		if (!this.needSpace) return;
-		this.lastNumberOfNewLines = 0;
-		this.pendingSpace = true;
-		this.column++;
-		this.needSpace = false;		
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.TrueLiteral, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(TrueLiteral trueLiteral, BlockScope scope) {
+
+		final int numberOfParens = (trueLiteral.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(trueLiteral, numberOfParens);
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNametrue);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(trueLiteral, numberOfParens);
+		}
+		return false;
 	}
 
-	public String toString() {
-		StringBuffer stringBuffer = new StringBuffer();
-		stringBuffer
-			.append("(page width = " + this.pageWidth + ") - (tabChar = ");//$NON-NLS-1$//$NON-NLS-2$
-		switch(this.tabChar) {
-			case DefaultCodeFormatterOptions.TAB :
-				 stringBuffer.append("TAB");//$NON-NLS-1$
-				 break;
-			case DefaultCodeFormatterOptions.SPACE :
-				 stringBuffer.append("SPACE");//$NON-NLS-1$
-				 break;
-			default :
-				 stringBuffer.append("MIXED");//$NON-NLS-1$
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.TryStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(TryStatement tryStatement, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNametry);
+		tryStatement.tryBlock.traverse(this, scope);
+		if (tryStatement.catchArguments != null) {
+			for (int i = 0, max = tryStatement.catchBlocks.length; i < max; i++) {
+				if (this.preferences.insert_new_line_before_catch_in_try_statement) {
+					this.scribe.printNewLine();
+				}	
+				this.scribe.printNextToken(TerminalTokens.TokenNamecatch, this.preferences.insert_space_after_closing_brace_in_block);
+				final int line = this.scribe.line;
+				this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_catch);
+				
+				if (this.preferences.insert_space_after_opening_paren_in_catch) {
+					this.scribe.space();
+				}
+				
+				tryStatement.catchArguments[i].traverse(this, scope);
+			
+				this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_catch);
+				
+				formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+				tryStatement.catchBlocks[i].traverse(this, scope);
+			}
 		}
-		stringBuffer
-			.append(") - (tabSize = " + this.tabLength + ")")//$NON-NLS-1$//$NON-NLS-2$
-			.append(this.lineSeparator)
-			.append("(line = " + this.line + ") - (column = " + this.column + ") - (identationLevel = " + this.indentationLevel + ")")	//$NON-NLS-1$	//$NON-NLS-2$	//$NON-NLS-3$	//$NON-NLS-4$
-			.append(this.lineSeparator)
-			.append("(needSpace = " + this.needSpace + ") - (lastNumberOfNewLines = " + this.lastNumberOfNewLines + ") - (checkLineWrapping = " + this.checkLineWrapping + ")")	//$NON-NLS-1$	//$NON-NLS-2$	//$NON-NLS-3$	//$NON-NLS-4$
-			.append(this.lineSeparator)
-			.append("==================================================================================")	//$NON-NLS-1$
-			.append(this.lineSeparator);
-		printRule(stringBuffer);
-		return stringBuffer.toString();
+		if (tryStatement.finallyBlock != null) {
+			if (this.preferences.insert_new_line_before_finally_in_try_statement) {
+				this.scribe.printNewLine();
+			}	
+			this.scribe.printNextToken(TerminalTokens.TokenNamefinally, this.preferences.insert_space_after_closing_brace_in_block);
+			tryStatement.finallyBlock.traverse(this, scope);
+		}
+		return false;
 	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(
+		TypeDeclaration localTypeDeclaration,
+		BlockScope scope) {
+
+			format(localTypeDeclaration);
+			return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration, org.eclipse.jdt.internal.compiler.lookup.ClassScope)
+	 */
+	public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
+		format(memberTypeDeclaration);	
+		return false;
+	}
 	
-	public void unIndent() {
-		this.indentationLevel -= this.indentationSize;
-		this.numberOfIndentations--;
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration, org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope)
+	 */
+	public boolean visit(
+		TypeDeclaration typeDeclaration,
+		CompilationUnitScope scope) {
+
+		format(typeDeclaration);
+		return false;
 	}
-}
\ No newline at end of file
+	public boolean visit(TypeParameter typeParameter, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+		if (typeParameter.type != null) {
+			this.scribe.space();
+			this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);
+			this.scribe.space();
+			typeParameter.type.traverse(this, scope);
+		}
+		final TypeReference[] bounds = typeParameter.bounds;
+		if (bounds != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameAND, this.preferences.insert_space_before_and_in_type_parameter);
+			if (this.preferences.insert_space_after_and_in_type_parameter) {
+				this.scribe.space();
+			}
+			int boundsLength = bounds.length;
+			for (int i = 0; i < boundsLength - 1; i++) {
+				bounds[i].traverse(this, scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameAND, this.preferences.insert_space_before_and_in_type_parameter);
+				if (this.preferences.insert_space_after_and_in_type_parameter) {
+					this.scribe.space();
+				}
+			}
+			bounds[boundsLength - 1].traverse(this, scope);
+		}
+		return false;
+	}
+	public boolean visit(TypeParameter typeParameter, ClassScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier);
+		if (typeParameter.type != null) {
+			this.scribe.space();
+			this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);
+			this.scribe.space();
+			typeParameter.type.traverse(this, scope);
+		}
+		final TypeReference[] bounds = typeParameter.bounds;
+		if (bounds != null) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameAND, this.preferences.insert_space_before_and_in_type_parameter);
+			if (this.preferences.insert_space_after_and_in_type_parameter) {
+				this.scribe.space();
+			}
+			int boundsLength = bounds.length;
+			for (int i = 0; i < boundsLength - 1; i++) {
+				bounds[i].traverse(this, scope);
+				this.scribe.printNextToken(TerminalTokens.TokenNameAND, this.preferences.insert_space_before_and_in_type_parameter);
+				if (this.preferences.insert_space_after_and_in_type_parameter) {
+					this.scribe.space();
+				}
+			}
+			bounds[boundsLength - 1].traverse(this, scope);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.UnaryExpression, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(UnaryExpression unaryExpression, BlockScope scope) {
+
+		final int numberOfParens = (unaryExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT;
+		if (numberOfParens > 0) {
+			manageOpeningParenthesizedExpression(unaryExpression, numberOfParens);
+		}
+
+		/*
+		 * Print the operator
+		 */
+		int operator;
+		switch((unaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
+			case OperatorIds.PLUS:
+				operator = TerminalTokens.TokenNamePLUS;
+				break;
+			case OperatorIds.MINUS:
+				operator = TerminalTokens.TokenNameMINUS;
+				break;
+			case OperatorIds.TWIDDLE:
+				operator = TerminalTokens.TokenNameTWIDDLE;
+				break;
+			default:
+				operator = TerminalTokens.TokenNameNOT;
+		}
+
+		this.scribe.printNextToken(operator, this.preferences.insert_space_before_unary_operator);
+		if (this.preferences.insert_space_after_unary_operator) {
+			this.scribe.space();
+		}
+		unaryExpression.expression.traverse(this, scope);
+
+		if (numberOfParens > 0) {
+			manageClosingParenthesizedExpression(unaryExpression, numberOfParens);
+		}
+		return false;
+	}
+
+	/**
+	 * @see org.eclipse.jdt.internal.compiler.ASTVisitor#visit(org.eclipse.jdt.internal.compiler.ast.WhileStatement, org.eclipse.jdt.internal.compiler.lookup.BlockScope)
+	 */
+	public boolean visit(WhileStatement whileStatement, BlockScope scope) {
+
+		this.scribe.printNextToken(TerminalTokens.TokenNamewhile);
+		final int line = this.scribe.line;
+		this.scribe.printNextToken(TerminalTokens.TokenNameLPAREN, this.preferences.insert_space_before_opening_paren_in_while);
+		
+		if (this.preferences.insert_space_after_opening_paren_in_while) {
+			this.scribe.space();
+		}
+		whileStatement.condition.traverse(this, scope);
+		
+		this.scribe.printNextToken(TerminalTokens.TokenNameRPAREN, this.preferences.insert_space_before_closing_paren_in_while);
+		
+		final Statement action = whileStatement.action;
+		if (action != null) {
+			if (action instanceof Block) {
+                formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+				action.traverse(this, scope);
+			} else if (action instanceof EmptyStatement) {
+				/*
+				 * This is an empty statement
+				 */
+				formatNecessaryEmptyStatement();
+			} else {
+				this.scribe.printNewLine();
+                /* Martijn Kruithof {} */
+                formatStatementAsBlock(scope, line, action);
+			}
+		} else {
+			/*
+			 * This is an empty statement
+			 */
+			formatNecessaryEmptyStatement();
+		}
+		return false;
+	}
+	public boolean visit(Wildcard wildcard, BlockScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameQUESTION, this.preferences.insert_space_before_question_in_wilcard);
+		switch(wildcard.kind) {
+			case Wildcard.SUPER :
+				this.scribe.printNextToken(TerminalTokens.TokenNamesuper, true);				
+				this.scribe.space();
+				wildcard.bound.traverse(this, scope);
+				break;
+			case Wildcard.EXTENDS :
+				this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);				
+				this.scribe.space();
+				wildcard.bound.traverse(this, scope);
+				break;
+			case Wildcard.UNBOUND :
+				if (this.preferences.insert_space_after_question_in_wilcard) {
+					this.scribe.space();
+				}
+		}
+		return false;
+	}
+	public boolean visit(Wildcard wildcard, ClassScope scope) {
+		this.scribe.printNextToken(TerminalTokens.TokenNameQUESTION, this.preferences.insert_space_before_question_in_wilcard);
+		switch(wildcard.kind) {
+			case Wildcard.SUPER :
+				this.scribe.printNextToken(TerminalTokens.TokenNamesuper, true);				
+				this.scribe.space();
+				wildcard.bound.traverse(this, scope);
+				break;
+			case Wildcard.EXTENDS :
+				this.scribe.printNextToken(TerminalTokens.TokenNameextends, true);				
+				this.scribe.space();
+				wildcard.bound.traverse(this, scope);
+				break;
+			case Wildcard.UNBOUND :
+				if (this.preferences.insert_space_after_question_in_wilcard) {
+					this.scribe.space();
+				}
+		}
+		return false;
+	}
+    
+        /* Martijn Kruithof {} */
+    private void formatStatementAsBlock(BlockScope scope, final int line,
+            final Statement statement) {
+        formatLeftCurlyBrace(line, this.preferences.brace_position_for_block);
+        this.scribe
+                .insertLBrace(this.preferences.insert_space_before_opening_brace_in_block);
+        this.scribe.indent();
+        this.scribe.printNewLine();
+        statement.traverse(this, scope);
+        if (statement instanceof Expression) {
+            this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON,
+                    this.preferences.insert_space_before_semicolon);
+            this.scribe.printTrailingComment();
+        }
+        this.scribe.unIndent();
+        this.scribe.printNewLine();
+        this.scribe.insertRBrace(true);
+    }
+}
