/******************************************************************************* * Copyright © 2008, 2013 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 * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.ui.internal.formatting; import java.io.BufferedReader; import java.io.StringReader; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Stack; import java_cup.runtime.Symbol; import org.eclipse.edt.compiler.core.EGLKeywordHandler; import org.eclipse.edt.compiler.core.ast.*; import org.eclipse.edt.compiler.core.ast.ExitStatement.ExitModifier; import org.eclipse.edt.compiler.core.ast.ExitStatement.OptionalExpressionExitModifier; import org.eclipse.edt.compiler.core.ast.Class; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.DeleteEdit; import org.eclipse.text.edits.InsertEdit; import org.eclipse.text.edits.MalformedTreeException; import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.text.edits.TextEdit; public class CodeFormatterVisitor extends AbstractASTPartVisitor { private final static char SPACECHAR = ' '; private final static String SPACE = " "; //NON-NLS-1 //$NON-NLS-1$ private final static String TAB = "\t"; //NON-NLS-1 //$NON-NLS-1$ private Map fPreferenceSetting; private java_cup.runtime.Scanner fScanner; private IDocument fDocument; private String fLineSeparator; private int fFormatOffset; private int fFormatLength; private int fIndentationLevel; private List fEdits; private Symbol fPrevToken, fCurrToken; private boolean fIsFirstImportDeclaration = true; private boolean fGlobalAddSpace = true; private int fGlobalNumOfBlankLines = -1; private int fCurrentWrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; /** * the current token's left(starting) column index of the line after formatting */ private int fCurrentColumn = 0; /** * list of PendingWrapEdit * a list to cache the possible pending wrap edits, depends on the wrapping necessarity, * we may wrap it using the wrapEdits or no wrap it using the noWrapEdits in each of the element */ private LinkedList /*PendingWrapEdit>*/ fPendingWrapEdits; private boolean fIsWrappingNecessary = false; private Stack fContextPath; // Flag to fix indentation in nested functions in external types & interfaces private boolean fIndentNeeded = true; private class PendingWrapEdit{ List fNoWrapEdits; //temporary list holds the no wrap edits, could be committed to fEdit if wrapping is not necessary int fNoWrapColumn; //saved column value after it is no wrap List fWrapEdits; //temporary list holds the wrap edits, could be committed to fEdit if wrapping is necessary int fWrapColumn; //saved column value after it is wrapped public PendingWrapEdit(List noWrapEdits, int noWrapCol, List wrapEdits, int wrapCol){ fNoWrapEdits = noWrapEdits; fNoWrapColumn = noWrapCol; fWrapEdits = wrapEdits; fWrapColumn = wrapCol; } } private static interface ICallBackFormatter{ public void format(Symbol prevToken, Symbol currToken); } public CodeFormatterVisitor(Map preferenceSetting, IDocument document, int offset, int length, int initialIndentationLevel, String lineSeparator){ fPreferenceSetting = preferenceSetting; fDocument = document; fFormatOffset = offset; fFormatLength = length; fLineSeparator = lineSeparator; fIndentationLevel = initialIndentationLevel; fEdits = new ArrayList(); fPendingWrapEdits = new LinkedList(); fContextPath = new Stack(); String strSource = document.get(); fScanner = new Lexer(new BufferedReader(new StringReader(strSource))); } private void setGlobalFormattingSettings(int numOfBlankLines, boolean addSpace, int wrappingPolicy){ fGlobalNumOfBlankLines = numOfBlankLines; fGlobalAddSpace = addSpace; fCurrentWrappingPolicy = wrappingPolicy; } public TextEdit format(File fileAST){ fileAST.accept(this); return getFinalEdits(); } public boolean visit(File file) { push2ContextPath(file); fCurrToken = nextToken(); fPrevToken = new Symbol(-1, 0, 0); //fake token to represent the token before the 1st token //remove any white space in the very beginning of the file // if(fCurrToken.left > 0){ // //there are spaces in the beginning of the file // fEdits.add(new DeleteEdit(0, fCurrToken.left)); // } return true; } private void endVisitNode(Node astNode){ popContextPath(); } public void endVisit(File file) { endVisitNode(file); }; /** * generic formatting, for the parts that we do not have specific formatting coded yet * at least, we maintain the current file */ public void visitPart(Part part) { final int partEndOffset = part.getLength() + part.getOffset(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { //close the part with end, should be aligned with the openning block if(fCurrToken.right == partEndOffset) printToken(fPrevToken, fCurrToken, 0, false); else printKeywordToken(fCurrToken, fEdits); } }; formatNode(part, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); } private int getIntPrefSetting(String key){ return CodeFormatterConstants.getIntPreferenceSetting(fPreferenceSetting, key); } private boolean getBooleanPrefSetting(String key){ return CodeFormatterConstants.getBooleanPreferenceSetting(fPreferenceSetting, key); } private int getEnumPrefSetting(String key){ return CodeFormatterConstants.getEnumPreferenceSetting(fPreferenceSetting, key); } private String getIndentationStringPreference(){ String indentationString = ""; //$NON-NLS-1$ int tabPolicyChoice = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_TABPOLICY); switch(tabPolicyChoice){ case CodeFormatterConstants.FORMATTER_PREF_TABPOLICY_SPACE_ONLY: StringBuffer strBuf = new StringBuffer(); int indentSpaceSize = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_INDENT_SIZE); for(int i=0; i<indentSpaceSize; i++) strBuf.append(SPACE); indentationString = strBuf.toString(); break; case CodeFormatterConstants.FORMATTER_PREF_TABPOLICY_TAB_ONLY: indentationString = TAB; break; } return indentationString; } private String getIndentationString() { StringBuffer strIndentationBuffer = new StringBuffer(); for(int j=0; j<fIndentationLevel; j++){ strIndentationBuffer.append(getIndentationStringPreference()); } return strIndentationBuffer.toString(); } private void indent(){ indent(1); } private void unindent(){ unindent(1); } /** * increment the indentation level by numOfIndents * @param numOfIndents */ private void indent(int numOfIndents){ fIndentationLevel += numOfIndents; } /** * decrement the indentation level by numOfIndents * @param numOfIndents */ private void unindent(int numOfIndents){ fIndentationLevel -= numOfIndents; if(fIndentationLevel < 0) fIndentationLevel = 0; } private void formatNode(Node astNode, ICallBackFormatter callbackFormatter, int numOfBlankLinesBeforeNode, boolean addSpaceBeforeNode){ formatNode(astNode, callbackFormatter, numOfBlankLinesBeforeNode, addSpaceBeforeNode, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); } /** * * @param astNode * @param callbackFormatter * @param numOfBlankLinesBeforeNode - number of blank lines before the astNode * <0 means no new lines, 0 means new line, >0 means blank lines * @param addSpaceBeforeNode - whether or not add a white space before the astNode * if numOfBlankLinesBeforeNode >=0, this value is ignored */ private void formatNode(Node astNode, ICallBackFormatter callbackFormatter, int numOfBlankLinesBeforeNode, boolean addSpaceBeforeNode, int wrappingPolicy){ int nodeStartOffset = astNode.getOffset(); int nodeEndOffset = astNode.getLength() + nodeStartOffset; if(printStuffBeforeNode(nodeStartOffset, numOfBlankLinesBeforeNode, addSpaceBeforeNode, wrappingPolicy)){ while(fCurrToken.right != nodeEndOffset && fCurrToken.sym != NodeTypes.EOF){ fPrevToken = fCurrToken; fCurrToken = nextToken(); callbackFormatter.format(fPrevToken, fCurrToken); fPrevToken = fCurrToken; } } } public boolean visit(PackageDeclaration packageDeclaration) { ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; if(prevToken.sym == NodeTypes.PACKAGE) addSpace = true; else if(currToken.sym == NodeTypes.SEMI) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); else addSpace = false; printToken(prevToken, currToken, -1, addSpace); } }; formatNode(packageDeclaration, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PKG), false); return false; } public boolean visit(ImportDeclaration importDeclaration) { int numOfBlankLineBeforeImports = 0; if(fIsFirstImportDeclaration) //only add user preferenced blank line before the 1st import declaration numOfBlankLineBeforeImports = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_IMPORT); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; if(prevToken.sym == NodeTypes.IMPORT) addSpace = true; else if(currToken.sym == NodeTypes.SEMI) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); else addSpace = false; printToken(prevToken, currToken, -1, addSpace); } }; formatNode(importDeclaration, callbackFormatter, numOfBlankLineBeforeImports, false); fIsFirstImportDeclaration = false; return false; } public boolean visit(DataItem dataItem) { push2ContextPath(dataItem); final CodeFormatterVisitor thisVisitor = this; final Type diTypeNode = dataItem.getType(); final List settingsBlocks = dataItem.getSettingsBlocks(); final SettingsBlock firstSettingsBlock = (settingsBlocks != null && !settingsBlocks.isEmpty()) ? (SettingsBlock)settingsBlocks.get(0) : null; ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; int numOfBlankLines = -1; if(currToken.left == diTypeNode.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); diTypeNode.accept(thisVisitor); } else if(firstSettingsBlock != null && currToken.left == firstSettingsBlock.getOffset()){ //now deal with settings block boolean isFirstSettingsBlock = true; for(Iterator it = settingsBlocks.iterator(); it.hasNext();){ SettingsBlock settingsBlock = (SettingsBlock)it.next(); setGlobalFormattingSettings(isFirstSettingsBlock ? getNumOfBlankLinesBeforeCurlyBrace() : 0, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(thisVisitor); isFirstSettingsBlock = false; } } else{ switch(prevToken.sym){ case NodeTypes.PRIVATE: addSpace = true; break; default: addSpace = false; break; } if(currToken.sym == NodeTypes.END) numOfBlankLines = 0; else numOfBlankLines = -1; printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(dataItem, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); popContextPath(); return false; } private int getNumOfBlankLinesBeforeCurlyBrace(){ int openCurlyPos = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_LCURLY_POS); int numOfBlankLinesBeforeCurly = -1; switch(openCurlyPos){ case CodeFormatterConstants.FORMATTER_PREF_BRACES_SAMELINE: numOfBlankLinesBeforeCurly = -1; break; case CodeFormatterConstants.FORMATTER_PREF_BRACES_NEXTLINE: case CodeFormatterConstants.FORMATTER_PREF_BRACES_NEXTLINE_INDENTED: numOfBlankLinesBeforeCurly = 0; break; } return numOfBlankLinesBeforeCurly; } public boolean visit(SettingsBlock settingsBlock) { push2ContextPath(settingsBlock); List settings = settingsBlock.getSettings(); int settingBlockWrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_SETTINGSBLOCK); //if more than the max len preference, then we will wrap the settings block //now we need to know user's preference on where to put the open curly brace when wrapping int openCurlyPos = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_LCURLY_POS); if(openCurlyPos == CodeFormatterConstants.FORMATTER_PREF_BRACES_NEXTLINE_INDENTED) indent(); //indentA printStuffBeforeToken(NodeTypes.LCURLY, fGlobalNumOfBlankLines, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS)); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); if(openCurlyPos == CodeFormatterConstants.FORMATTER_PREF_BRACES_SAMELINE) indent(numOfIndents4Wrapping); //indentB boolean isFirstSetting = true; boolean indentFirstSetting = false; int settingsCnt = settings.size(); if(settingsCnt == 1 && settingBlockWrappingPolicy != CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOCHANGE) settingBlockWrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; for(Iterator it=settings.iterator(); it.hasNext();){ int blankLines = -1; //print comma if there are more than one expressions if(!isFirstSetting){ printStuffBeforeToken(NodeTypes.COMMA, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_SETTINGS)); } else{ //for the 1st setting, and if open curly is on the next line //then 1st setting will start on a new line, and one indent from the open curly if(openCurlyPos != CodeFormatterConstants.FORMATTER_PREF_BRACES_SAMELINE){ blankLines = 0; indent(); //indentC indentFirstSetting = true; } } boolean addSpaceBeforeSetting = isFirstSetting?getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LCURLY_SETTINGS): getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_SETTINGS); Node settingNode = (Node)it.next(); setGlobalFormattingSettings(blankLines, addSpaceBeforeSetting, settingBlockWrappingPolicy); settingNode.accept(this); isFirstSetting = false; } if(indentFirstSetting) unindent(); //match indentC if(openCurlyPos == CodeFormatterConstants.FORMATTER_PREF_BRACES_SAMELINE) unindent(numOfIndents4Wrapping); //match indentB //if open curly is on the same line, then the close curly will always be after the last setting, no new line, no space. printStuffBeforeToken(NodeTypes.RCURLY, getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RCURLY_SETTINGS)); if(openCurlyPos == CodeFormatterConstants.FORMATTER_PREF_BRACES_NEXTLINE_INDENTED) unindent(); //match indentA popContextPath(); return false; } public boolean visit(Assignment assignment) { push2ContextPath(assignment); Expression lhsExpr = assignment.getLeftHandSide(); lhsExpr.accept(this); int numOfBlankLines = -1; boolean addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_ASSIGNMENT); Assignment.Operator assignOp = assignment.getOperator(); if(assignOp == Assignment.Operator.ASSIGN) printStuffBeforeToken(NodeTypes.ASSIGN, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.TIMES) printStuffBeforeToken(NodeTypes.TIMESEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.TIMESTIMES) printStuffBeforeToken(NodeTypes.TIMESTIMESEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.DIVIDE) printStuffBeforeToken(NodeTypes.DIVEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.MODULO) printStuffBeforeToken(NodeTypes.MODULOEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.PLUS) printStuffBeforeToken(NodeTypes.PLUSEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.MINUS) printStuffBeforeToken(NodeTypes.MINUSEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.OR) printStuffBeforeToken(NodeTypes.BITOREQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.AND) printStuffBeforeToken(NodeTypes.BITANDEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.XOR) printStuffBeforeToken(NodeTypes.XOREQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.CONCAT) printStuffBeforeToken(NodeTypes.CONCATEQ, numOfBlankLines, addSpace); else if(assignOp == Assignment.Operator.NULLCONCAT) printStuffBeforeToken(NodeTypes.NULLCONCATEQ, numOfBlankLines, addSpace); Expression rhsExpr = assignment.getRightHandSide(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_OP_ASSIGNMENT), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); rhsExpr.accept(this); popContextPath(); return false; } public boolean visit(Delegate delegate) { push2ContextPath(delegate); final CodeFormatterVisitor thisVisitor = this; final ReturnsDeclaration returnDecl = delegate.getReturnDeclaration(); final List parameters = delegate.getParameters(); final Parameter firstParameter = (parameters != null && !parameters.isEmpty()) ? (Parameter)parameters.get(0) : null; ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; int numOfBlankLines = -1; if(firstParameter != null && currToken.left == firstParameter.getOffset()){ //print parameters formatParameters(parameters, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FUNCPARMS)); } else if(returnDecl != null && currToken.left == returnDecl.getOffset()){ //print returns returnDecl.accept(thisVisitor); } else{ switch(prevToken.sym){ case NodeTypes.PRIVATE: case NodeTypes.DELEGATE: addSpace = true; break; default: addSpace = false; break; } if(currToken.sym == NodeTypes.LPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_FUNCPARMS); else if(currToken.sym == NodeTypes.RPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_FUNCPARMS); if(currToken.sym == NodeTypes.END) numOfBlankLines = 0; else numOfBlankLines = -1; printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(delegate, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); popContextPath(); return false; } public boolean visit(Record record) { // | privateAccessModifierOpt:privateAccessModifier1 RECORD:record1 ID:id1 partSubTypeOpt:partSubType1 structureContent_star:structureContents1 END:end1 // {: RESULT = new Record(privateAccessModifier1, new SimpleName(id1, id1left, id1right), partSubType1, structureContents1, privateAccessModifier1 == Boolean.FALSE ? record1left : privateAccessModifier1left, end1right); :} push2ContextPath(record); final CodeFormatterVisitor thisVisitor = this; final List structureContents = record.getStructureContents(); final Node firstStructureContent = (structureContents != null && !structureContents.isEmpty()) ? (Node)structureContents.get(0) : null; final Name subTypeName = record.getSubType(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; if(firstStructureContent != null && currToken.left == firstStructureContent.getOffset()){ indent(); formatStructureContents(structureContents); } else if(subTypeName != null && currToken.left == subTypeName.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); //add a space before the name subTypeName.accept(thisVisitor); } else{ int numOfBlankLines = -1; switch(prevToken.sym){ case NodeTypes.PRIVATE: case NodeTypes.RECORD: addSpace = true; break; default: addSpace = false; break; } if(currToken.sym == NodeTypes.TYPE) addSpace = true; else if(currToken.sym == NodeTypes.END){ if(firstStructureContent != null) unindent(); numOfBlankLines = 0; } printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(record, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); popContextPath(); return false; } public boolean visit(StructureItem structureItem) { // ::= levelOpt:level1 ID:id1 type:type1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // StructureItem // {: RESULT = new StructureItem(level1, new SimpleName(id1, id1left, id1right), type1, null, settingsBlock1, initializer1, false, false, level1 == null ? id1left : level1left, semi1right); :} // | levelOpt:level1 ID:id1 occursOpt:occurs1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // UntypedStructureItem // {: RESULT = new StructureItem(level1, new SimpleName(id1, id1left, id1right), null, occurs1, settingsBlock1, initializer1, false, false, level1 == null ? id1left : level1left, semi1right); :} // | levelOpt:level1 TIMES:times type:type1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // FillerStructureItem // {: RESULT = new StructureItem(level1, null, type1, null, settingsBlock1, initializer1, true, false, level1 == null ? timesleft : level1left, semi1right); :} // | levelOpt:level1 TIMES:times occursOpt:occurs1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // UntypedFillerStructureItem // {: RESULT = new StructureItem(level1, null, null, occurs1, settingsBlock1, initializer1, true, false, level1 == null ? timesleft : level1left, semi1right); :} // | levelOpt:level1 EMBED:embed name:name1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // EmbeddedRecordStructureItem // {: RESULT = new StructureItem(level1, null, new NameType(name1, name1left, name1right), null, settingsBlock1, initializer1, false, true, level1 == null ? embedleft : level1left, semi1right); :} push2ContextPath(structureItem); int numOfBlankLines = fGlobalNumOfBlankLines; boolean addSpace = fGlobalAddSpace; int wrappingPolicy = fCurrentWrappingPolicy; Name name = structureItem.getName(); if(name != null){ setGlobalFormattingSettings(numOfBlankLines, addSpace, wrappingPolicy); name.accept(this); } Type type = structureItem.getType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); type.accept(this); if(structureItem.hasSettingsBlock()){ SettingsBlock settingsBlock = structureItem.getSettingsBlock(); setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(this); } if(structureItem.hasInitializer()){ // | ASSIGN expr:expr1 // {: RESULT = expr1; :} printStuffBeforeToken(NodeTypes.ASSIGN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_ASSIGNMENT)); Expression initExpr = structureItem.getInitializer(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_OP_ASSIGNMENT), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_INITEXPR)); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); initExpr.accept(this); unindent(numOfIndents4Wrapping); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(Handler handler) { // | privateAccessModifierOpt:privateAccessModifier1 HANDLER:handler1 ID:id1 partSubTypeOpt:partSubType1 classContent_star:classContents1 END:end1 // {: RESULT = new Handler(privateAccessModifier1, new SimpleName(id1, id1left, id1right), partSubType1, classContents1, privateAccessModifier1 == Boolean.FALSE ? handler1left : privateAccessModifier1left, end1right); :} push2ContextPath(handler); final CodeFormatterVisitor thisVisitor = this; final List classContents = handler.getContents(); final Node firstClassContent = (classContents != null && !classContents.isEmpty()) ? (Node)classContents.get(0) : null; final Name subTypeName = handler.getSubType(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; if(firstClassContent != null && currToken.left == firstClassContent.getOffset()){ indent(); formatContents(classContents); } else if(subTypeName != null && currToken.left == subTypeName.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); //add a space before the name subTypeName.accept(thisVisitor); } else{ int numOfBlankLines = -1; switch(prevToken.sym){ case NodeTypes.PRIVATE: case NodeTypes.HANDLER: addSpace = true; break; default: addSpace = false; break; } if(currToken.sym == NodeTypes.TYPE) addSpace = true; else if(currToken.sym == NodeTypes.END){ if(firstClassContent != null) unindent(); numOfBlankLines = 0; } printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(handler, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); popContextPath(); return false; } public boolean visit(Class eglClass) { // | privateAccessModifierOpt:privateAccessModifier1 CLASS:class1 ID:id1 singleExtendsOpt:extends1 implementsOpt:implements1 partSubTypeOpt:partSubType1 eglClassContent_star:classContents1 END:end1 // {: RESULT = new EGLClass(privateAccessModifier1, new SimpleName(id1, id1left, id1right), extends1, implements1, partSubType1, classContents1, privateAccessModifier1 == Boolean.FALSE ? class1left : privateAccessModifier1left, end1right); :} push2ContextPath(eglClass); int numOfBlankLines = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL); boolean addSpace = false; if(eglClass.isPrivate()){ //print PRIVATE printStuffBeforeNode(eglClass.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } if(eglClass.isAbstract()) { //print ABSTRACT printStuffBeforeNode(eglClass.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } printStuffBeforeToken(NodeTypes.CLASS, numOfBlankLines, addSpace); Name name = eglClass.getName(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); name.accept(this); Name superType = eglClass.getExtends(); if(superType != null){ // | EXTENDS name:name1 // {: RESULT = name1; :} printStuffBeforeToken(NodeTypes.EXTENDS, -1, true); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); superType.accept(this); } List impls = eglClass.getImplementedInterfaces(); if(impls != null && !impls.isEmpty()){ // | IMPLEMENTS name_plus:names1 // {: RESULT = names1; :} printStuffBeforeToken(NodeTypes.IMPLEMENTS, -1, true); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatCommaSeparatedNodeList(impls, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_IMPL), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_IMPL), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IMPL)); } if(eglClass.hasSubType()){ printStuffBeforeToken(NodeTypes.TYPE, -1, true); Name subTypeName = eglClass.getSubType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); subTypeName.accept(this); } indent(); List clsContents = eglClass.getContents(); formatContents(clsContents); unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(Program program) { // | privateAccessModifierOpt:privateAccessModifier1 PROGRAM:program1 ID:id1 partSubTypeOpt:partSubType1 programParametersOpt:programParameters1 classContent_star:classContents1 END:end1 // {: RESULT = new Program(privateAccessModifier1, new SimpleName(id1, id1left, id1right), partSubType1, programParameters1, classContents1, privateAccessModifier1 == Boolean.FALSE ? program1left : privateAccessModifier1left, end1right); :} push2ContextPath(program); if(program.isPrivate()){ //print PRIVATE printStuffBeforeNode(program.getOffset(), getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); } int numOfBlankLines = program.isPrivate() ? -1 : getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL); boolean addSpace = program.isPrivate() ? true : false; printStuffBeforeToken(NodeTypes.PROGRAM, numOfBlankLines, addSpace); Name name = program.getName(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); name.accept(this); if(program.hasSubType()){ printStuffBeforeToken(NodeTypes.TYPE, -1, true); Name subTypeName = program.getSubType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); subTypeName.accept(this); } indent(); List classContents = program.getContents(); formatContents(classContents); unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(Service service) { // | privateAccessModifierOpt:privateAccessModifier1 SERVICE:service1 ID:id1 implementsOpt:implements1 classContent_star:classContents1 END:end1 // {: RESULT = new Service(privateAccessModifier1, new SimpleName(id1, id1left, id1right), implements1, classContents1, privateAccessModifier1 == Boolean.FALSE ? service1left : privateAccessModifier1left, end1right); :} push2ContextPath(service); if(service.isPrivate()){ //print PRIVATE printStuffBeforeNode(service.getOffset(), getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); } int numOfBlankLines = service.isPrivate() ? -1 : getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL); boolean addSpace = service.isPrivate() ? true : false; printStuffBeforeToken(NodeTypes.SERVICE, numOfBlankLines, addSpace); Name name = service.getName(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); name.accept(this); List impls = service.getImplementedInterfaces(); if(impls != null && !impls.isEmpty()){ // | IMPLEMENTS name_plus:names1 // {: RESULT = names1; :} printStuffBeforeToken(NodeTypes.IMPLEMENTS, -1, true); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatCommaSeparatedNodeList(impls, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_IMPL), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_IMPL), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IMPL)); } indent(); List clsContents = service.getContents(); formatContents(clsContents); unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(Interface interfaceNode) { // | privateAccessModifierOpt:privateAccessModifier1 INTERFACE:interface1 ID:id1 partSubTypeOpt:partSubType1 interfaceContent_star:interfaceContents1 END:end1 // {: RESULT = new Interface(privateAccessModifier1, new SimpleName(id1, id1left, id1right), partSubType1, interfaceContents1, privateAccessModifier1 == Boolean.FALSE ? interface1left : privateAccessModifier1left, end1right); :} push2ContextPath(interfaceNode); int numOfBlankLines = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL); boolean addSpace = false; if(interfaceNode.isPrivate()){ //print PRIVATE printStuffBeforeNode(interfaceNode.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } if(interfaceNode.hasExplicitAbstractModifier()) { //print ABSTRACT printStuffBeforeNode(interfaceNode.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } printStuffBeforeToken(NodeTypes.INTERFACE, numOfBlankLines, addSpace); Name name = interfaceNode.getName(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); name.accept(this); if(interfaceNode.hasSubType()){ printStuffBeforeToken(NodeTypes.TYPE, -1, true); Name subTypeName = interfaceNode.getSubType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); subTypeName.accept(this); } indent(); // Since functions in interfaces don't include a function body, // one less indent is needed. fIndentNeeded = false; List interfaceContents = interfaceNode.getContents(); formatContents(interfaceContents); fIndentNeeded = true; // restore unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(ExternalType externalType) { // | privateAccessModifierOpt:privateAccessModifier1 EXTERNALTYPE:externalType1 ID:id1 extendsOpt:extends1 partSubTypeOpt:partSubType1 externalTypeContent_star:externalTypeContents1 END:end1 // {: RESULT = new ExternalType(privateAccessModifier1, new SimpleName(id1, id1left, id1right), extends1, partSubType1, externalTypeContents1, privateAccessModifier1 == Boolean.FALSE ? externalType1left : privateAccessModifier1left, end1right); :} push2ContextPath(externalType); int numOfBlankLines = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL); boolean addSpace = false; if(externalType.isPrivate()){ //print PRIVATE printStuffBeforeNode(externalType.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } if (externalType.isAbstract()){ //print ABSTRACT printStuffBeforeNode(externalType.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } printStuffBeforeToken(NodeTypes.EXTERNALTYPE, numOfBlankLines, addSpace); Name name = externalType.getName(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); name.accept(this); List extendedTypes = externalType.getExtendedTypes(); if(extendedTypes != null && !extendedTypes.isEmpty()){ // | EXTENDS name_plus:names1 // {: RESULT = names1; :} printStuffBeforeToken(NodeTypes.EXTENDS, -1, true); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatCommaSeparatedNodeList(extendedTypes, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_IMPL), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_IMPL), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IMPL)); } if(externalType.hasSubType()){ printStuffBeforeToken(NodeTypes.TYPE, -1, true); Name subTypeName = externalType.getSubType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); subTypeName.accept(this); } indent(); // Since functions in external types don't include a function body, // one less indent is needed. fIndentNeeded = false; List externalTypeContents = externalType.getContents(); formatContents(externalTypeContents); fIndentNeeded = true; // restore unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(Constructor constructor) { // | CONSTRUCTOR:constructor1 LPAREN functionParameter_star:functionParameters1 RPAREN settingsBlockOpt:settingsBlock1 SEMI:semi1 // {: RESULT = new Constructor(functionParameters1, settingsBlock1, constructor1left, semi1right); :} push2ContextPath(constructor); //print CONSTRUCTOR printStuffBeforeNode(constructor.getOffset(), getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_NESTEDFUNC), false); printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_FUNCPARMS)); List params = constructor.getParameters(); formatParameters(params, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FUNCPARMS)); printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_FUNCPARMS)); if(constructor.hasSettingsBlock()){ SettingsBlock settingsBlock = constructor.getSettingsBlock(); setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(this); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(Enumeration enumeration) { // | privateAccessModifierOpt:privateAccessModifier1 ENUMERATION:enumeration1 ID:id1 settingsBlockOpt:settingsBlock1 enumerationField_star:fields END:end1 // {: RESULT = new Enumeration(privateAccessModifier1, new SimpleName(id1, id1left, id1right), settingsBlock1, fields, privateAccessModifier1 == Boolean.FALSE ? enumeration1left : privateAccessModifier1left, end1right); :} push2ContextPath(enumeration); if(enumeration.isPrivate()){ //print PRIVATE printStuffBeforeNode(enumeration.getOffset(), getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); } int numOfBlankLines = enumeration.isPrivate() ? -1 : getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL); boolean addSpace = enumeration.isPrivate() ? true : false; printStuffBeforeToken(NodeTypes.ENUMERATION, numOfBlankLines, addSpace); Name name = enumeration.getName(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); name.accept(this); if(enumeration.hasSettingsBlock()){ SettingsBlock settingsBlock = enumeration.getSettingsBlock(); setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(this); } indent(); List fields = enumeration.getFields(); formatCommaSeparatedNodeList(fields, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_ENUM), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_ENUM), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_ENUM)); unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(EnumerationField enumerationField) { // ::= ID:id1 // {: RESULT = new EnumerationField(new SimpleName(id1, id1left, id1right), null, id1left, id1right); :} // | ID:id1 ASSIGN expr:expr1 // {: RESULT = new EnumerationField(new SimpleName(id1, id1left, id1right), expr1, id1left, expr1right); :} push2ContextPath(enumerationField); Name name = enumerationField.getName(); name.accept(this); if(enumerationField.hasConstantValue()){ printStuffBeforeToken(NodeTypes.ASSIGN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_ASSIGNMENT)); Expression expr = enumerationField.getConstantValue(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_OP_ASSIGNMENT), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); } popContextPath(); return false; } public boolean visit(Library library) { // | privateAccessModifierOpt:privateModifier1 LIBRARY:lib1 ID:id1 partSubTypeOpt:subType classContent_star:contents END:end // {: RESULT = new Library(privateModifier1, new SimpleName(id1,id1left,id1right), subType, contents, privateModifier1 == Boolean.FALSE ? lib1left : privateModifier1left, endright); :} push2ContextPath(library); final CodeFormatterVisitor thisVisitor = this; final List classContents = library.getContents(); final Node firstClassContent = (classContents != null && !classContents.isEmpty()) ? (Node)classContents.get(0) : null; final Name subTypeName = library.getSubType(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; if(firstClassContent != null && currToken.left == firstClassContent.getOffset()){ indent(); formatContents(classContents); } else if(subTypeName != null && currToken.left == subTypeName.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); //add a space before the name subTypeName.accept(thisVisitor); } else{ int numOfBlankLines = -1; switch(prevToken.sym){ case NodeTypes.PRIVATE: case NodeTypes.LIBRARY: addSpace = true; break; default: addSpace = false; break; } if(currToken.sym == NodeTypes.TYPE) addSpace = true; else if(currToken.sym == NodeTypes.END){ if(firstClassContent != null) unindent(); numOfBlankLines = 0; } printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(library, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDECL), false); popContextPath(); return false; } private void formatContents(List contents){ if(contents != null){ boolean isFirstContent = true; for(Iterator it=contents.iterator(); it.hasNext();){ Node content = (Node)it.next(); if(content instanceof SettingsBlock){ setGlobalFormattingSettings(isFirstContent ? getNumOfBlankLinesBeforeCurlyBrace() : 0, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); } content.accept(this); isFirstContent = false; } } } private void formatStructureContents(List structureContents){ if(structureContents != null){ boolean isFirstContent = true; for(Iterator it=structureContents.iterator(); it.hasNext();){ int levelIndex = 0; //print new line for each class content Node structureContent = (Node)it.next(); if(structureContent instanceof SettingsBlock && isFirstContent) setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); else setGlobalFormattingSettings(0, false, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); structureContent.accept(this); unindent(levelIndex); isFirstContent = false; } } } public boolean visit(NestedFunction nestedFunction) { // | privateAccessModifierOpt:privateModifier1 FUNCTION:function1 ID:id1 LPAREN functionParameter_star:parms RPAREN returnsOpt:returns1 stmt_star:stmts END:end1 // {: RESULT = new NestedFunction(privateModifier1, Boolean.FALSE, new SimpleName(id1,id1left,id1right), parms, returns1, stmts, false, privateModifier1 == Boolean.FALSE ? function1left : privateModifier1left, end1right); :} // ::= privateAccessModifierOpt:privateAccessModifier1 staticAccessModifierOpt:staticAccessModifier1 FUNCTION:function1 ID:id1 LPAREN functionParameter_star:functionParameters1 RPAREN returnsOpt:returns1 settingsBlockOpt:settingsBlock1 SEMI:semi1 // {: RESULT = new NestedFunction(privateAccessModifier1, staticAccessModifier1, new SimpleName(id1,id1left,id1right), functionParameters1, returns1, settingsBlock1 == null ? Collections.EMPTY_LIST : Arrays.asList(new Object[] {settingsBlock1}), true, (privateAccessModifier1 == Boolean.FALSE && staticAccessModifier1 == Boolean.FALSE ? function1left : (privateAccessModifier1 == Boolean.FALSE ? staticAccessModifier1left : privateAccessModifier1left)), semi1right); :} push2ContextPath(nestedFunction); final CodeFormatterVisitor thisVisitor = this; final ReturnsDeclaration returnDecl = nestedFunction.getReturnDeclaration(); final List parameters = nestedFunction.getFunctionParameters(); final Parameter firstParameter = (parameters != null && !parameters.isEmpty()) ? (Parameter)parameters.get(0) : null; final List<Statement> stmts = nestedFunction.getStmts(); final Node firstStmt = (stmts != null && !stmts.isEmpty()) ? (Node)stmts.get(0) : null; final SettingsBlock settingsBlock = nestedFunction.getSettingsBlock(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { if(firstParameter != null && currToken.left == firstParameter.getOffset()){ //print parameters formatParameters(parameters, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FUNCPARMS)); } else if(returnDecl != null && currToken.left == returnDecl.getOffset()){ //print returns returnDecl.accept(thisVisitor); } else if((firstStmt != null) && (currToken.left == firstStmt.getOffset())){ if (fIndentNeeded) { indent(); //indentA } formatStatements(stmts); } else if(settingsBlock != null && currToken.left == settingsBlock.getOffset()){ setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(thisVisitor); } else{ boolean addSpace = false; int numOfBlankLines = -1; switch(prevToken.sym){ case NodeTypes.PRIVATE: case NodeTypes.STATIC: case NodeTypes.FUNCTION: case NodeTypes.ABSTRACT: addSpace = true; break; default: addSpace = false; break; } if(currToken.sym == NodeTypes.LPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_FUNCPARMS); else if(currToken.sym == NodeTypes.RPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_FUNCPARMS); else if(currToken.sym == NodeTypes.SEMI) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); if(currToken.sym == NodeTypes.END){ if(firstStmt != null) unindent(); //match indentA numOfBlankLines = 0; } else numOfBlankLines = -1; printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(nestedFunction, callbackFormatter, getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_NESTEDFUNC), false); popContextPath(); return false; } private void formatStatements(List<Statement> stmts){ if(stmts != null){ for(Iterator<Statement> it=stmts.iterator(); it.hasNext();){ //print new line for each class content Statement stmt = it.next(); setGlobalFormattingSettings(0, false, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); stmt.accept(this); } } } public boolean visit(FunctionDataDeclaration functionDataDeclaration) { // ::= ID_plus:IDs1 type:type1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // Variable declaration // {: RESULT = new FunctionDataDeclaration(IDs1, type1, settingsBlock1, initializer1, false, IDs1left, semi1right); :} // | CONST:const1 ID_plus:IDs1 type:type1 settingsBlockOpt:settingsBlock1 ASSIGN expr:expr1 SEMI:semi1 // Constant declaration // {: RESULT = new FunctionDataDeclaration(IDs1, type1, settingsBlock1, expr1, true, const1left, semi1right); :} push2ContextPath(functionDataDeclaration); boolean addSpace = fGlobalAddSpace; int numOfBlankLines = fGlobalNumOfBlankLines; if(functionDataDeclaration.isConstant()){ printStuffBeforeNode(functionDataDeclaration.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } List names = functionDataDeclaration.getNames(); Type type = functionDataDeclaration.getType(); SettingsBlock settingsBlock = functionDataDeclaration.getSettingsBlockOpt(); Expression initExpr = functionDataDeclaration.getInitializer(); setGlobalFormattingSettings(numOfBlankLines, addSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatCommaSeparatedNodeList(names, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_DATADECL), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_DATADECL), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_VAR_DELC)); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); type.accept(this); //I decided not to put space before ? if (functionDataDeclaration.isNullable()) { printStuffBeforeToken(NodeTypes.QUESTION, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_QUESTION_FIELDS)); } if(settingsBlock != null){ setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(this); } if(initExpr != null){ printStuffBeforeToken(NodeTypes.ASSIGN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_ASSIGNMENT)); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_OP_ASSIGNMENT), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_INITEXPR)); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); initExpr.accept(this); unindent(numOfIndents4Wrapping); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(AssignmentStatement assignmentStatement) { // | assignment:assignment1 SEMI:semi1 // {: RESULT = new AssignmentStatement(assignment1, assignment1left, semi1right); :} push2ContextPath(assignmentStatement); Assignment assignment = assignmentStatement.getAssignment(); assignment.accept(this); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(FunctionInvocationStatement functionInvocationStatement) { // | functionInvocation:functionInvocation1 SEMI:semi1 // {: RESULT = new FunctionInvocationStatement(functionInvocation1, functionInvocation1left, semi1right); :} push2ContextPath(functionInvocationStatement); FunctionInvocation funcInvoc = functionInvocationStatement.getFunctionInvocation(); funcInvoc.accept(this); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(SetValuesStatement setValuesStatement) { // | primary:primary1 settingsBlock:settingsBlock1 SEMI:semi1 // Set values statement // {: RESULT = new SetValuesStatement(new SetValuesExpression(primary1, settingsBlock1, primary1left, settingsBlock1right), primary1left, semi1right); :} // | name:name1 settingsBlock:settingsBlock1 SEMI:semi1 // Set values statement // {: RESULT = new SetValuesStatement(new SetValuesExpression(name1, settingsBlock1, name1left, settingsBlock1right), name1left, semi1right); :} push2ContextPath(setValuesStatement); Expression setValExpr = setValuesStatement.getSetValuesExpression(); setValExpr.accept(this); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(CallStatement callStatement) { // | CALL:call1 name:expr1 callParametersOpt:parametersOpt callReturnToOpt:callReturnTo callOnExceptionOpt:onExcept1 settingsBlockOpt:settingsBlock SEMI:semi1 // {: RESULT = new CallStatement(expr1, parametersOpt, settingsBlock, callReturnTo, onExcept1, call1left, semi1right); :} // // | CALL:call1 primaryNoNew:expr1 callParametersOpt:parametersOpt callReturnToOpt:callReturnTo callOnExceptionOpt:onExcept1 settingsBlockOpt:settingsBlock SEMI:semi1 // {: RESULT = new CallStatement(expr1, parametersOpt, settingsBlock, callReturnTo, onExcept1, call1left, semi1right); :} // callParametersOpt // ::= // | LPAREN expr_plus:exprs1 RPAREN // {: RESULT = exprs1; :} // callReturnToOpt // ::= // | RETURNING:returning1 TO name:expr1 // {: RESULT = new CallbackTarget(expr1, returning1left, expr1right); :} // // | RETURNING:returning1 TO primaryNoNew:expr1 // {: RESULT = new CallbackTarget(expr1, returning1left, expr1right); :} // ; // // callOnExceptionOpt // ::= // | ONEXCEPTION:onexception1 name:expr1 // {: RESULT = new CallbackTarget(expr1, onexception1left, expr1right); :} // // | ONEXCEPTION:onexception1 primaryNoNew:expr1 // {: RESULT = new CallbackTarget(expr1, onexception1left, expr1right); :} // ; push2ContextPath(callStatement); final CodeFormatterVisitor thisVisitor = this; final Expression expr = callStatement.getInvocationTarget(); final Expression usingExpr = callStatement.getUsing(); final CallSynchronizationValues callSynValues = callStatement.getCallSynchronizationValues(); final CallbackTarget callbackTgt = (callSynValues != null) ? callSynValues.getReturnTo() : null; final Expression callbackExpr = (callbackTgt != null) ? callbackTgt.getExpression() : null; final CallbackTarget errCallbackTgt = (callSynValues != null) ?callSynValues.getOnException() : null; final Expression errCallbackExpr = (errCallbackTgt != null ) ? errCallbackTgt.getExpression() : null; final SettingsBlock settingsBlock = callStatement.getSettingsBlock(); final List callParams = callStatement.getArguments(); final Expression firstCallParm = (callParams != null && !callParams.isEmpty()) ? (Expression)callParams.get(0) : null; final int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { if(currToken.left == expr.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(thisVisitor); } else if(firstCallParm != null && currToken.left == firstCallParm.getOffset()){ setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_CALLSTMT), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(callParams, getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_ARGS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_CALLSTMT), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_CALLSTMT)); } else if(usingExpr != null && currToken.left == usingExpr.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); usingExpr.accept(thisVisitor); } else if(callbackExpr != null && currToken.left == callbackExpr.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); callbackExpr.accept(thisVisitor); } else if(errCallbackExpr != null && currToken.left == errCallbackExpr.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); errCallbackExpr.accept(thisVisitor); } else if(settingsBlock != null && currToken.left == settingsBlock.getOffset()){ setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(thisVisitor); } else { boolean addSpace = false; int numOfBlankLines = -1; int wrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; switch(prevToken.sym){ case NodeTypes.RETURNING: case NodeTypes.TO: addSpace = true; break; } if(currToken.sym == NodeTypes.LPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_CALLSTMT); else if(currToken.sym == NodeTypes.RPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_CALLSTMT); else if(currToken.sym == NodeTypes.USING){ addSpace = true; wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_CALLSTMT); if(usingExpr == null) indent(numOfIndents4Wrapping); //indentA } else if(currToken.sym == NodeTypes.RETURNING){ //this implies that callbackTgt != null addSpace = true; wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_CALLSTMT); indent(numOfIndents4Wrapping); //indentA } else if(currToken.sym == NodeTypes.ONEXCEPTION){ //implies that errCallbackTgt != null addSpace = true; wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_CALLSTMT); if(callbackTgt == null) indent(numOfIndents4Wrapping); //indentA } else if(currToken.sym == NodeTypes.SEMI){ addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); if(callbackTgt != null || errCallbackTgt != null) unindent(numOfIndents4Wrapping); //match indentA } printToken(prevToken, currToken, numOfBlankLines, addSpace, wrappingPolicy); } } }; formatNode(callStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(GotoStatement gotoStatement) { // | GOTO:goto1 ID:id1 SEMI:semi1 // {: RESULT = new GotoStatement(id1, goto1left, semi1right); :} push2ContextPath(gotoStatement); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; int numOfBlankLines = -1; if(prevToken.sym == NodeTypes.GOTO) addSpace = true; if(currToken.sym == NodeTypes.SEMI) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); printToken(prevToken, currToken, numOfBlankLines, addSpace); } }; formatNode(gotoStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(LabelStatement labelStatement) { // | ID:id1 COLON:colon1 // label statement // {: RESULT = new LabelStatement(id1, id1left, colon1right); :} push2ContextPath(labelStatement); unindent(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; int numOfBlankLines = -1; if(currToken.sym == NodeTypes.COLON) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COLON_LABELSTMT); printToken(prevToken, currToken, numOfBlankLines, addSpace); } }; formatNode(labelStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); indent(); popContextPath(); return false; } public boolean visit(MoveStatement moveStatement) { // | MOVE:move1 expr:expr1 TO lvalue:lvalue1 moveModifier_star:moveModifiers1 SEMI:semi1 // {: RESULT = new MoveStatement(expr1, lvalue1, moveModifiers1, move1left, semi1right); :} push2ContextPath(moveStatement); //print MOVE printStuffBeforeNode(moveStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression sourceExpr = moveStatement.getSource(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); sourceExpr.accept(this); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); //indentA int moveWrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_MOVESTMT); printStuffBeforeToken(NodeTypes.TO, -1, true, moveWrappingPolicy); Expression targetExpr = moveStatement.getTarget(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); targetExpr.accept(this); MoveModifier moveModifier = moveStatement.getMoveModifierOpt(); if(moveModifier != null){ // moveModifier // ::= BYNAME // {: RESULT = MoveStatement.DefaultMoveModifier.BYNAME; :} // | BYPOSITION // {: RESULT = MoveStatement.DefaultMoveModifier.BYPOSITION; :} // | FOR ALL // {: RESULT = MoveStatement.DefaultMoveModifier.FORALL; :} // | FOR expr:expr1 // {: RESULT = new ForMoveModifier(expr1); :} // | WITHV60COMPAT // {: RESULT = MoveStatement.DefaultMoveModifier.WITHV60COMPAT; :} indent(numOfIndents4Wrapping); //indentB if(moveModifier.isByName()) printStuffBeforeToken(NodeTypes.BYNAME, -1, true, moveWrappingPolicy); else if(moveModifier.isByPosition()) printStuffBeforeToken(NodeTypes.BYPOSITION, -1, true, moveWrappingPolicy); else if(moveModifier.isForAll()){ printStuffBeforeToken(NodeTypes.FOR, -1, true, moveWrappingPolicy); printStuffBeforeToken(NodeTypes.ALL, -1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); } else if(moveModifier.isFor()){ printStuffBeforeToken(NodeTypes.FOR, -1, true, moveWrappingPolicy); Expression forMoveExpr = moveModifier.getExpression(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); forMoveExpr.accept(this); } else if(moveModifier.isWithV60Compat()) printStuffBeforeToken(NodeTypes.WITHV60COMPAT, -1, true, moveWrappingPolicy); unindent(numOfIndents4Wrapping); //match indentB } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); unindent(numOfIndents4Wrapping); //match indentA popContextPath(); return false; } public boolean visit(ReturnStatement returnStatement) { // | RETURN:return1 SEMI:semi1 // {: RESULT = new ReturnStatement(null, return1left, semi1right); :} // | RETURN:return1 LPAREN:lparen expr:expr1 RPAREN:rparen SEMI:semi1 // {: RESULT = new ReturnStatement(new ParenthesizedExpression(expr1, lparenleft, rparenright), return1left, semi1right); :} push2ContextPath(returnStatement); printStuffBeforeNode(returnStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression parenthesizedExpr = returnStatement.getParenthesizedExprOpt(); if(parenthesizedExpr != null){ //fGlobalAddSpace will be ignored in visit(ParenthesizedExpression), it will use addSpace before ( preference setting setGlobalFormattingSettings(-1, fGlobalAddSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); parenthesizedExpr.accept(this); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(SetStatement setStatement) { // | SET:set1 setTarget_plus:setTargets1 ID_plus:IDs1 SEMI:semi1 // {: RESULT = new SetStatement(setTargets1, simpleNameListToStringList(IDs1), set1left, semi1right); :} push2ContextPath(setStatement); //print SET printStuffBeforeNode(setStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); boolean addSapceAfterComma = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_SETSTMT); boolean addSpaceBeforeComma = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_SETSTMT); int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_SETSTMT); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); List setTargets = setStatement.getSetTargets(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(setTargets, wrappingPolicy, addSpaceBeforeComma, addSapceAfterComma); //======================================================================================================= //we need to reparse the ID_plus, since it is being converted to list of Strings rather than a list of AST Names node in the AST tree //we would need to reparse it to get the offset or symbol info of the ID tokens try { int targetsCnt = setTargets.size(); //try to get the last setTarget's right offset Expression lastTarget = (Expression)setTargets.get(targetsCnt-1); int lastTargetRight = lastTarget.getOffset() + lastTarget.getLength(); int setStatementRight = setStatement.getOffset() + setStatement.getLength(); String strIDs = fDocument.get(lastTargetRight, setStatementRight-lastTargetRight); java_cup.runtime.Scanner scanner = new Lexer(new BufferedReader(new StringReader(strIDs))); Symbol token = scanner.next_token(); int numOfBlankLines = -1; boolean addSpace = false; boolean isFirstID = true; //indent it twice as much, so when using forced split, the id wrapping is indented from the setTarget_plus indent(numOfIndents4Wrapping*2); while(token.sym != NodeTypes.EOF){ int idwrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; switch(token.sym){ case NodeTypes.ID:{ if(isFirstID) addSpace = true; else{ addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_SETSTMT); idwrappingPolicy = wrappingPolicy; } isFirstID = false; } break; case NodeTypes.COMMA: addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_SETSTMT); break; case NodeTypes.SEMI: addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); break; } printStuffBeforeNode(token.left+lastTargetRight, numOfBlankLines, addSpace, idwrappingPolicy); token = scanner.next_token(); } unindent(numOfIndents4Wrapping*2); } catch (Exception e) { e.printStackTrace(); } //======================================================================================================= popContextPath(); return false; } public boolean visit(TryStatement tryStatement) { // | TRY:try1 stmt_star:stmts1 onException_star:onExcept1 END:end1 // {: RESULT = new TryStatement(stmts1, onExcept1, try1left, end1right); :} push2ContextPath(tryStatement); printStuffBeforeNode(tryStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); indent(); List stmts = tryStatement.getStmts(); if(stmts != null) formatStatements(stmts); unindent(); List onExcepts = tryStatement.getOnExceptionBlocks(); if(onExcepts != null && !onExcepts.isEmpty()){ for(Iterator it = onExcepts.iterator(); it.hasNext();){ Node onExceptBlock = (Node)it.next(); setGlobalFormattingSettings(0, false, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); onExceptBlock.accept(this); } } printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(OnExceptionBlock onExceptionBlock) { // ::= ONEXCEPTION:onexception1 stmt_star:stmts1 // {: RESULT = new OnExceptionBlock(stmts1, null, null, onexception1left, stmts1right); :} // | ONEXCEPTION:onexception1 LPAREN ID:id1 type:type1 RPAREN stmt_star:stmts1 // {: RESULT = new OnExceptionBlock(stmts1, new SimpleName(id1, id1left, id1right), type1, onexception1left, stmts1right); :} push2ContextPath(onExceptionBlock); printStuffBeforeNode(onExceptionBlock.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_ONEXCEPTION)); Name exceptionName = onExceptionBlock.getExceptionName(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_ONEXCEPTION), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); exceptionName.accept(this); Type exceptionType = onExceptionBlock.getExceptionType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); exceptionType.accept(this); printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_ONEXCEPTION)); indent(); final List stmts = onExceptionBlock.getStmts(); formatStatements(stmts); unindent(); popContextPath(); return false; } public boolean visit(ThrowStatement throwStatement) { // | THROW:throw1 expr:expr1 SEMI:semi1 // {: RESULT = new ThrowStatement(expr1, throw1left, semi1right); :} push2ContextPath(throwStatement); printStuffBeforeNode(throwStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = throwStatement.getExpression(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(CaseStatement caseStatement) { // | CASE:case1 whenClause_star:whenClauses1 defaultClauseOpt:defaultClause1 END:end1 // {: RESULT = new CaseStatement(null, whenClauses1, defaultClause1, case1left, end1right); :} // | CASE:case1 LPAREN:lparen expr:expr1 RPAREN:rparen whenClause_star:whenClauses1 defaultClauseOpt:defaultClause1 END:end1 // {: RESULT = new CaseStatement(new ParenthesizedExpression(expr1, lparenleft, rparenright), whenClauses1, defaultClause1, case1left, end1right); :} push2ContextPath(caseStatement); printStuffBeforeNode(caseStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); indent(); if(caseStatement.hasCriterion()){ Expression expr = caseStatement.getCriterion(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_CASE), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); } List whens = caseStatement.getWhenClauses(); if(whens != null){ for(Iterator it = whens.iterator(); it.hasNext();){ Node when = (Node)it.next(); setGlobalFormattingSettings(0, false, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); when.accept(this); } } if(caseStatement.hasOtherwiseClause()){ OtherwiseClause otherwise = caseStatement.getDefaultClause(); setGlobalFormattingSettings(0, false, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); otherwise.accept(this); } unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(WhenClause whenClause) { // ::= WHEN:when1 LPAREN expr_plus:exprs1 RPAREN stmt_star:stmts1 // {: RESULT = new WhenClause(exprs1, stmts1, when1left, stmts1right); :} push2ContextPath(whenClause); printStuffBeforeNode(whenClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_WHEN)); List exprs = whenClause.getExpr_plus(); if(exprs != null && !exprs.isEmpty()){ setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_WHEN), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(exprs, getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_EXPRS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_WHEN), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_WHEN)); } printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_WHEN)); indent(); List stmts = whenClause.getStmts(); if(stmts != null) formatStatements(stmts); unindent(); popContextPath(); return false; } public boolean visit(OtherwiseClause otherwiseClause) { // | OTHERWISE:otherwise1 stmt_star:stmts1 // {: RESULT = new OtherwiseClause(stmts1, otherwise1left, stmts1right); :} push2ContextPath(otherwiseClause); printStuffBeforeNode(otherwiseClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); indent(); List stmts = otherwiseClause.getStatements(); if(stmts != null) formatStatements(stmts); unindent(); popContextPath(); return false; } public boolean visit(IfStatement ifStatement) { // | IF:if1 LPAREN expr:expr1 RPAREN stmt_star:stmts1 elseOpt:else1 END:end1 // {: RESULT = new IfStatement(expr1, stmts1, else1, if1left, end1right); :} push2ContextPath(ifStatement); printStuffBeforeNode(ifStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_IF)); Expression expr = ifStatement.getCondition(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_IF), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_IF)); indent(); List stmts = ifStatement.getStmts(); if(stmts != null) formatStatements(stmts); unindent(); if(ifStatement.hasElse()){ ElseBlock elseBlock = ifStatement.getElse(); setGlobalFormattingSettings(0, false, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); elseBlock.accept(this); } printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(ElseBlock elseBlock) { // | ELSE:else1 stmt_star:stmts1 // {: RESULT = new ElseBlock(stmts1, else1left, stmts1right); :} push2ContextPath(elseBlock); printStuffBeforeNode(elseBlock.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); indent(); List stmts = elseBlock.getStmts(); if(stmts != null) formatStatements(stmts); unindent(); popContextPath(); return false; } public boolean visit(WhileStatement whileStatement) { // | WHILE:while1 LPAREN expr:expr1 RPAREN stmt_star:stmts1 END:end1 // {: RESULT = new WhileStatement(expr1, stmts1, while1left, end1right); :} push2ContextPath(whileStatement); printStuffBeforeNode(whileStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_WHILE)); Expression expr = whileStatement.getExpr(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_WHILE), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_WHILE)); indent(); List stmts = whileStatement.getStmts(); if(stmts != null) formatStatements(stmts); unindent(); printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(ForStatement forStatement) { // | FOR:for1 LPAREN lvalue:lvalue1 fromExprOpt:fromExpr1 TO expr:expr1 stepOpt:step1 RPAREN stmt_star:stmts1 END:end1 // {: RESULT = new ForStatement(lvalue1, null, null, fromExpr1, expr1, step1, stmts1, for1left, end1right); :} // | FOR:for1 LPAREN ID:id1 type:type1 fromExprOpt:fromExpr1 TO expr:expr1 stepOpt:step1 RPAREN stmt_star:stmts1 END:end1 // {: RESULT = new ForStatement(null, new SimpleName(id1, id1left, id1right), type1, fromExpr1, expr1, step1, stmts1, for1left, end1right); :} push2ContextPath(forStatement); printStuffBeforeNode(forStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_FOR)); if(forStatement.hasVariableDeclaration()){ Name varDeclName = forStatement.getVariableDeclarationName(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FOR), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); varDeclName.accept(this); Type varDeclType = forStatement.getVariableDeclarationType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); varDeclType.accept(this); } else{ Expression lvalue = forStatement.getCounterVariable(); if(lvalue != null){ setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FOR), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); lvalue.accept(this); } } if(forStatement.hasFromIndex()){ // | FROM expr:expr1 // {: RESULT = expr1; :} printStuffBeforeToken(NodeTypes.FROM, -1, true); Expression fromExpr = forStatement.getFromIndex(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); fromExpr.accept(this); } int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); //indentA int forWrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_FORSTMT); printStuffBeforeToken(NodeTypes.TO, -1, true, forWrappingPolicy); Expression endExpr = forStatement.getEndIndex(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); endExpr.accept(this); // stepOpt // ::= // | BY expr:expr1 // {: RESULT = new ForStatement.IncrementForStep(expr1); :} // | DECREMENT BY expr:expr1 // {: RESULT = new ForStatement.DecrementForStep(expr1); :} if(forStatement.hasPositiveDelta()) printStuffBeforeToken(NodeTypes.BY, -1, true, forWrappingPolicy); else if(forStatement.hasNegativeDelta()){ printStuffBeforeToken(NodeTypes.DECREMENT, -1, true, forWrappingPolicy); printStuffBeforeToken(NodeTypes.BY, -1, true); } Expression stepExpr = forStatement.getDeltaExpression(); if(stepExpr != null){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); stepExpr.accept(this); } printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_FOR)); unindent(numOfIndents4Wrapping); //match indentA indent(); //indentB List stmts = forStatement.getStmts(); if(stmts != null) formatStatements(stmts); unindent(); //match indentB printStuffBeforeToken(NodeTypes.END, 0, false); popContextPath(); return false; } public boolean visit(ForEachStatement forEachStatement) { // | FOREACH:foreach1 LPAREN foreachTarget:foreachTarget1 intoClauseOpt:intoClause1 RPAREN stmt_star:stmts1 END:end1 // {: RESULT = new ForEachStatement(foreachTarget1, intoClause1, stmts1, foreach1left, end1right); :} // foreachTarget // ::= expr:expr1 // {: RESULT = new ForEachStatement.ExpressionForEachTarget(expr1); :} // | FROM ID:resultSetID // {: RESULT = new ForEachStatement.ResultSetForEachTarget(resultSetID); :} push2ContextPath(forEachStatement); final CodeFormatterVisitor thisVisitor = this; // final Expression sqlRerdExpr = forEachStatement.hasSQLRecord() ? forEachStatement.getSQLRecord() : null; // final IntoClause intoClause = forEachStatement.hasIntoClause() ? forEachStatement.getIntoClause() : null; final List stmts = forEachStatement.getStmts(); final Node firstStmt = (stmts != null && !stmts.isEmpty()) ? (Node)stmts.get(0) : null; final SimpleName decVariable = forEachStatement.getVariableDeclarationName(); final Type varDeclType = forEachStatement.getVariableDeclarationType(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { // if(sqlRerdExpr != null && currToken.left == sqlRerdExpr.getOffset()){ // setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FOREACH), // CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); // sqlRerdExpr.accept(thisVisitor); // } // else if(intoClause != null && currToken.left == intoClause.getOffset()){ // setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); // intoClause.accept(thisVisitor); // } // else if(decVariable != null && currToken.left == decVariable.getOffset()) { setGlobalFormattingSettings(-1,getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FOREACH), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); decVariable.accept(thisVisitor); }else if (varDeclType != null && currToken.left == varDeclType.getOffset()) { setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); varDeclType.accept(thisVisitor); }else if(firstStmt != null && currToken.left == firstStmt.getOffset()){ indent(); formatStatements(stmts); unindent(); } else { int numOfBlankLines = -1; boolean addSpace = false; switch(prevToken.sym){ case NodeTypes.FOREACH: addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_FOREACH); break; case NodeTypes.FROM: addSpace = true; break; } switch(currToken.sym){ case NodeTypes.FROM: addSpace = true; break; case NodeTypes.RPAREN: addSpace =getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_FOREACH); break; case NodeTypes.END: numOfBlankLines = 0; addSpace = false; break; } printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(forEachStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(IntoClause intoClause) { // | INTO:into1 expr_plus:exprs1 // {: RESULT = new IntoClause( exprs1, into1left, exprs1right); :} push2ContextPath(intoClause); printStuffBeforeNode(intoClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); List exprs = intoClause.getExpressions(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(exprs, getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_EXPRS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_FOREACH), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_FOREACH)); popContextPath(); return false; } public boolean visit(ContinueStatement continueStatement) { // | CONTINUE:continue1 continueModifierOpt:continueModifier1 SEMI:semi1 // {: RESULT = new ContinueStatement(continueModifier1, continue1left, semi1right); :} push2ContextPath(continueStatement); // continueModifierOpt // ::= // | FOR // {: RESULT = ContinueStatement.ContinueModifier.FOR; :} // | FOREACH // {: RESULT = ContinueStatement.ContinueModifier.FOREACH; :} // | WHILE // {: RESULT = ContinueStatement.ContinueModifier.WHILE; :} // | OPENUI // {: RESULT = ContinueStatement.ContinueModifier.OPENUI; :} // | ID:id1 // {: RESULT = new ContinueStatement.LabelContinueModifier(id1); :} ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; int numOfBlankLines = -1; if(prevToken.sym == NodeTypes.CONTINUE) addSpace = true; if(currToken.sym == NodeTypes.SEMI) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); printToken(prevToken, currToken, numOfBlankLines, addSpace); } }; formatNode(continueStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(ExitStatement exitStatement) { // | EXIT:exit1 exitModifierOpt:exitModifier1 SEMI:semi1 // {: RESULT = new ExitStatement(exitModifier1, exit1left, semi1right); :} // exitModifierOpt // ::= // | PROGRAM // {: RESULT = new ExitStatement.ProgramExitModifier(null); :} // | PROGRAM LPAREN:lparen expr:expr1 RPAREN:rparen // {: RESULT = new ExitStatement.ProgramExitModifier(new ParenthesizedExpression(expr1, lparenleft, rparenright)); :} // | RUNUNIT // {: RESULT = new ExitStatement.RunUnitExitModifier(null); :} // | RUNUNIT LPAREN:lparen expr:expr1 RPAREN:rparen // {: RESULT = new ExitStatement.RunUnitExitModifier(new ParenthesizedExpression(expr1, lparenleft, rparenright)); :} // | STACK simpleNameOpt:simpleName1 // {: RESULT = new ExitStatement.StackExitModifier(simpleName1); :} // | CASE // {: RESULT = ExitStatement.DefaultExitModifier.CASE; :} // | IF // {: RESULT = ExitStatement.DefaultExitModifier.IF; :} // | WHILE // {: RESULT = ExitStatement.DefaultExitModifier.WHILE; :} // | FOR // {: RESULT = ExitStatement.DefaultExitModifier.FOR; :} // | FOREACH // {: RESULT = ExitStatement.DefaultExitModifier.FOREACH; :} // | OPENUI // {: RESULT = ExitStatement.DefaultExitModifier.OPENUI; :} // | ID:id1 // {: RESULT = new ExitStatement.LabelExitModifier(id1); :} push2ContextPath(exitStatement); final CodeFormatterVisitor thisVisitor = this; ExitModifier exitModifier = exitStatement.getExitModifierOpt(); final Expression exitExpr = (exitModifier instanceof OptionalExpressionExitModifier) ? ((OptionalExpressionExitModifier)exitModifier).getExpression() : null; ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { if(exitExpr != null && currToken.left == exitExpr.getOffset()){ setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_EXIT), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); exitExpr.accept(thisVisitor); } else{ int numOfBlankLines = -1; boolean addSpace = false; switch(prevToken.sym){ case NodeTypes.EXIT: case NodeTypes.STACK: addSpace = true; break; } switch(currToken.sym){ case NodeTypes.SEMI: addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); break; } printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(exitStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(UseStatement useStatement) { // ::= USE:use1 name_plus:names1 settingsBlockOpt:settingsBlock1 SEMI:semi1 // {: RESULT = new UseStatement(names1, settingsBlock1, use1left, semi1right); :} // ::= USE:use1 name_plus:names1 SEMI:semi1 // {: RESULT = new UseStatement(names1, null, use1left, semi1right); :} push2ContextPath(useStatement); final CodeFormatterVisitor thisVisitor = this; final List names = useStatement.getNames(); final Name firstName = (names != null && !names.isEmpty()) ? (Name)names.get(0) : null; final SettingsBlock settingsBlock = useStatement.getSettingsBlock(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { if(settingsBlock != null && currToken.left == settingsBlock.getOffset()){ setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(thisVisitor); } else{ boolean addSpace = false; int numOfBlankLines = -1; if(prevToken.sym == NodeTypes.USE) addSpace = true; else if(currToken.sym == NodeTypes.SEMI) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); if(firstName != null && currToken.left == firstName.getOffset()){ setGlobalFormattingSettings(numOfBlankLines, addSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatCommaSeparatedNodeList(names, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_USESTMT), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_USESTMT), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_USESTMT)); } else printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(useStatement, callbackFormatter, 0, false); popContextPath(); return false; } //IO Statements public boolean visit(AddStatement addStatement) { // | ADD:add1 expr_plus:exprs1 addOption_star:addOptions1 SEMI:semi1 // {: RESULT = new AddStatement(exprs1, addOptions1, add1left, semi1right); :} push2ContextPath(addStatement); printStuffBeforeNode(addStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); List exprs = addStatement.getIOObjects(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(exprs); List addOptions = addStatement.getIOClauses(); if(addOptions != null && !addOptions.isEmpty()){ int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); indent(numOfIndents4Wrapping); for(Iterator it=addOptions.iterator(); it.hasNext();){ Node addOption = (Node)it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); addOption.accept(this); } unindent(numOfIndents4Wrapping); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(WithExpressionClause withExpressionClause) { // ::= WITH:with1 inlineSQLStatement:inlineSQLStatement1 // {: RESULT = new WithInlineSQLClause(inlineSQLStatement1, with1left, // inlineSQLStatement1right); :} // inlineSQLStatement // ::= SQLSTMTLIT:sqlStatement // {: RESULT = sqlStatement; :} push2ContextPath(withExpressionClause); // print with printStuffBeforeNode(withExpressionClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = withExpressionClause.getExpression(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); // printStuffBeforeToken( // NodeTypes.SEMI, // -1, // getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(WithInlineSQLClause withInlineSQLClause) { // ::= WITH:with1 inlineSQLStatement:inlineSQLStatement1 // {: RESULT = new WithInlineSQLClause(inlineSQLStatement1, with1left, inlineSQLStatement1right); :} // inlineSQLStatement // ::= SQLSTMTLIT:sqlStatement // {: RESULT = sqlStatement; :} push2ContextPath(withInlineSQLClause); //print with printStuffBeforeNode(withInlineSQLClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); InlineSQLStatement inlineSQLStmt = withInlineSQLClause.getSqlStmt(); printStuffBeforeNode(inlineSQLStmt.getOffset(), -1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); popContextPath(); return false; } public boolean visit(CloseStatement closeStatement) { // | CLOSE:close1 expr:expr1 SEMI:semi1 // {: RESULT = new CloseStatement(expr1, close1left, semi1right); :} push2ContextPath(closeStatement); //print CLOSE printStuffBeforeNode(closeStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = closeStatement.getExpr(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(DeleteStatement deleteStatement) { // | DELETE:delete1 expr:expr1 deleteOption_star:deleteOptions1 SEMI:semi1 // {: RESULT = new DeleteStatement(expr1, deleteOptions1, delete1left, semi1right); :} push2ContextPath(deleteStatement); //print DELETE printStuffBeforeNode(deleteStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = deleteStatement.getTarget(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); List delOptions = new ArrayList(); delOptions.add(deleteStatement.getDataSource()); delOptions.addAll(deleteStatement.getOptions()); if (delOptions != null && !delOptions.isEmpty()) { int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); indent(numOfIndents4Wrapping); for (Iterator it = delOptions.iterator(); it.hasNext();) { Node delOption = (Node) it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); delOption.accept(this); } unindent(numOfIndents4Wrapping); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(FromOrToExpressionClause fromOrToClause) { // | FROM:from1 ID:resultSetID1 // {: RESULT = new FromResultSetClause(resultSetID1, from1left, resultSetID1right); :} push2ContextPath(fromOrToClause); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { int numOfBlankLines = -1; boolean addSpace = false; if(prevToken.sym == NodeTypes.FROM || prevToken.sym == NodeTypes.TO) addSpace = true; printToken(prevToken, currToken, numOfBlankLines, addSpace); } }; formatNode(fromOrToClause, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(NoCursorClause noCursorClause) { // | NOCURSOR:nocursor // {: RESULT = new NoCursorClause(nocursorleft, nocursorright); :} push2ContextPath(noCursorClause); printStuffBeforeNode(noCursorClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(UsingKeysClause usingKeysClause) { // | USINGKEYS:usingkeys1 expr_plus:exprs1 // {: RESULT = new UsingKeysClause(exprs1, usingkeys1left, exprs1right); :} push2ContextPath(usingKeysClause); printStuffBeforeNode(usingKeysClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); List exprs = usingKeysClause.getExpressions(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(exprs); popContextPath(); return false; } public boolean visit(ForwardStatement forwardStatement) { // | FORWARD:forward1 expr_star:exprs1 forwardTargetOpt:forwardTarget1 forwardOption_star:forwardOptions1 SEMI:semi1 // {: RESULT = new ForwardStatement(exprs1, forwardTarget1, forwardOptions1, forward1left, semi1right); :} push2ContextPath(forwardStatement); //print FORWARD printStuffBeforeNode(forwardStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); List exprs = forwardStatement.getArguments(); if(exprs != null && !exprs.isEmpty()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(exprs); } int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); indent(numOfIndents4Wrapping); // forwardTargetOpt // ::= // | TO:to1 expr:expr1 // {: RESULT = new ForwardStatement.DefaultForwardTarget(expr1); :} // | TO:to1 LABEL:label1 expr:expr1 // {: RESULT = new ForwardStatement.ToLabelForwardTarget(expr1); :} // | TO:to1 URL:url1 expr:expr1 // {: RESULT = new ForwardStatement.ToURLForwardTarget(expr1); :} if(forwardStatement.hasForwardTarget()){ printStuffBeforeToken(NodeTypes.TO, -1, true, wrappingPolicy); if(forwardStatement.isForwardToLabel()) printStuffBeforeToken(NodeTypes.LABEL, -1, true); else if(forwardStatement.isForwardToURL()) printStuffBeforeToken(NodeTypes.URL, -1, true); Expression forwardTargetExpr = forwardStatement.getForwardTarget(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); forwardTargetExpr.accept(this); } // forwardOption // ::= RETURNING:returning1 TO name:name1 // {: RESULT = new ReturningToNameClause(name1, returning1left, name1right); :} // | PASSING:passing1 expr:expr1 // {: RESULT = new PassingClause(expr1, passing1left, expr1right); :} List forwardOpts = forwardStatement.getForwardOptions(); if(forwardOpts != null && !forwardOpts.isEmpty()){ for(Iterator it=forwardOpts.iterator(); it.hasNext();){ Node forwardOpt = (Node)it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); forwardOpt.accept(this); } } unindent(numOfIndents4Wrapping); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(ReturningToNameClause returningToNameClause) { // ::= RETURNING:returning1 TO name:name1 // {: RESULT = new ReturningToNameClause(name1, returning1left, name1right); :} push2ContextPath(returningToNameClause); printStuffBeforeNode(returningToNameClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); printStuffBeforeToken(NodeTypes.TO, -1, true); Name name = returningToNameClause.getName(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); name.accept(this); popContextPath(); return false; } public boolean visit(ExecuteStatement executeStatement) { // | EXECUTE:execute1 executeTarget:executeTarget1 executeOption_star:executeOptions1 SEMI:semi1 // {: RESULT = new ExecuteStatement(executeTarget1, executeOptions1, execute1left, semi1right); :} // executeTarget // ::= UPDATE:update1 inlineSQLStatementOpt:inlineSQLStatement1 // {: RESULT = new ExecuteStatement.UpdateExecuteTarget(inlineSQLStatement1, update1left, inlineSQLStatement1 == null ? update1right : inlineSQLStatement1right); :} // | DELETE:delete1 inlineSQLStatementOpt:inlineSQLStatement1 // {: RESULT = new ExecuteStatement.DeleteExecuteTarget(inlineSQLStatement1, delete1left, inlineSQLStatement1 == null ? delete1right : inlineSQLStatement1right); :} // | INSERT:insert1 inlineSQLStatementOpt:inlineSQLStatement1 // {: RESULT = new ExecuteStatement.InsertExecuteTarget(inlineSQLStatement1, insert1left, inlineSQLStatement1 == null ? insert1right : inlineSQLStatement1right); :} // | ID:preparedStmtID // {: RESULT = new ExecuteStatement.PreparedStatementExecuteTarget(preparedStmtID, preparedStmtIDleft, preparedStmtIDright); :} // | inlineSQLStatement:inlineSQLStatement1 // {: RESULT = new ExecuteStatement.DefaultSQLStatementExecuteTarget(inlineSQLStatement1, inlineSQLStatement1left, inlineSQLStatement1right); :} push2ContextPath(executeStatement); final CodeFormatterVisitor thisVisitor = this; final List executeOptions = executeStatement.getExecuteOptions(); final Node firstExeOpt = (executeOptions != null && !executeOptions.isEmpty())? (Node)executeOptions.get(0) : null; final int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); final int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { if(firstExeOpt != null && currToken.left == firstExeOpt.getOffset()){ for(Iterator it=executeOptions.iterator(); it.hasNext();){ Node exeOpt = (Node)it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); exeOpt.accept(thisVisitor); } } else { int numOfBlankLines = -1; boolean addSpace = false; int tokenWrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; switch(prevToken.sym){ case NodeTypes.EXECUTE: case NodeTypes.ID: addSpace = true; indent(numOfIndents4Wrapping); break; case NodeTypes.UPDATE: case NodeTypes.DELETE: case NodeTypes.INSERT: addSpace = true; break; } if(currToken.sym == NodeTypes.SQLSTMTLIT) tokenWrappingPolicy = wrappingPolicy; else if(currToken.sym == NodeTypes.SEMI){ unindent(numOfIndents4Wrapping); addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); } printToken(prevToken, currToken, numOfBlankLines, addSpace, tokenWrappingPolicy); } } }; formatNode(executeStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(UsingClause usingClause) { // ::= USING:using1 expr_plus:exprs1 // {: RESULT = new UsingClause(exprs1, using1left, exprs1right); :} push2ContextPath(usingClause); printStuffBeforeNode(usingClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); List exprs = usingClause.getExpressions(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(exprs); popContextPath(); return false; } public boolean visit(ForExpressionClause forExpressionClause) { // | FOR:for1 expr:expr1 // {: RESULT = new ForExpressionClause(expr1, for1left, expr1right); :} push2ContextPath(forExpressionClause); printStuffBeforeNode(forExpressionClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = forExpressionClause.getExpression(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); popContextPath(); return false; } public boolean visit(GetByKeyStatement getByKeyStatement) { // | GET:get1 expr_star:exprs1 getByKeyOption_star:getByKeyOptions1 SEMI:semi1 // {: RESULT = new GetByKeyStatement(exprs1, getByKeyOptions1, get1left, semi1right); :} push2ContextPath(getByKeyStatement); //print GET printStuffBeforeNode(getByKeyStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); List exprs = getByKeyStatement.getTargets(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(exprs); final int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); final int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); indent(numOfIndents4Wrapping); List getbyKeyOpts = getByKeyStatement.getGetByKeyOptions(); if(getbyKeyOpts != null && !getbyKeyOpts.isEmpty()){ for(Iterator it=getbyKeyOpts.iterator(); it.hasNext();){ Node getbyKeyOpt = (Node)it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); getbyKeyOpt.accept(this); } } unindent(numOfIndents4Wrapping); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(ForUpdateClause forUpdateClause) { // ::= FORUPDATE:forupdate1 IDOpt:ID1 // {: RESULT = new ForUpdateWithIDClause(ID1, forupdate1left, ID1right); :} push2ContextPath(forUpdateClause); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { int numOfBlankLines = -1; boolean addSpace = false; if(prevToken.sym == NodeTypes.FORUPDATE) addSpace = true; printToken(prevToken, currToken, numOfBlankLines, addSpace); } }; formatNode(forUpdateClause, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(SingleRowClause singleRowClause) { // | SINGLEROW:singlerow1 // {: RESULT = new SingleRowClause(singlerow1left, singlerow1right); :} push2ContextPath(singleRowClause); printStuffBeforeNode(singleRowClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(WithIDClause withIDClause) { // | WITH:with1 ID:preparedStmtID // {: RESULT = new WithIDClause(preparedStmtID, with1left, preparedStmtIDright); :} push2ContextPath(withIDClause); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { int numOfBlankLines = -1; boolean addSpace = false; if(prevToken.sym == NodeTypes.WITH) addSpace = true; printToken(prevToken, currToken, numOfBlankLines, addSpace); } }; formatNode(withIDClause, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(GetByPositionStatement getByPositionStatement) { // | GET:get1 direction:direction1 inparentOpt:inparent1 getByPositionSource:getByPositionSource1 getByPositionOption_star:getByPositionOptions1 SEMI:semi1 // {: RESULT = new GetByPositionStatement(direction1, inparent1, getByPositionSource1, getByPositionOptions1, get1left, semi1right); :} // direction // ::= NEXT // {: RESULT = GetByPositionStatement.DefaultDirection.NEXT; :} // | PREVIOUS // {: RESULT = GetByPositionStatement.DefaultDirection.PREVIOUS; :} // | FIRST // {: RESULT = GetByPositionStatement.DefaultDirection.FIRST; :} // | LAST // {: RESULT = GetByPositionStatement.DefaultDirection.LAST; :} // | CURRENT // {: RESULT = GetByPositionStatement.DefaultDirection.CURRENT; :} // | RELATIVE LPAREN expr:expr1 RPAREN // {: RESULT = new GetByPositionStatement.RelativeDirection(expr1); :} // | ABSOLUTE LPAREN expr:expr1 RPAREN // {: RESULT = new GetByPositionStatement.AbsoluteDirection(expr1); :} // inparentOpt // ::= // {: RESULT = Boolean.FALSE; :} // | INPARENT:inparent1 // {: RESULT = Boolean.TRUE; :} // getByPositionSource // ::= expr_plus:exprs1 // {: RESULT = new GetByPositionStatement.ExpressionListSource(exprs1); :} // | FROM ID:resultSetID // {: RESULT = new GetByPositionStatement.FromResultSetSource(resultSetID); :} // | expr:expr1 FROM ID:resultSetID // {: RESULT = new GetByPositionStatement.ExpressionFromResultSetSource(expr1, resultSetID); :} // ; push2ContextPath(getByPositionStatement); final CodeFormatterVisitor thisVisitor = this; final int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); final int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); final Expression exprDirection = getByPositionStatement.getPosition(); final List exprSources = getByPositionStatement.getTargetRecords(); final Node firstExprSource = (exprSources != null && !exprSources.isEmpty()) ? (Node)exprSources.get(0) : null; final List getbyPosOpts = getByPositionStatement.getGetByPositionOptions(); final Node firstGetByPosOpt = (getbyPosOpts != null && !getbyPosOpts.isEmpty()) ? (Node)getbyPosOpts.get(0) : null; final boolean[] hasIndented = new boolean[]{false}; ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { if(exprDirection != null && currToken.left == exprDirection.getOffset()){ setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_GETBYPOS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); exprDirection.accept(thisVisitor); } else if(firstExprSource != null && currToken.left == firstExprSource.getOffset()){ if(!hasIndented[0]){ //condition should always be true, the check is redundant, just a safety net indent(numOfIndents4Wrapping); //indentA hasIndented[0] = true; } setGlobalFormattingSettings(-1, true, wrappingPolicy); formatExpressions(exprSources); } else if(firstGetByPosOpt != null && currToken.left == firstGetByPosOpt.getOffset()){ for(Iterator it=getbyPosOpts.iterator(); it.hasNext();){ Node getByPosOpt = (Node)it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); getByPosOpt.accept(thisVisitor); } } else { int numOfBlankLines = -1; boolean addSpace = false; int tokenWrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; switch(prevToken.sym){ case NodeTypes.GET: case NodeTypes.FROM: addSpace = true; break; case NodeTypes.RELATIVE: case NodeTypes.ABSOLUTE: addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_GETBYPOS); break; } if(currToken.sym == NodeTypes.RPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_GETBYPOS); else if(currToken.sym == NodeTypes.INPARENT) addSpace = true; else if(currToken.sym == NodeTypes.FROM){ addSpace = true; if(firstExprSource == null){ //only set for - FROM ID:resultSetID if(!hasIndented[0]){ //condition should always be true, the check is redundant, just a safety net indent(numOfIndents4Wrapping); //also indentA hasIndented[0] = true; } tokenWrappingPolicy = wrappingPolicy; } } else if(currToken.sym == NodeTypes.SEMI){ if(hasIndented[0]) //condition should always be true, the check is redundant, just a safety net unindent(numOfIndents4Wrapping); //match indentA addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); } printToken(prevToken, currToken, numOfBlankLines, addSpace, tokenWrappingPolicy); } } }; formatNode(getByPositionStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(OpenStatement openStatement) { // | OPEN:open1 ID:resultSetID openModifierOpt:openModifier1 openTarget_star:openTargets1 SEMI:semi1 // {: RESULT = new OpenStatement(resultSetID, openModifier1, openTargets1, open1left, semi1right); :} // openModifierOpt // ::= // {: RESULT = new Boolean[] { Boolean.FALSE, Boolean.FALSE }; :} // | HOLD // {: RESULT = new Boolean[] { Boolean.TRUE, Boolean.FALSE }; :} // | SCROLL // {: RESULT = new Boolean[] { Boolean.FALSE, Boolean.TRUE }; :} // | HOLD SCROLL // {: RESULT = new Boolean[] { Boolean.TRUE, Boolean.TRUE }; :} // | SCROLL HOLD // {: RESULT = new Boolean[] { Boolean.TRUE, Boolean.TRUE }; :} push2ContextPath(openStatement); final CodeFormatterVisitor thisVisitor = this; final int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); final int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); final List openTargets = openStatement.getOpenTargets(); final Node firstOpenTarget = (openTargets != null && !openTargets.isEmpty()) ? (Node)openTargets.get(0) : null; ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { if(firstOpenTarget != null && currToken.left == firstOpenTarget.getOffset()){ indent(numOfIndents4Wrapping); for(Iterator it=openTargets.iterator(); it.hasNext();){ Node openTarget = (Node)it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); openTarget.accept(thisVisitor); } unindent(numOfIndents4Wrapping); } else { int numOfBlankLines = -1; boolean addSpace = false; switch(prevToken.sym){ case NodeTypes.OPEN: addSpace = true; break; } switch(currToken.sym){ case NodeTypes.HOLD: case NodeTypes.SCROLL: addSpace = true; break; case NodeTypes.SEMI: addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT); break; } printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(openStatement, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(PrepareStatement prepareStatement) { // | PREPARE:prepare1 ID:preparedStmtID prepareOption_star:prepareOptions1 SEMI:semi1 // {: RESULT = new PrepareStatement(preparedStmtID, prepareOptions1, prepare1left, semi1right); :} push2ContextPath(prepareStatement); // print PREPARE printStuffBeforeNode(prepareStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); setGlobalFormattingSettings(-1, true, wrappingPolicy); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); if ( prepareStatement.getSqlStmt() != null ) { prepareStatement.getSqlStmt().accept(this); } if ( prepareStatement.getDataSource() != null ) { prepareStatement.getDataSource().accept(this); } if ( prepareStatement.getWithClause() != null ) { prepareStatement.getWithClause().accept(this); } unindent(numOfIndents4Wrapping); printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(FromExpressionClause fromExpressionClause) { // ::= FROM:from1 expr:expr1 // {: RESULT = new FromExpressionClause(expr1, from1left, expr1right); :} push2ContextPath(fromExpressionClause); printStuffBeforeNode(fromExpressionClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = fromExpressionClause.getExpression(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); popContextPath(); return false; } public boolean visit(ReplaceStatement replaceStatement) { // | REPLACE:replace1 expr:expr1 replaceOption_star:replaceOptions1 SEMI:semi1 // {: RESULT = new ReplaceStatement(expr1, replaceOptions1, replace1left, semi1right); :} push2ContextPath(replaceStatement); printStuffBeforeNode(replaceStatement.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = replaceStatement.getRecord(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_IOSTMT); List replaceOpts = replaceStatement.getReplaceOptions(); if(replaceOpts != null && !replaceOpts.isEmpty()){ indent(numOfIndents4Wrapping); for(Iterator it=replaceOpts.iterator(); it.hasNext();){ Node replaceOpt = (Node)it.next(); setGlobalFormattingSettings(-1, true, wrappingPolicy); replaceOpt.accept(this); } unindent(numOfIndents4Wrapping); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } public boolean visit(ReturningToInvocationTargetClause returningToInvocationTargetClause) { // ::= RETURNING:returning1 TO name:expr1 // {: RESULT = new ReturningToInvocationTargetClause(expr1, returning1left, expr1right); :} // | RETURNING:returning1 TO primaryNoNew:expr1 // {: RESULT = new ReturningToInvocationTargetClause(expr1, returning1left, expr1right); :} push2ContextPath(returningToInvocationTargetClause); printStuffBeforeNode(returningToInvocationTargetClause.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); printStuffBeforeToken(NodeTypes.TO, -1, true); Expression expr = returningToInvocationTargetClause.getExpression(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); popContextPath(); return false; } public boolean visit(ClassDataDeclaration classDataDeclaration) { // | privateAccessModifierOpt:privateAccessModifier1 ID_plus:IDs1 type:type1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // Variable Declaration // {: RESULT = new ClassDataDeclaration(privateAccessModifier1, Boolean.FALSE, IDs1, type1, settingsBlock1, initializer1, false, privateAccessModifier1 == Boolean.FALSE ? IDs1left : privateAccessModifier1left, semi1right); :} // | privateAccessModifierOpt:privateAccessModifier1 CONST:const1 ID_plus:IDs1 type:type1 settingsBlockOpt:settingsBlock1 ASSIGN expr:expr1 SEMI:semi1 // constant // {: RESULT = new ClassDataDeclaration(privateAccessModifier1, Boolean.FALSE, IDs1, type1, settingsBlock1, expr1, true, privateAccessModifier1 == Boolean.FALSE ? const1left : privateAccessModifier1left, semi1right); :} // | privateAccessModifierOpt:privateAccessModifier1 staticAccessModifierOpt:staticAccessModifier1 ID_plus:IDs1 type:type1 settingsBlockOpt:settingsBlock1 initializerOpt:initializer1 SEMI:semi1 // Variable Declaration // {: RESULT = new ClassDataDeclaration(privateAccessModifier1, staticAccessModifier1, IDs1, type1, settingsBlock1, initializer1, false, privateAccessModifier1 == Boolean.FALSE ? IDs1left : privateAccessModifier1left, semi1right); :} push2ContextPath(classDataDeclaration); final List names = classDataDeclaration.getNames(); final Type type = classDataDeclaration.getType(); final SettingsBlock settingsBlock = classDataDeclaration.getSettingsBlockOpt(); final Expression initExpr = classDataDeclaration.getInitializer(); //can not use the formatNode() callbackFormatter style here, because PRIVATE, CONST, STATIC is all optional, //the classDataDeclaration could start with ID_plus boolean addSpace = false; int numOfBlankLines = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_BEFORE_PARTDATADECL); if(classDataDeclaration.isPrivate()){ //print PRIVATE printStuffBeforeNode(classDataDeclaration.getOffset(), numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } if(classDataDeclaration.isStatic()){ printStuffBeforeToken(NodeTypes.STATIC, numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } if(classDataDeclaration.isConstant()){ printStuffBeforeToken(NodeTypes.CONST, numOfBlankLines, addSpace); addSpace = true; numOfBlankLines = -1; } setGlobalFormattingSettings(numOfBlankLines, addSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatCommaSeparatedNodeList(names, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_DATADECL), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_DATADECL), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_VAR_DELC)); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); type.accept(this); //I decided not to put space before ? if (classDataDeclaration.isNullable()) { printStuffBeforeToken(NodeTypes.QUESTION, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_QUESTION_FIELDS)); } if(settingsBlock != null){ setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(this); } if(initExpr != null){ printStuffBeforeToken(NodeTypes.ASSIGN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_ASSIGNMENT)); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_OP_ASSIGNMENT), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_INITEXPR)); int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); initExpr.accept(this); unindent(numOfIndents4Wrapping); } printStuffBeforeToken(NodeTypes.SEMI, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_SEMI_STMT)); popContextPath(); return false; } private void formatCommaSeparatedNodeList(List nodes, boolean addSpaceBeforeCommaPref, boolean addSpaceAfterCommaPref, int wrappingPolicyFrom2ndName){ boolean isFirstName = true; int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); boolean hasIndented4Wrap = false; for(Iterator it=nodes.iterator(); it.hasNext();){ Node node = (Node)it.next(); if(isFirstName){ //the first name's global setting should be set by the caller of the formatNames() function, //in other words, caller decide if there will be new line, space being put in front of the 1st ID //but we do not wrap the 1st nmae setGlobalFormattingSettings(fGlobalNumOfBlankLines, fGlobalAddSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); } else{ if(!hasIndented4Wrap){ //we want to set the indentation from the 2nd name, because sometimes NameList can be a beginning of a line //i.e. classDataDeclaration: a, b, c int; //we do not want to have extra indentation before 'a' indent(numOfIndents4Wrapping); hasIndented4Wrap = true; } printStuffBeforeToken(NodeTypes.COMMA, -1, addSpaceBeforeCommaPref); setGlobalFormattingSettings(-1, !isFirstName && addSpaceAfterCommaPref, wrappingPolicyFrom2ndName); } node.accept(this); isFirstName = false; } if(hasIndented4Wrap) unindent(numOfIndents4Wrapping); } private void formatParameters(List parameters, boolean addSpaceAfterLParen){ formatParameters(parameters, addSpaceAfterLParen, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_FUNCPARAMS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_FUNCPARAMS)); } private void formatParameters(List parameters, boolean addSpaceAfterLParen, boolean addSpaceBeforeComma, boolean addSpaceAfterComma){ boolean isFirstParameter = true; int wrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); if(parameters != null){ for(Iterator it=parameters.iterator(); it.hasNext();){ //print comma if there are more than one parameters if(!isFirstParameter){ printStuffBeforeToken(NodeTypes.COMMA, -1, addSpaceBeforeComma); } Parameter param = (Parameter)it.next(); if(!isFirstParameter){ wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_PARAMS); } boolean addSpace = isFirstParameter ? addSpaceAfterLParen : addSpaceAfterComma; setGlobalFormattingSettings(-1, addSpace, wrappingPolicy); param.accept(this); isFirstParameter = false; } } unindent(numOfIndents4Wrapping); } public boolean visit(final FunctionParameter functionParameter) { push2ContextPath(functionParameter); final CodeFormatterVisitor thisVisitor = this; final Type paramType = functionParameter.getType(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { //resetCurrentWrappingPolicy(); boolean addSpace = false; if(currToken.left == paramType.getOffset()){ setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); paramType.accept(thisVisitor); //I decided not to put space before ? if (functionParameter.isNullable()) { printStuffBeforeToken(NodeTypes.QUESTION, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_QUESTION_PARMS)); } } else{ switch(currToken.sym){ case NodeTypes.IN: case NodeTypes.INOUT: case NodeTypes.OUT: case NodeTypes.CONST: addSpace = true; break; default: addSpace = false; break; } printToken(prevToken, currToken, -1, addSpace); } } }; formatNode(functionParameter, callbackFormatter, fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(ArrayType arrayType) { push2ContextPath(arrayType); Type arrayElemType = arrayType.getElementType(); arrayElemType.accept(this); //I decided no new line [ printStuffBeforeToken(NodeTypes.LBRACKET, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LBRACKET_ARRAY)); Expression initialSize = arrayType.getInitialSize(); if(initialSize != null){ setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LBRACKET_ARRAY), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); initialSize.accept(this); } printStuffBeforeToken(NodeTypes.RBRACKET, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RBRACKET_ARRAY)); popContextPath(); return false; } //primaryNoNew public boolean visit(ParenthesizedExpression parenthesizedExpression) { // ::= LPAREN:lparen1 expr:expr1 RPAREN:rparen1 // {: RESULT = new ParenthesizedExpression(expr1, lparen1left, rparen1right); :} push2ContextPath(parenthesizedExpression); final int BEFORE_LPAREN = 0; final int AFTER_LPAREN = 1; final int BEFORE_RPAREN = 2; final CodeFormatterVisitor thisVisitor = this; final boolean[] addSpaces = new boolean[]{getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_PARENTEXPR), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_PARENTEXPR), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_PARENTEXPR)}; //special cases, we want to use different space preference for different statement Node parentNode = parenthesizedExpression.getParent(); if(parentNode instanceof ReturnStatement){ addSpaces[BEFORE_LPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_RETURN); addSpaces[AFTER_LPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_RETURN); addSpaces[BEFORE_RPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_RETURN); } else if(parentNode instanceof CaseStatement){ addSpaces[BEFORE_LPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_CASE); addSpaces[AFTER_LPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_CASE); addSpaces[BEFORE_RPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_CASE); } else if(parentNode instanceof ExitStatement){ addSpaces[BEFORE_LPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_EXIT); addSpaces[AFTER_LPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_EXIT); addSpaces[BEFORE_RPAREN] = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_EXIT); } final Expression expr = parenthesizedExpression.getExpression(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; int numOfBlankLines = -1; if(currToken.left == expr.getOffset()){ //print expressions setGlobalFormattingSettings(fGlobalNumOfBlankLines, addSpaces[AFTER_LPAREN], fCurrentWrappingPolicy); expr.accept(thisVisitor); } else{ if(currToken.sym == NodeTypes.RPAREN) addSpace = addSpaces[BEFORE_RPAREN]; printToken(prevToken, currToken, numOfBlankLines, addSpace); } } }; formatNode(parenthesizedExpression, callbackFormatter, fGlobalNumOfBlankLines, addSpaces[BEFORE_LPAREN], fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(SuperExpression superExpression) {return visitTerminalExpression(superExpression);} public boolean visit(ThisExpression thisExpression) {return visitTerminalExpression(thisExpression);} //literal public boolean visit(IntegerLiteral integerLiteral) {return visitTerminalExpression(integerLiteral);} public boolean visit(DecimalLiteral decimalLiteral) {return visitTerminalExpression(decimalLiteral);} public boolean visit(FloatLiteral floatLiteral) {return visitTerminalExpression(floatLiteral);} public boolean visit(StringLiteral stringLiteral) {return visitTerminalExpression(stringLiteral);} public boolean visit(BooleanLiteral booleanLiteral) {return visitTerminalExpression(booleanLiteral);} public boolean visit(NullLiteral nullLiteral) {return visitTerminalExpression(nullLiteral);} public boolean visit(SQLLiteral sQLLiteral) {return visitTerminalExpression(sQLLiteral);} public boolean visit(BytesLiteral bytesLiteral) {return visitTerminalExpression(bytesLiteral);} private boolean visitTerminalExpression(Expression literalExpression){ // if(!fGlobalAddSpace) // fGlobalAddSpace = !fIsFirstExpr; return visitTerminalNode(literalExpression); } public boolean visit(ArrayLiteral arrayLiteral) { // | LBRACKET:lbracket1 expr_star:exprs1 RBRACKET:rbracket1 // {: RESULT = new ArrayLiteral(exprs1, lbracket1left, rbracket1right); :} push2ContextPath(arrayLiteral); printStuffBeforeToken(NodeTypes.LBRACKET, fGlobalNumOfBlankLines, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LBRACKET_ARRAY), fCurrentWrappingPolicy); int wrappingPolicy = CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP; final List exprs = arrayLiteral.getExpressions(); if(exprs != null && !exprs.isEmpty()){ if(exprs.size() > 1 || getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_ARRAY) != CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOCHANGE) wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_ARRAY); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LBRACKET_ARRAY), wrappingPolicy); formatExpressions(exprs, wrappingPolicy, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_ARRAY), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_ARRAY)); } //if there is no expression, do not wrap the closing bracket //if there is one expression, do not wrap the closing bracket, unless user wrapping policy is do not change printStuffBeforeToken(NodeTypes.RBRACKET, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RBRACKET_ARRAY), wrappingPolicy); popContextPath(); return false; } public boolean visit(ArrayAccess arrayAccess) { // ::= primary:primary1 LBRACKET expr_plus:expr1 RBRACKET:rbracket1 // {: RESULT = new ArrayAccess(primary1, expr1, primary1left, rbracket1right); :} // | name:name1 LBRACKET expr_plus:expr1 RBRACKET:rbracket1 // {: RESULT = new ArrayAccess(name1, expr1, name1left, rbracket1right); :} push2ContextPath(arrayAccess); Expression primaryOrName = arrayAccess.getArray(); primaryOrName.accept(this); printStuffBeforeToken(NodeTypes.LBRACKET, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LBRACKET_ARRAY)); List exprs = arrayAccess.getIndices(); int wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_ARRAY); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LBRACKET_ARRAY), wrappingPolicy); formatExpressions(exprs, wrappingPolicy, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_ARRAY), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_ARRAY)); printStuffBeforeToken(NodeTypes.RBRACKET, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RBRACKET_ARRAY)); popContextPath(); return false; } public boolean visit(SubstringAccess substringAccess) { // | primary:primary1 LBRACKET expr:expr1 COLON expr:expr2 RBRACKET:rbracket1 // {: RESULT = new SubstringAccess(primary1, expr1, expr2, primary1left, rbracket1right); :} // | name:name1 LBRACKET expr:expr1 COLON expr:expr2 RBRACKET:rbracket1 // {: RESULT = new SubstringAccess(name1, expr1, expr2, name1left, rbracket1right); :} push2ContextPath(substringAccess); Expression primaryOrName = substringAccess.getPrimary(); primaryOrName.accept(this); printStuffBeforeToken(NodeTypes.LBRACKET, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LBRACKET_ARRAY)); Expression expr1 = substringAccess.getExpr(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LBRACKET_ARRAY), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr1.accept(this); printStuffBeforeToken(NodeTypes.COLON, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COLON_SUBSTRING)); Expression expr2 = substringAccess.getExpr2(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COLON_SUBSTRING), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr2.accept(this); printStuffBeforeToken(NodeTypes.RBRACKET, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RBRACKET_ARRAY)); popContextPath(); return false; } public boolean visit(FieldAccess fieldAccess) { // ::= primary:primary1 DOT ID:id1 // {: RESULT = new FieldAccess(primary1, id1, primary1left, id1right); :} push2ContextPath(fieldAccess); Expression primaryOrName = fieldAccess.getPrimary(); primaryOrName.accept(this); printStuffBeforeToken(NodeTypes.DOT, -1, false); printStuffBeforeToken(NodeTypes.ID, -1, false); popContextPath(); return false; } public boolean visit(FunctionInvocation functionInvocation) { // ::= name:target1 LPAREN expr_star:funcArgs1 RPAREN:rparen1 // {: RESULT = new FunctionInvocation(target1, funcArgs1, target1left, rparen1right); :} // | primaryNoNew:target1 LPAREN expr_star:funcArgs1 RPAREN:rparen1 // {: RESULT = new FunctionInvocation(target1, funcArgs1, target1left, rparen1right); :} push2ContextPath(functionInvocation); Expression targetExpr = functionInvocation.getTarget(); targetExpr.accept(this); printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_FUNCINVOC)); List args = functionInvocation.getArguments(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_FUNCINVOC), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(args, getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_ARGS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_FUNCINVOC), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_FUNCINVOC)); printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_FUNCINVOC)); popContextPath(); return false; } public boolean visit(AnnotationExpression annotationExpression) { // | AT:at1 name:name1 // {: RESULT = new AnnotationExpression(name1, at1left, name1right); :} push2ContextPath(annotationExpression); //print AT printStuffBeforeNode(annotationExpression.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Name annotationName = annotationExpression.getName(); setGlobalFormattingSettings(-1, false, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); annotationName.accept(this); popContextPath(); return false; } public boolean visit(NewExpression newExpression) { // | NEW:new1 typeNoName:type1 settingsBlockOpt:settingsBlock1 // {: RESULT = new NewExpression(type1, null, settingsBlock1, new1left, settingsBlock1right); :} // | NEW:new1 namedType:type1 settingsBlockOpt:settingsBlock1 // {: RESULT = new NewExpression(type1, null, settingsBlock1, new1left, settingsBlock1right); :} // | NEW:new1 namedType:type1 LPAREN expr_star:funcArgs RPAREN settingsBlockOpt:settingsBlock1 // {: RESULT = new NewExpression(type1, funcArgs, settingsBlock1, new1left, settingsBlock1right); :} push2ContextPath(newExpression); //print NEW printStuffBeforeNode(newExpression.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Type type = newExpression.getType(); setGlobalFormattingSettings(-1, true, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); type.accept(this); SettingsBlock settingsBlock = newExpression.getSettingsBlock(); if(settingsBlock != null){ setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(this); } popContextPath(); return false; } public boolean visit(SetValuesExpression setValuesExpression) { // | primary:primary1 settingsBlock:settingsBlock1 // {: RESULT = new SetValuesExpression(primary1, settingsBlock1, primary1left, settingsBlock1right); :} // | name:name1 settingsBlock:settingsBlock1 // {: RESULT = new SetValuesExpression(name1, settingsBlock1, name1left, settingsBlock1right); :} push2ContextPath(setValuesExpression); Expression primaryOrName = setValuesExpression.getExpression(); primaryOrName.accept(this); SettingsBlock settingsBlock = setValuesExpression.getSettingsBlock(); setGlobalFormattingSettings(getNumOfBlankLinesBeforeCurlyBrace(), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LCURLY_SETTINGS), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); settingsBlock.accept(this); popContextPath(); return false; } public boolean visit(TypeLiteralExpression typeLiteralExpression) { // | PRIMITIVE:prim1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new NoSpecPrimitiveType(prim1, prim1left, prim1right), prim1left, typeKeywordright); :} // | NUMERICPRIMITIVE:numericprimitive1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new NumericSpecPrimitiveType(numericprimitive1, null, numericprimitive1left, numericprimitive1right), numericprimitive1left, typeKeywordright); :} // | CHARPRIMITIVE:charprimitive1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new CharacterSpecPrimitiveType(charprimitive1, null, charprimitive1left, charprimitive1right), charprimitive1left, typeKeywordright); :} // | TIMESTAMPINTERVALPRIMITIVE:timestampintervalprimitive1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new TimestampIntervalSpecPrimitiveType(timestampintervalprimitive1, null, timestampintervalprimitive1left, timestampintervalprimitive1right), timestampintervalprimitive1left, typeKeywordright); :} // | PRIMITIVE:prim1 LBRACKET RBRACKET:rbracket1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new ArrayType(new NoSpecPrimitiveType(prim1, prim1left, prim1right), null, prim1left, rbracket1right), prim1left, typeKeywordright); :} // | NUMERICPRIMITIVE:prim1 LBRACKET RBRACKET:rbracket1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new ArrayType(new NumericSpecPrimitiveType(prim1, null, prim1left, prim1right), null, prim1left, rbracket1right), prim1left, typeKeywordright); :} // | CHARPRIMITIVE:prim1 LBRACKET RBRACKET:rbracket1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new ArrayType(new CharacterSpecPrimitiveType(prim1, null, prim1left, prim1right), null, prim1left, rbracket1right), prim1left, typeKeywordright); :} // | TIMESTAMPINTERVALPRIMITIVE:prim1 LBRACKET RBRACKET:rbracket1 DOT TYPE:typeKeyword // {: RESULT = new TypeLiteralExpression(new ArrayType(new TimestampIntervalSpecPrimitiveType(prim1, null, prim1left, prim1right), null, prim1left, rbracket1right), prim1left, typeKeywordright); :} push2ContextPath(typeLiteralExpression); Type type = typeLiteralExpression.getType(); type.accept(this); printStuffBeforeToken(NodeTypes.DOT, -1, false); printStuffBeforeToken(NodeTypes.TYPE, -1, false); popContextPath(); return false; } public boolean visit(UnaryExpression unaryExpression) { // ::= PLUS:plus1 expr:expr1 // {: RESULT = new UnaryExpression(UnaryExpression.Operator.PLUS, expr1, plus1left, expr1right); :} %prec UPLUS // | MINUS:minus1 expr:expr1 // {: RESULT = new UnaryExpression(UnaryExpression.Operator.MINUS, expr1, minus1left, expr1right); :} %prec UMINUS // | BANG:bang1 expr:expr1 // {: RESULT = new UnaryExpression(UnaryExpression.Operator.BANG, expr1, bang1left, expr1right); :} push2ContextPath(unaryExpression); printStuffBeforeNode(unaryExpression.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); Expression expr = unaryExpression.getExpression(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_OP_UNARY), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); expr.accept(this); popContextPath(); return false; } public boolean visit(BinaryExpression binaryExpression) { push2ContextPath(binaryExpression); Expression firstExpr = binaryExpression.getFirstExpression(); firstExpr.accept(this); int numOfBlankLines = -1; boolean addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_BINARY); BinaryExpression.Operator binaryOp = binaryExpression.getOperator(); if(binaryOp == BinaryExpression.Operator.PLUS) printStuffBeforeToken(NodeTypes.PLUS, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.MINUS) printStuffBeforeToken(NodeTypes.MINUS, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.TIMES) printStuffBeforeToken(NodeTypes.TIMES, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.DIVIDE) printStuffBeforeToken(NodeTypes.DIV, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.MODULO) printStuffBeforeToken(NodeTypes.MODULO, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.TIMESTIMES) printStuffBeforeToken(NodeTypes.TIMESTIMES, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.CONCAT) printStuffBeforeToken(NodeTypes.CONCAT, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.NULLCONCAT) printStuffBeforeToken(NodeTypes.NULLCONCAT, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.OR) printStuffBeforeToken(NodeTypes.OR, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.AND) printStuffBeforeToken(NodeTypes.AND, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.BITAND) printStuffBeforeToken(NodeTypes.BITAND, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.BITOR) printStuffBeforeToken(NodeTypes.BITOR, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.XOR) printStuffBeforeToken(NodeTypes.XOR, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.EQUALS) printStuffBeforeToken(NodeTypes.EQ, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.NOT_EQUALS) printStuffBeforeToken(NodeTypes.NE, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.LESS) printStuffBeforeToken(NodeTypes.LT, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.GREATER) printStuffBeforeToken(NodeTypes.GT, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.LESS_EQUALS) printStuffBeforeToken(NodeTypes.LE, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.GREATER_EQUALS) printStuffBeforeToken(NodeTypes.GE, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.LEFT_SHIFT) printStuffBeforeToken(NodeTypes.LEFTSHIFT, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.RIGHT_SHIFT_ARITHMETIC) printStuffBeforeToken(NodeTypes.RIGHTSHIFTARITHMETIC, numOfBlankLines, addSpace); else if(binaryOp == BinaryExpression.Operator.RIGHT_SHIFT_LOGICAL) printStuffBeforeToken(NodeTypes.RIGHTSHIFTLOGICAL, numOfBlankLines, addSpace); Expression secondExpr = binaryExpression.getSecondExpression(); format2ndExpressionInBinaryExpression(secondExpr) ; popContextPath(); return false; } /** * helper method, common code shared for all the binary style expression * * @param secondExpr */ private void format2ndExpressionInBinaryExpression(Node secondExpr) { int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); indent(numOfIndents4Wrapping); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_OP_BINARY), getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_BINARYEXPR)); secondExpr.accept(this); unindent(numOfIndents4Wrapping); } public boolean visit(IsAExpression isAExpression) { // | expr:expr1 ISA type:type1 // {: RESULT = new IsAExpression(expr1, type1, expr1left, type1right); :} push2ContextPath(isAExpression); Expression expr = isAExpression.getExpression(); expr.accept(this); printStuffBeforeToken(NodeTypes.ISA, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_BINARY)); Type type = isAExpression.getType(); format2ndExpressionInBinaryExpression(type); popContextPath(); return false; } public boolean visit(AsExpression asExpression) { // | expr:expr1 AS type:type1 // {: RESULT = new AsExpression(expr1, type1, expr1left, type1right); :} // | expr:expr1 AS STRING:stringLiteral // {: RESULT = new AsExpression(expr1, stringLiteral, expr1left, stringLiteralright); :} push2ContextPath(asExpression); Expression expr = asExpression.getExpression(); expr.accept(this); printStuffBeforeToken(NodeTypes.AS, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_BINARY)); if(asExpression.hasType()){ Type type = asExpression.getType(); format2ndExpressionInBinaryExpression(type); } else if(asExpression.hasStringLiteral()){ Expression stringLiteralExpr = asExpression.getStringLiteral(); format2ndExpressionInBinaryExpression(stringLiteralExpr); } popContextPath(); return false; } public boolean visit(IsNotExpression isNotExpression) { // | expr:expr1 IS expr:expr2 // {: RESULT = new IsNotExpression(IsNotExpression.Operator.IS, expr1, expr2, expr1left, expr2right); :} // | expr:expr1 NOT expr:expr2 // {: RESULT = new IsNotExpression(IsNotExpression.Operator.NOT, expr1, expr2, expr1left, expr2right); :} push2ContextPath(isNotExpression); Expression firstExpr = isNotExpression.getFirstExpression(); firstExpr.accept(this); IsNotExpression.Operator isNotOp = isNotExpression.getOperator(); if(isNotOp == IsNotExpression.Operator.IS) printStuffBeforeToken(NodeTypes.IS, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_BINARY)); else if(isNotOp == IsNotExpression.Operator.NOT) printStuffBeforeToken(NodeTypes.NOT, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_OP_BINARY)); Expression secondExpr = isNotExpression.getSecondExpression(); format2ndExpressionInBinaryExpression(secondExpr); popContextPath(); return false; } private void formatExpressions(List exprs){ formatExpressions(exprs, getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_EXPRS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_EXPRS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_EXPRS)); } private void formatExpressions(List exprs, int wrappingPolicy, boolean addSpaceBeforeComma, boolean addSpaceAfterComma){ boolean isFirstExpr = true; int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); boolean indentedWrap = false; if(fGlobalNumOfBlankLines < 0){ indent(numOfIndents4Wrapping); indentedWrap = true; } if(exprs!= null){ int cnt = exprs.size(); //if there is only one expression and user did not specify no change, then we do not want to wrap if((cnt == 1) && (wrappingPolicy != CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOCHANGE)) setGlobalFormattingSettings(fGlobalNumOfBlankLines, fGlobalAddSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); for(Iterator it=exprs.iterator(); it.hasNext();){ //print comma if there are more than one expressions if(!isFirstExpr){ printStuffBeforeToken(NodeTypes.COMMA, -1, addSpaceBeforeComma); //wrappingPolicy = getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_EXPRS); setGlobalFormattingSettings(-1, addSpaceAfterComma, wrappingPolicy); } Expression expr = (Expression)it.next(); expr.accept(this); if(!indentedWrap){ indent(numOfIndents4Wrapping); //indentA indentedWrap = true; } isFirstExpr = false; } } if(indentedWrap) unindent(numOfIndents4Wrapping); } // public boolean visit(NullableType nullableType) { //// | typeNoName:typeNoName1 QUESTION:question1 //// {: RESULT = new NullableType(typeNoName1, typeNoName1left, question1right); :} //// | namedType:name1 QUESTION:question1 //// {: RESULT = new NullableType(name1, name1left, question1right); :} // push2ContextPath(nullableType); // Type baseType = nullableType.getBaseType(); // baseType.accept(this); // //I decided not to put space before ? // printStuffBeforeToken(NodeTypes.QUESTION, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_QUESTION_NULLABLETYPE)); // popContextPath(); // return false; // } public boolean visit(NameType nameType) { // ::= name:name1 // {: RESULT = new NameType(name1, name1left, name1right); :} push2ContextPath(nameType); Name name = nameType.getName(); name.accept(this); if(nameType.hasArguments()){ printStuffBeforeToken(NodeTypes.LPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_NAMEDTYPE)); List funcArgs = nameType.getArguments(); setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_NAMEDTYPE), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); formatExpressions(funcArgs, getEnumPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_ARGS), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_COMMA_NAMEDTYPE), getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_COMMA_NAMEDTYPE)); printStuffBeforeToken(NodeTypes.RPAREN, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_NAMEDTYPE)); } popContextPath(); return false; } private boolean visitTerminalNode(Node terminalASTNode){ push2ContextPath(terminalASTNode); printStuffBeforeNode(terminalASTNode.getOffset(), fGlobalNumOfBlankLines, fGlobalAddSpace, fCurrentWrappingPolicy); popContextPath(); return false; } public boolean visit(SimpleName simpleName) { // ::= ID:id1 // {: RESULT = new SimpleName(id1, id1left, id1right); :} return visitTerminalNode(simpleName); } public boolean visit(QualifiedName qualifiedName) { // | name:name1 DOT ID:id1 // {: RESULT = new QualifiedName(name1, id1, name1left, id1right); :} push2ContextPath(qualifiedName); qualifiedName.getQualifier().accept(this); printStuffBeforeToken(NodeTypes.DOT, -1, false); printStuffBeforeToken(NodeTypes.ID, -1, false); popContextPath(); return false; } public boolean visit(final ReturnsDeclaration returnsDeclaration) { // | RETURNS:returns1 LPAREN type:type1 sqlNullableOpt:nullable1 RPAREN:rparen1 // {: RESULT = new ReturnsDeclaration(type1, nullable1, returns1left, rparen1right); :} push2ContextPath(returnsDeclaration); final CodeFormatterVisitor thisVisitor = this; final int noNewLine = -1; final Type returnType = returnsDeclaration.getType(); ICallBackFormatter callbackFormatter = new ICallBackFormatter(){ public void format(Symbol prevToken, Symbol currToken) { boolean addSpace = false; if(currToken.left == returnType.getOffset()){ setGlobalFormattingSettings(-1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_AFTER_LPAREN_RETURN), CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); returnType.accept(thisVisitor); //I decided not to put space before ? if (returnsDeclaration.isNullable()) { printStuffBeforeToken(NodeTypes.QUESTION, -1, getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_QUESTION_RETURNS)); } } else{ if(currToken.sym == NodeTypes.LPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_LPAREN_RETURN); else if(currToken.sym == NodeTypes.RPAREN) addSpace = getBooleanPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WS_BEFORE_RPAREN_RETURN); else addSpace = false; printToken(prevToken, currToken, noNewLine, addSpace); } } }; //always add one space before returns formatNode(returnsDeclaration, callbackFormatter, noNewLine, true); popContextPath(); return false; } /*==> visitor methods <===*/ //if the production starts with terminal node, use the ICallBackFormatter style //otherwise, call each node's accept method with this visitor // //also note, see visit(ArrayLiteral) as example, when the starting and ending offset is not the //starting and ending offset of the production nodes, but some nodes within, use the each node's accept method style /*====================================================================================*/ /*==> helper methods <===*/ private void push2ContextPath(Node node){ fContextPath.push(node.getClass().getSimpleName()); } private void popContextPath(){ fContextPath.pop(); } private boolean printStuffBeforeNode(int nodeStartingOffset, int numOfBlankLinesBeforeNode, boolean addSpaceBeforeNode) { return printStuffBeforeNode(nodeStartingOffset, numOfBlankLinesBeforeNode, addSpaceBeforeNode, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); }; private boolean printStuffBeforeToken(int tokenType, int numOfBlankLinesBeforeNode, boolean addSpaceBeforeNode) { return printStuffBeforeToken(tokenType, numOfBlankLinesBeforeNode, addSpaceBeforeNode, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); }; /** * * @param nodeStartingOffset - the starting offset of the node we're trying to reach * * @return - true, it reached node * - false, it reached end of file */ private boolean printStuffBeforeNode(int nodeStartingOffset, int numOfBlankLinesBeforeNode, boolean addSpaceBeforeNode, int wrappingPolicy) { return printStuffBeforeNodeCommon(true, nodeStartingOffset, numOfBlankLinesBeforeNode, addSpaceBeforeNode, wrappingPolicy); }; private boolean printStuffBeforeToken(int tokenType, int numOfBlankLinesBeforeNode, boolean addSpaceBeforeNode, int wrappingPolicy) { return printStuffBeforeNodeCommon(false, tokenType, numOfBlankLinesBeforeNode, addSpaceBeforeNode, wrappingPolicy); }; private boolean printStuffBeforeNodeCommon(boolean useAsOffset, int nodeStartingOffset_Or_TokenType, int numOfBlankLinesBeforeNode, boolean addSpaceBeforeNode, int wrappingPolicy) { if(compareEqual(useAsOffset, fCurrToken, nodeStartingOffset_Or_TokenType)){ //when using the token symbol instead of offset to decide which token, if there are serveral same tokens in a roll, i.e. }}}} //we need to move the fCurrToken ahead, otherwise, it will always be compareEqual on the same token. if(!useAsOffset && fPrevToken == fCurrToken){ fCurrToken = nextToken(); printStuffBeforeNodeCommon(useAsOffset, nodeStartingOffset_Or_TokenType, numOfBlankLinesBeforeNode, addSpaceBeforeNode, wrappingPolicy); } else{ printToken(fPrevToken, fCurrToken, numOfBlankLinesBeforeNode, addSpaceBeforeNode, wrappingPolicy); fPrevToken = fCurrToken; } } while(!compareEqual(useAsOffset, fCurrToken, nodeStartingOffset_Or_TokenType) && fCurrToken.sym != NodeTypes.EOF){ fPrevToken = fCurrToken; fCurrToken = nextToken(); boolean addSpace = false; int numOfBlankLines = -1; if(fPrevToken.sym == NodeTypes.LINE_COMMENT){ numOfBlankLines = 0; } switch(fPrevToken.sym){ case NodeTypes.PRIVATE: case NodeTypes.ABSTRACT: addSpace = true; break; } //add one white space before the line comments //if this line comments does not start the line // if(fCurrToken.sym == NodeTypes.LINE_COMMENT) // if(fPrevToken.sym != NodeTypes.LINEBREAKS) // addSpace = true; // else // numOfBlankLines = 0; if(compareEqual(useAsOffset, fCurrToken, nodeStartingOffset_Or_TokenType)){ //when the previous token is a line comment //change the numOfBlankLinesBeforeNode value if it is <0 and wrapping policy is no wrap //so the next token will start on a new line with the right indentation(whatever the current indentation level is) if(fPrevToken.sym == NodeTypes.LINE_COMMENT && wrappingPolicy == CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP) numOfBlankLinesBeforeNode = numOfBlankLinesBeforeNode > 0 ? numOfBlankLinesBeforeNode : 0; printToken(fPrevToken, fCurrToken, numOfBlankLinesBeforeNode, addSpaceBeforeNode, wrappingPolicy); } else printToken(fPrevToken, fCurrToken, numOfBlankLines, addSpace); fPrevToken = fCurrToken; } if(fCurrToken.sym == NodeTypes.EOF) return false; return true; }; /** * if useAsOffset, compare token.left with offsetOrTokenType(an integer represents offset) * else, compare token.sym with offsetOrTokenType(an integer represents some NodeTypes) * * @param useAsOffset * @param token * @param offsetOrTokenType * @return - true: equal * false: not equal */ private boolean compareEqual(boolean useAsOffset, Symbol token, int offsetOrTokenType){ if(useAsOffset) return token.left == offsetOrTokenType; else return token.sym == offsetOrTokenType; } private void printToken(Symbol prevToken, Symbol token, int numOfBlankLines, boolean addSpace){ printToken(prevToken, token, numOfBlankLines, addSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP); } /** * insert numOfBlnakLines, white space before the currentToken * * @param prevToken * @param token * @param numOfBlankLines - <0 means no new lines, 0 means new line, but 0 blank lines, >0 means # of blank lines * @param addSpace - if there is new line added, this value is ignored */ private void printToken(Symbol prevToken, Symbol token, int numOfBlankLines, boolean addSpace, int wrappingPolicy){ //initialize the fCurrentColumn before it's being formatted int prevTokenLen = prevToken.right - prevToken.left; if(prevToken.sym == NodeTypes.BLOCK_COMMENT){ //block comments may have multiple line breaks try{ String blockComments = fDocument.get(prevToken.left, prevTokenLen); int lastLineSeparator = blockComments.lastIndexOf(fLineSeparator); if(lastLineSeparator != -1) fCurrentColumn = prevTokenLen-1-lastLineSeparator-1; else fCurrentColumn += prevTokenLen; } catch (BadLocationException e) { e.printStackTrace(); } } else { if(prevToken.sym == NodeTypes.LINE_COMMENT) //line comments includes one line break fCurrentColumn = 0; else if(prevToken.sym != NodeTypes.LINEBREAKS) fCurrentColumn += prevTokenLen; } fCurrentColumn += token.left - prevToken.right; //we do not format block comment or line comment if they're followed by non-line breaks //so if the current token is block comment or line comment and previous token is not line break //we do not format them, whatever position they were in will stay the same if(token.sym != NodeTypes.BLOCK_COMMENT && token.sym != NodeTypes.LINE_COMMENT){ printFormatToken(prevToken, token, numOfBlankLines, addSpace, wrappingPolicy, fEdits) ; printKeywordToken(token, fEdits); } else if(prevToken.sym == NodeTypes.LINEBREAKS || prevToken.sym == NodeTypes.LINE_COMMENT){ //line comment contains a line break //when the previous token is line break and current token is blockcomments or line comment //we want to remove the extra blank lines if there are any that's more than preserved blank lines preference printFormatToken(prevToken, token, 0, addSpace, wrappingPolicy, fEdits); } } private void printFormatToken(Symbol prevToken, Symbol token, int numOfBlankLines, boolean addSpace, int wrappingPolicy, List edits) { //now let's format, fCurrentColumn value may change based on the type of textEdit if(numOfBlankLines>=0){ if(wrappingPolicy == CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP){ //we are starting a new line, clear anything that's still in the pending wrap edit list, //wrapping is not necessary, commit no wrap edits while(!fPendingWrapEdits.isEmpty()){ PendingWrapEdit pendingWrapEdit = (PendingWrapEdit)fPendingWrapEdits.removeFirst(); fEdits.addAll(pendingWrapEdit.fNoWrapEdits); fIsWrappingNecessary = false; } } //we ignore the addSpace setting if addSpace is true, it will remove white spaces if there is any printSpace(prevToken, token, false, edits); //print blank lines will add appropriate indentation if it's needed printBlankLines(prevToken, token, numOfBlankLines, edits); } else{ //if user wants do not change wrapping policy, means they do not want it to be formatted if(wrappingPolicy != CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOCHANGE){ printNewLineBasedOnWrappingPolicy(prevToken, token, addSpace, wrappingPolicy) ; } } } private void printNewLineBasedOnWrappingPolicy(Symbol prevToken, Symbol token, boolean addSpace, int wrappingPolicy) { //try format it as "do not wrap", but do not commit the edit changes yet List noWrapEdits = new ArrayList(); boolean isLineBreaksRemoved = printRemoveLineBreaks(prevToken, token, addSpace, CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP, noWrapEdits); //if line breaks are not removed, which means it printed >=1 blank lines, //then the addSpace has been taken into consideration, which is alway false(do not add space) when adding blank lines //so we only need to print space when there is no new lines if(isLineBreaksRemoved) printSpace(prevToken, token, addSpace, noWrapEdits); //when the current token is line break, ignore it's length, //because this length is used to calculate whether or not it exceeds the maxLineWidth int tokenLen = (token.sym != NodeTypes.LINEBREAKS) ? (token.right - token.left) : 0; int maxLineWidth = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_MAX_LEN); if(wrappingPolicy == CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NOWRAP){ //when wrapping policy is not to wrap, then commit the noWrapEdits fEdits.addAll(noWrapEdits); //we might need to wrap any pending ones if there is any and it is necessary if(fCurrentColumn + tokenLen >= maxLineWidth){ fIsWrappingNecessary = true; //need to wrap the pending ones if there is any int savedNoWrapCurrentColumn = fCurrentColumn; while(!fPendingWrapEdits.isEmpty()){ PendingWrapEdit pendingWrapEdit = (PendingWrapEdit)fPendingWrapEdits.removeFirst(); fEdits.addAll(pendingWrapEdit.fWrapEdits); //since we're wrapping, so the new currentColumn should be //the pendingWrapEdit.fWrapColumn + the delta between the saved current token and the pending token's fNoWrapColumn fCurrentColumn = pendingWrapEdit.fWrapColumn + (savedNoWrapCurrentColumn - pendingWrapEdit.fNoWrapColumn); } } } else{ //wrapping policy is to wrap something List wrapEdits = new ArrayList(); //save the column value before it is wrapped int noWrapColumn = fCurrentColumn; wrapToken(prevToken, token, addSpace, wrappingPolicy, wrapEdits); //save the column value after it is wrapped int wrapColumn = fCurrentColumn; switch(wrappingPolicy){ case CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_NECESSARY: //check to see if there is any pending wrap, //if there are still some, those do not need to be wrapped, wrapping is not necessary for the ones in the pending list //we need to remove it, then committing the noWrapEdits while(!fPendingWrapEdits.isEmpty()){ PendingWrapEdit pendingWrapEdit = (PendingWrapEdit)fPendingWrapEdits.removeFirst(); fEdits.addAll(pendingWrapEdit.fNoWrapEdits); fIsWrappingNecessary = false; } if(noWrapColumn + tokenLen >= maxLineWidth){ fEdits.addAll(wrapEdits); fIsWrappingNecessary = true; } else{//save to the pending list, reset the currentColumn value back to no wrap column, since we haven't wrap it yet fPendingWrapEdits.add(new PendingWrapEdit(noWrapEdits, noWrapColumn, wrapEdits, wrapColumn)); fCurrentColumn = noWrapColumn; } break; case CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_ONEPERLINE_NECESSARY: //if it is necessary to wrap, wrap it if(noWrapColumn + tokenLen >= maxLineWidth || fIsWrappingNecessary){ fIsWrappingNecessary = true; while(!fPendingWrapEdits.isEmpty()){ PendingWrapEdit pendingWrapEdit = (PendingWrapEdit)fPendingWrapEdits.removeFirst(); fEdits.addAll(pendingWrapEdit.fWrapEdits); } fEdits.addAll(wrapEdits); } else{//save to the pending list, reset the currentColumn value back to no wrap column, since we haven't wrap it yet fPendingWrapEdits.add(new PendingWrapEdit(noWrapEdits, noWrapColumn, wrapEdits, wrapColumn)); fCurrentColumn = noWrapColumn; } break; case CodeFormatterConstants.FORMATTER_PREF_WRAP_POLICY_ONEPERLINE_FORCE: fEdits.addAll(wrapEdits); break; } } } private void wrapToken(Symbol prevToken, Symbol token, boolean addSpace, int wrappingPolicy, List edits) { // int numOfIndents4Wrapping = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_WRAP_NUMINDENTS); // //increase the indentation // indent(numOfIndents4Wrapping); //add a new line printFormatToken(prevToken, token, 0, addSpace, wrappingPolicy, edits); //unindent // unindent(numOfIndents4Wrapping); } /** * check to see if this token is an EGL keyword, if so, change its cases to the user preference case * * @param token */ private void printKeywordToken(Symbol token, List edits){ try { int tokenLen = token.right - token.left; String strToken = fDocument.get(token.left, tokenLen); HashSet eglKeywords = EGLKeywordHandler.getKeywordHashSet(); String lowerCasedToken = strToken.toLowerCase(); //if token is a keyword, we need to change its case based on user preference if(eglKeywords.contains(lowerCasedToken)){ String prefToken = ""; //$NON-NLS-1$ int keywordCasePref = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_KEYWORD_CASE); switch(keywordCasePref){ case CodeFormatterConstants.FORMATTER_PREF_KEYWORD_NOCHANGE: prefToken = strToken; break; case CodeFormatterConstants.FORMATTER_PREF_KEYWORD_UPPER: prefToken = strToken.toUpperCase(); break; case CodeFormatterConstants.FORMATTER_PREF_KEYWORD_LOWER: prefToken = lowerCasedToken; break; case CodeFormatterConstants.FORMATTER_PREF_KEYWORD_PREFER: { String[] eglPreferedCaseKeywords = EGLKeywordHandler.getKeywordNames(); boolean fFnd = false; for(int i=0; i<eglPreferedCaseKeywords.length && !fFnd; i++){ String eglPreferedCaseKeyword = eglPreferedCaseKeywords[i]; if(strToken.equalsIgnoreCase(eglPreferedCaseKeyword)){ prefToken = eglPreferedCaseKeyword; fFnd = true; } } } break; } //if the preferenced keyword case differs, format it to the user pereferenced keyword case if(!prefToken.equals(strToken)) edits.add(new ReplaceEdit(token.left, tokenLen, prefToken)); } } catch (BadLocationException e) { e.printStackTrace(); } } /** * will print numOfBlankLines before the current token, if the * numOfBlankLines is 0 and prevToken is not a linebreak, a new line would * be inserted before the current token * * this method takes preserve number of blank lines preference into consideration. * if preserve number of blank lines is more than the input parameter numOfBlankLines, and there are existing blank lines * keep the smaller of the existing blank lines or preserve blank lines preferences * * @param prevToken * @param token - * current token * @param numOfBlankLines */ private void printBlankLines(Symbol prevToken, Symbol token, int numOfBlankLines, List edits){ int preserveBlankLines = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_KEEP_EXISTING); int existingBlankLines = getExistingBlankLines(prevToken, fDocument) ; //try to figure out what's the number of blank lines format should set between prevToken and token StringBuffer lines = new StringBuffer(); int formatNumOfBlankLines = numOfBlankLines; //if there are existing blank lines, take the preveBlank lines preference into consideration if(existingBlankLines>0 && (preserveBlankLines > numOfBlankLines)){ formatNumOfBlankLines = Math.min(existingBlankLines, preserveBlankLines); } for(int i=0; i<formatNumOfBlankLines; i++) lines.append(fLineSeparator); //get indentation String String strIndentation = getIndentationString(); if(prevToken.sym == NodeTypes.LINEBREAKS){ int replaceLength = prevToken.right-prevToken.left; //check to see if offset prevToken.left is at a beginning of a line - so this would already be a blank line if(!isOffsetOnABlankLine(prevToken.left, fDocument)) lines.append(fLineSeparator); lines.append(strIndentation); edits.add(new ReplaceEdit(prevToken.left, replaceLength, lines.toString())); } else if(formatNumOfBlankLines >=0){ //check to see if the insertion offset token.left is at a beginning of a line - so this would make it a blank line if(!isOffsetOnABlankLine(token.left, fDocument)) lines.append(fLineSeparator); lines.append(strIndentation); String strLines = lines.toString(); if(strLines.length()>0) //no need to insert empty string edits.add(new InsertEdit(token.left, strLines)); } fCurrentColumn = 0; //starting a new line fCurrentColumn += strIndentation.length(); } /** * return the number of blank lines if testToken is LINEBREAKS, * otherwise, return 0 * * @param testToken * @return */ private static int getExistingBlankLines(Symbol testToken, IDocument document) { int existingBlankLines = 0; try { //calculate number of existing blank lines if(testToken.sym == NodeTypes.LINEBREAKS){ int startLineNum = document.getLineOfOffset(testToken.left); int endLineNum = document.getLineOfOffset(testToken.right); existingBlankLines = endLineNum-startLineNum; if(!isOffsetOnABlankLine(testToken.left, document)){ existingBlankLines--; //existingBlankLines can't be smaller than 0 if(existingBlankLines<0) existingBlankLines = 0; } } }catch (BadLocationException e) { e.printStackTrace(); } return existingBlankLines ; } private static boolean isOffsetOnABlankLine(int offset, IDocument document){ try { int lineNum = document.getLineOfOffset(offset); int lineStartingOffset = document.getLineOffset(lineNum); int lineLen = document.getLineLength(lineNum); int firstNonWhiteSpaceCharOffset = lineStartingOffset; boolean bFnd = false; //let's get the 1st non white space character on the line for(int i=lineStartingOffset; (i<lineStartingOffset+lineLen)&&!bFnd; i++){ char ch = document.getChar(i); if(!isEGLSpaceCharacter(ch)){ firstNonWhiteSpaceCharOffset = i; bFnd = true; } } if(firstNonWhiteSpaceCharOffset == offset) return true; } catch (BadLocationException e) { e.printStackTrace(); } return false; } /** * EGL lexer consider the following characters as white space character, which is ignored during parsing * see egl.flex * * @param ch * @return */ private static boolean isEGLSpaceCharacter(char ch){ if((ch == ' ') || (ch == '\t') || (ch == '\f')) return true; return false; } /** * print one space between the previous token and current token * if isAddSpace=true * insert a space if there were none, remove extra spaces if there were more than one * when isAddSpace=flase, remove any space that were there * * @param prevToken * @param token * @param isAddSpace */ private void printSpace(Symbol prevToken, Symbol token, boolean isAddSpace, List edits){ int spaceInBetweenTokens = token.left - prevToken.right; if(isAddSpace ){ if(spaceInBetweenTokens == 0){ //if there is no space between the current token and previous token) //insert space here edits.add(new InsertEdit(prevToken.right, SPACE)); fCurrentColumn ++; } else if (spaceInBetweenTokens > 1){ //replace the spaceInBetweenTokens with one space edits.add(new ReplaceEdit(prevToken.right, spaceInBetweenTokens, SPACE)); fCurrentColumn = fCurrentColumn + SPACE.length() - spaceInBetweenTokens; } else if(spaceInBetweenTokens == 1){ //need to check if this character is a white space character, it could be /t, we want to replace it with ' ' try { char whiteSpaceChar = fDocument.getChar(prevToken.right) ; if(whiteSpaceChar != SPACECHAR){ edits.add(new ReplaceEdit(prevToken.right, 1, SPACE)); } } catch (BadLocationException e) { e.printStackTrace(); } } } else { if(spaceInBetweenTokens > 0){ //delete the spaceInBetweenTokens edits.add(new DeleteEdit(prevToken.right, spaceInBetweenTokens)); fCurrentColumn -= spaceInBetweenTokens; } } } /** * Remove line breaks before the token if there were any (that is prevToken is line break) * * @param prevToken * @param token - current token * @param addSpace * @param wrappingPolicy * @param edits * * @return whether or not line breaks were removed before token * true - printed no new lines, line breaks were either removed if there were any or * there was no line breaks between the tokens in the first place that needs to be removed * false - printed >=1 blank lines, line breaks can not be removed, * because there were some exsiting blank lines that needs to be preserved based on the preserve blank lines preference */ private boolean printRemoveLineBreaks(Symbol prevToken, Symbol token, boolean addSpace, int wrappingPolicy, List edits){ if(prevToken.sym == NodeTypes.LINEBREAKS || prevToken.sym == NodeTypes.LINE_COMMENT){//line comment contains one line break //check to see if there is any existing blank lines //if so, we need to consider the preserve blank lines preferences int preserveBlankLines = getIntPrefSetting(CodeFormatterConstants.FORMATTER_PREF_BLANKLINES_KEEP_EXISTING); int existingBlankLines = getExistingBlankLines(prevToken, fDocument); if(existingBlankLines > 0 && preserveBlankLines > 0){ int numOfBlankLines = Math.min(existingBlankLines, preserveBlankLines); printFormatToken(prevToken, token, numOfBlankLines, addSpace, wrappingPolicy, edits); return false; } else if(prevToken.sym == NodeTypes.LINE_COMMENT){ //this way, the token after the line comment can start with the right indentation level printFormatToken(prevToken, token, 0, addSpace, wrappingPolicy, edits); return false; } else{ //no existing blank lines, remove the line breaks if it already has one //fCurrentColumn's value does not change, since we removed the line break edits.add(new DeleteEdit(prevToken.left, prevToken.right-prevToken.left)); } } return true; } /** * helper method, to wrap the exception * @return */ private Symbol nextToken(){ Symbol nextToken = null; try { nextToken = fScanner.next_token(); } catch (Exception e) { e.printStackTrace(); //should never happen } return nextToken; } private TextEdit getFinalEdits(){ MultiTextEdit edit = new MultiTextEdit(); int i=0; try{ for(Iterator it= fEdits.iterator(); it.hasNext();){ TextEdit editElem = (TextEdit)it.next(); //for partial format, only count in the ones that's within the formatting range if(editElem.getExclusiveEnd() >= fFormatOffset && editElem.getInclusiveEnd() <= (fFormatOffset+fFormatLength) ) edit.addChild(editElem); i++; } }catch(MalformedTreeException e){ e.printStackTrace(); //the following is for debugging purpose TextEdit childEdit = e.getChild(); System.out.println("index is: " + i); //$NON-NLS-1$ System.out.println("cuasing child edit is: " + childEdit.toString()); //$NON-NLS-1$ try { System.out.println("child edit text is: " + fDocument.get(childEdit.getOffset(), childEdit.getOffset()+childEdit.getLength())); //$NON-NLS-1$ } catch (BadLocationException e1) { e1.printStackTrace(); } } return edit; } }