in formatter/src/main/java/org/apache/royale/formatter/ASTokenFormatter.java [204:1141]
private String parseTokens(List<IASToken> tokens, String fileText, String filePath) throws Exception {
indent = 0;
inCaseOrDefaultClause = false;
inControlFlowStatement = false;
inVarOrConstDeclaration = false;
inFunctionDeclaration = false;
inPackageDeclaration = false;
inClassDeclaration = false;
inInterfaceDeclaration = false;
inConfigGateForDefinition = false;
blockOpenPending = false;
elseNoNewLinePending = false;
indentedStatement = false;
caseOrDefaultBlockOpenPending = false;
skipFormatting = false;
varOrConstChainLevel = -1;
blockStack = new ArrayList<BlockStackItem>();
controlFlowParenStack = 0;
ternaryStack = 0;
numRequiredNewLines = 0;
requiredSpace = false;
prevTokenNotComment = null;
prevToken = null;
prevTokenOrExtra = null;
token = null;
nextToken = null;
nextTokenOrExtra = null;
nextTokenNotComment = null;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < tokens.size(); i++) {
token = tokens.get(i);
if (inConfigGateForDefinition && token.getType() == ASTokenTypes.TOKEN_SEMICOLON && token.isImplicit())
{
// skip the implicit semicolon if we just saw a namespace
// annotated config constant, like COMPILE:JS or COMPILE::SWF
// and the next token starts a definition, like a class.
// the implicit semicolon is only there because the ASParser
// can't resolve the constant's value without the user providing
// it manually.
inConfigGateForDefinition = false;
prevToken = token;
prevTokenOrExtra = token;
prevTokenNotComment = token;
continue;
}
if (token.getType() == TOKEN_TYPE_EXTRA) {
if (skipFormatting) {
builder.append(token.getText());
} else {
if (i == (tokens.size() - 1)) {
// if the last token is whitespace, include at most one
// new line, but strip the rest
numRequiredNewLines = Math.min(1, Math.max(0, countNewLinesInExtra(token)));
appendNewLines(builder, numRequiredNewLines);
break;
}
if (!blockOpenPending && !elseNoNewLinePending) {
int newLinesInExtra = countNewLinesInExtra(token);
if (prevToken != null && prevToken.getType() == ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT) {
newLinesInExtra++;
}
boolean oneLineBlock = prevToken != null && prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN
&& nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
if (oneLineBlock && settings.collapseEmptyBlocks) {
newLinesInExtra = 0;
}
numRequiredNewLines = Math.max(numRequiredNewLines, newLinesInExtra);
if (!indentedStatement && numRequiredNewLines > 0 && prevTokenNotComment != null
&& prevTokenNotComment.getType() != ASTokenTypes.TOKEN_SEMICOLON
&& prevTokenNotComment.getType() != ASTokenTypes.TOKEN_BLOCK_CLOSE
&& !(caseOrDefaultBlockOpenPending
&& prevTokenNotComment.getType() == ASTokenTypes.TOKEN_COLON)
&& !(prevTokenNotComment instanceof MetaDataPayloadToken)) {
boolean needsIndent = prevTokenNotComment.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN
|| (!blockStack.isEmpty() && blockStack
.get(blockStack.size() - 1) instanceof ObjectLiteralBlockStackItem);
if (needsIndent) {
startIndentedStatement();
}
}
}
}
prevTokenOrExtra = token;
continue;
}
nextTokenOrExtra = ((i + 1) < tokens.size()) ? tokens.get(i + 1) : null;
nextToken = getNextTokenByOffset(tokens, i, 1, true, false);
nextTokenNotComment = getNextTokenByOffset(tokens, i, 1, true, true);
boolean skipWhitespaceBeforeNextSignificantToken = nextToken == null
|| nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON
|| nextToken.getType() == ASTokenTypes.TOKEN_COMMA
|| nextToken.getType() == ASTokenTypes.TOKEN_COLON;
// characters that must appear before the token
if (token instanceof MetaDataPayloadToken) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
} else {
switch (token.getType()) {
case ASTokenTypes.TOKEN_BLOCK_OPEN: {
if (!blockOpenPending) {
// detect some cases of blocks that may have been
// missed earlier (these will be standalone blocks,
// without a control flow statement or definition).
// this should not detect object literals, though!
blockOpenPending = prevTokenNotComment == null
|| prevTokenNotComment.getType() == ASTokenTypes.TOKEN_SEMICOLON
|| prevTokenNotComment.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN
|| prevTokenNotComment.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
if (!blockOpenPending && prevTokenNotComment.getType() == ASTokenTypes.TOKEN_COLON
&& !blockStack.isEmpty()) {
IASToken blockToken = blockStack.get(blockStack.size() - 1).token;
blockOpenPending = blockToken.getType() == ASTokenTypes.TOKEN_KEYWORD_DEFAULT
|| blockToken.getType() == ASTokenTypes.TOKEN_KEYWORD_CASE;
}
if (blockOpenPending) {
blockStack.add(new BlockStackItem(token));
}
}
if (blockOpenPending) {
boolean oneLineBlock = nextToken != null
&& nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
boolean needsNewLine = settings.placeOpenBraceOnNewLine
&& (!settings.collapseEmptyBlocks || !oneLineBlock);
if (needsNewLine) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
} else if (oneLineBlock && settings.collapseEmptyBlocks) {
numRequiredNewLines = 0;
}
requiredSpace = true;
} else {
// probably an object literal
blockStack.add(new ObjectLiteralBlockStackItem(token));
// we will indent, but after appending the token
requiredSpace = prevTokenNotComment == null || prevTokenNotComment.getType() != ASTokenTypes.TOKEN_PAREN_OPEN;
}
break;
}
case ASTokenTypes.TOKEN_BLOCK_CLOSE: {
boolean checkNext = true;
while (!blockStack.isEmpty() && checkNext) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
if (stackItem.controlFlow && !stackItem.braces) {
// this block close token applies to a block
// that contains nested control flow statements
// without braces, so remove all of them
blockStack.remove(blockStack.size() - 1);
indent = decreaseIndent(indent);
continue;
}
checkNext = false;
}
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
if (stackItem.blockDepth <= 1) {
boolean oneLineBlock = prevToken != null
&& prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN
&& !(stackItem instanceof ObjectLiteralBlockStackItem);
boolean allowPackageIndent = settings.indentPackageContents
|| stackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_PACKAGE;
boolean allowSwitchIndent = settings.indentSwitchContents
|| stackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_SWITCH;
boolean allowCaseOrDefaultIndent = !(stackItem instanceof CaseOrDefaultBlockStackItem)
|| ((CaseOrDefaultBlockStackItem) stackItem).containsOnlyBlock;
if ((!settings.collapseEmptyBlocks || !oneLineBlock)
&& allowPackageIndent
&& allowSwitchIndent
&& allowCaseOrDefaultIndent) {
indent = decreaseIndent(indent);
}
if (stackItem instanceof CaseOrDefaultBlockStackItem)
{
CaseOrDefaultBlockStackItem caseOrDefaultStackItem = (CaseOrDefaultBlockStackItem) stackItem;
if (!caseOrDefaultStackItem.containsOnlyBlock) {
blockStack.remove(blockStack.size() - 1);
if (settings.indentSwitchContents) {
indent = decreaseIndent(indent);
}
}
}
}
}
// check again because case/default might have been removed
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
if (stackItem.token.getType() == ASTokenTypes.TOKEN_KEYWORD_SWITCH) {
SwitchBlockStackItem switchStackItem = (SwitchBlockStackItem) stackItem;
if (switchStackItem.clauseCount > 0
&& (prevToken == null
|| prevToken.getType() != ASTokenTypes.TOKEN_BLOCK_CLOSE)) {
indent = decreaseIndent(indent);
}
}
}
break;
}
case ASTokenTypes.TOKEN_SQUARE_CLOSE: {
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
if (stackItem.token.getType() == ASTokenTypes.TOKEN_SQUARE_OPEN) {
indent = decreaseIndent(indent);
blockStack.remove(blockStack.size() - 1);
}
}
break;
}
case ASTokenTypes.TOKEN_PAREN_CLOSE: {
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
if (stackItem.token.getType() == ASTokenTypes.TOKEN_PAREN_OPEN) {
indent = decreaseIndent(indent);
blockStack.remove(blockStack.size() - 1);
}
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_IN: {
inVarOrConstDeclaration = false;
// needs an extra space before the token
requiredSpace = true;
break;
}
case ASTokenTypes.TOKEN_KEYWORD_AS:
case ASTokenTypes.TOKEN_KEYWORD_IS:
case ASTokenTypes.TOKEN_KEYWORD_INSTANCEOF:
case ASTokenTypes.TOKEN_RESERVED_WORD_EACH:
case ASTokenTypes.TOKEN_RESERVED_WORD_EXTENDS:
case ASTokenTypes.TOKEN_RESERVED_WORD_IMPLEMENTS:
case ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT:
case ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT: {
// needs an extra space before the token
requiredSpace = true;
break;
}
case ASTokenTypes.TOKEN_KEYWORD_ELSE: {
if (elseNoNewLinePending) {
numRequiredNewLines = 0;
elseNoNewLinePending = false;
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_NOT_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_STRICT_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_STRICT_NOT_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_LESS_THAN:
case ASTokenTypes.TOKEN_OPERATOR_GREATER_THAN:
case ASTokenTypes.TOKEN_OPERATOR_LESS_THAN_EQUALS:
case ASTokenTypes.TOKEN_OPERATOR_GREATER_THAN_EQUALS:
case ASTokenTypes.TOKEN_OPERATOR_DIVISION:
case ASTokenTypes.TOKEN_OPERATOR_MODULO:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_AND:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_LEFT_SHIFT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_OR:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_XOR:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_AND:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_OR:
case ASTokenTypes.TOKEN_OPERATOR_NULLISH_COALESCING:
case ASTokenTypes.TOKEN_OPERATOR_PLUS_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_MINUS_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_MULTIPLICATION_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_DIVISION_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_MODULO_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_AND_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_LEFT_SHIFT_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_OR_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_XOR_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_AND_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_OR_ASSIGNMENT: {
if (settings.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_STAR: {
boolean isAnyType = checkTokenBeforeAnyType(prevTokenNotComment);
boolean isAnyVectorType = checkTokensForAnyVectorType(prevTokenNotComment, nextTokenNotComment);
if (!isAnyType && !isAnyVectorType && settings.insertSpaceBeforeAndAfterBinaryOperators
&& !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_PLUS:
case ASTokenTypes.TOKEN_OPERATOR_MINUS: {
boolean isUnary = checkTokenBeforePossibleUnaryOperator(prevTokenNotComment);
if (!isUnary && settings.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_ASSIGNMENT: {
inVarOrConstDeclaration = false;
if (settings.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_TERNARY: {
ternaryStack++;
if (settings.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_ELLIPSIS: {
boolean isFirstArg = prevToken == null || prevToken.getType() == ASTokenTypes.TOKEN_PAREN_OPEN;
if (!isFirstArg) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_DEFAULT:
case ASTokenTypes.TOKEN_KEYWORD_CASE: {
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
switch (stackItem.token.getType()) {
case ASTokenTypes.TOKEN_KEYWORD_DEFAULT:
case ASTokenTypes.TOKEN_KEYWORD_CASE: {
blockStack.remove(blockStack.size() - 1);
indent = decreaseIndent(indent);
break;
}
}
}
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
if (stackItem.token.getType() == ASTokenTypes.TOKEN_KEYWORD_SWITCH) {
SwitchBlockStackItem switchStackItem = (SwitchBlockStackItem) stackItem;
switchStackItem.clauseCount++;
inCaseOrDefaultClause = true;
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
blockStack.add(new CaseOrDefaultBlockStackItem(token));
}
}
break;
}
case ASTokenTypes.TOKEN_COLON: {
if (ternaryStack > 0) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_SEMICOLON: {
endIndentedStatement();
inVarOrConstDeclaration = false;
varOrConstChainLevel = -1;
break;
}
case ASTokenTypes.TOKEN_ASDOC_COMMENT: {
if (prevToken != null && prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
} else {
// add an extra line before an asdoc comment
numRequiredNewLines = Math.max(numRequiredNewLines, 2);
}
break;
}
}
}
if (!skipFormatting && prevToken != null) {
if (numRequiredNewLines > 0) {
appendNewLines(builder, numRequiredNewLines);
appendIndent(builder, indent);
} else if (requiredSpace) {
builder.append(' ');
}
}
switch (token.getType()) {
case ASTokenTypes.TOKEN_BLOCK_OPEN: {
if (blockOpenPending) {
boolean oneLineBlock = nextToken != null
&& nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
BlockStackItem stackItem = blockStack.isEmpty() ? null : blockStack.get(blockStack.size() - 1);
boolean allowPackageIndent = settings.indentPackageContents
|| stackItem == null
|| stackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_PACKAGE;
boolean allowSwitchIndent = settings.indentSwitchContents
|| stackItem == null
|| stackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_SWITCH;
if (settings.placeOpenBraceOnNewLine
&& (!settings.collapseEmptyBlocks || !oneLineBlock)
&& allowPackageIndent
&& allowSwitchIndent) {
indent = increaseIndent(indent);
}
}
break;
}
}
// include the token's own text
builder.append(getTokenText(token, indent, skipFormatting, fileText));
// characters that must appear after the token
if (token.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
&& token.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT
&& token.getType() != ASTokenTypes.TOKEN_ASDOC_COMMENT
&& token.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN) {
blockOpenPending = false;
}
if (token.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
&& token.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT
&& token.getType() != ASTokenTypes.TOKEN_ASDOC_COMMENT) {
caseOrDefaultBlockOpenPending = false;
}
requiredSpace = false;
numRequiredNewLines = 0;
if (token instanceof MetaDataPayloadToken) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
} else {
switch (token.getType()) {
case ASTokenTypes.TOKEN_SEMICOLON: {
if (inControlFlowStatement && isInForStatement(blockStack)) {
if (settings.insertSpaceAfterSemicolonInForStatements) {
requiredSpace = true;
}
// else no space
} else {
boolean checkNext = true;
int prevPoppedTokenType = -1;
while (!blockStack.isEmpty() && checkNext) {
checkNext = false;
BlockStackItem prevStackItem = blockStack.get(blockStack.size() - 1);
if (prevStackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_CASE
&& prevStackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_DEFAULT
&& prevStackItem.blockDepth <= 0) {
if (prevPoppedTokenType == ASTokenTypes.TOKEN_KEYWORD_IF && prevStackItem.token.getType() == ASTokenTypes.TOKEN_KEYWORD_IF && nextTokenNotComment != null && nextTokenNotComment.getType() == ASTokenTypes.TOKEN_KEYWORD_ELSE ) {
// if we've already popped an if, and
// we encounter another if, but the next
// non-comment token is an else, then
// we don't want to pop any more ifs
break;
}
blockStack.remove(blockStack.size() - 1);
if (prevStackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_CLASS
&& prevStackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_INTERFACE
&& prevStackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_FUNCTION) {
checkNext = !prevStackItem.braces;
indent = decreaseIndent(indent);
}
}
prevPoppedTokenType = prevStackItem.token.getType();
}
}
if (!inControlFlowStatement) {
if (nextToken != null
&& (nextToken.getType() == ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
|| nextToken.getType() == ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT)) {
requiredSpace = true;
} else {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
}
break;
}
case ASTokenTypes.TOKEN_BLOCK_OPEN: {
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
if (stackItem instanceof ObjectLiteralBlockStackItem) {
indent = increaseIndent(indent);
}
}
if (blockOpenPending) {
blockOpenPending = false;
BlockStackItem stackItem = null;
if (!blockStack.isEmpty()) {
stackItem = blockStack.get(blockStack.size() - 1);
stackItem.blockDepth++;
}
boolean oneLineBlock = nextToken != null
&& nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
boolean allowPackageIndent = settings.indentPackageContents
|| stackItem == null
|| stackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_PACKAGE;
boolean allowSwitchIndent = settings.indentSwitchContents
|| stackItem == null
|| stackItem.token.getType() != ASTokenTypes.TOKEN_KEYWORD_SWITCH;
if ((!settings.collapseEmptyBlocks || !oneLineBlock)
&& allowPackageIndent
&& allowSwitchIndent) {
if (!settings.placeOpenBraceOnNewLine) {
indent = increaseIndent(indent);
}
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
}
break;
}
case ASTokenTypes.TOKEN_BLOCK_CLOSE: {
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
stackItem.blockDepth--;
if (stackItem.blockDepth <= 0) {
blockStack.remove(blockStack.size() - 1);
}
if (!(stackItem instanceof ObjectLiteralBlockStackItem)) {
if (nextToken != null && nextTokenNotComment != null && nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT && nextTokenNotComment.getType() == ASTokenTypes.TOKEN_KEYWORD_ELSE && !settings.insertNewLineElse) {
elseNoNewLinePending = true;
}
else if (nextToken == null || (nextToken.getType() != ASTokenTypes.TOKEN_SEMICOLON
&& nextToken.getType() != ASTokenTypes.TOKEN_PAREN_CLOSE
&& nextToken.getType() != ASTokenTypes.TOKEN_COMMA
&& nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
&& nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT)) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
}
}
break;
}
case ASTokenTypes.TOKEN_SQUARE_OPEN: {
blockStack.add(new BlockStackItem(token));
indent = increaseIndent(indent);
break;
}
case ASTokenTypes.TOKEN_PAREN_OPEN: {
blockStack.add(new BlockStackItem(token));
indent = increaseIndent(indent);
if (inControlFlowStatement) {
controlFlowParenStack++;
}
break;
}
case ASTokenTypes.TOKEN_IDENTIFIER: {
// look for a config constant, like COMPILE:JS or COMPILE::SWF
if (prevToken != null && prevToken.getType() == ASTokenTypes.TOKEN_OPERATOR_NS_QUALIFIER) {
boolean isConfigBlock = nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN;
if (isConfigBlock) {
// this is a config constant block
blockStack.add(new BlockStackItem(prevToken));
blockOpenPending = true;
}
else if (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON && nextToken.isImplicit())
{
// if it's not before the start of a block, it
// might be before the start of a definition
IASToken prevPrevToken = getPrevTokenByOffset(tokens, i, 3, true, true);
if (prevPrevToken == null
|| prevPrevToken.getType() == ASTokenTypes.TOKEN_SEMICOLON
|| prevPrevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN
|| prevPrevToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE) {
IASToken nextNextToken = getNextTokenByOffset(tokens, i, 2, true, true);
if (nextNextToken != null) {
if (nextNextToken.getType() == ASTokenTypes.TOKEN_NAMESPACE_ANNOTATION
|| nextNextToken.getType() == ASTokenTypes.TOKEN_KEYWORD_CLASS
|| nextNextToken.getType() == ASTokenTypes.TOKEN_KEYWORD_INTERFACE
|| nextNextToken.getType() == ASTokenTypes.TOKEN_KEYWORD_FUNCTION
|| nextNextToken.getType() == ASTokenTypes.TOKEN_KEYWORD_VAR
|| nextNextToken.getType() == ASTokenTypes.TOKEN_KEYWORD_CONST
|| nextNextToken.getType() == ASTokenTypes.TOKEN_MODIFIER_ABSTRACT
|| nextNextToken.getType() == ASTokenTypes.TOKEN_MODIFIER_DYNAMIC
|| nextNextToken.getType() == ASTokenTypes.TOKEN_MODIFIER_FINAL
|| nextNextToken.getType() == ASTokenTypes.TOKEN_MODIFIER_NATIVE
|| nextNextToken.getType() == ASTokenTypes.TOKEN_MODIFIER_OVERRIDE
|| nextNextToken.getType() == ASTokenTypes.TOKEN_MODIFIER_STATIC
|| nextNextToken.getType() == ASTokenTypes.TOKEN_MODIFIER_VIRTUAL) {
// this config constant is gating a definition
// like COMPILE::JS or COMPILE::SWF before a class
inConfigGateForDefinition = true;
}
}
}
}
}
break;
}
case ASTokenTypes.TOKEN_PAREN_CLOSE: {
if (inControlFlowStatement) {
controlFlowParenStack--;
if (controlFlowParenStack <= 0) {
endIndentedStatement();
inControlFlowStatement = false;
// if a variable was declared inside the
// parentheses, such as in a for() loop, this
// should already be false (if it's not, there's
// a bug somewhere).
// but this will add a little extra safety.
inVarOrConstDeclaration = false;
if (!blockStack.isEmpty()) {
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
stackItem.controlFlowEnd = token.getEnd();
}
controlFlowParenStack = 0;
blockOpenPending = true;
if (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON) {
blockStack.remove(blockStack.size() - 1);
if (!skipWhitespaceBeforeNextSignificantToken) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
} else if (nextTokenNotComment != null && nextTokenNotComment.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN
&& !skipWhitespaceBeforeNextSignificantToken) {
indent = increaseIndent(indent);
BlockStackItem stackItem = blockStack.get(blockStack.size() - 1);
stackItem.braces = false;
// if a comment is on the same line
// don't add a line break yet
if (nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
&& nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT
&& nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_COMMENT) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
}
}
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_INCREMENT:
case ASTokenTypes.TOKEN_OPERATOR_DECREMENT: {
if (!inControlFlowStatement
&& !checkTokenBeforePossibleUnaryOperator(prevTokenNotComment)
&& !checkTokenAfterPossibleUnaryOperator(nextTokenNotComment)) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_CONTINUE:
case ASTokenTypes.TOKEN_KEYWORD_BREAK:
case ASTokenTypes.TOKEN_KEYWORD_RETURN: {
if (!skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_PACKAGE: {
blockStack.add(new BlockStackItem(token));
requiredSpace = true;
inPackageDeclaration = true;
break;
}
case ASTokenTypes.TOKEN_KEYWORD_CLASS: {
blockStack.add(new BlockStackItem(token));
requiredSpace = true;
inClassDeclaration = true;
break;
}
case ASTokenTypes.TOKEN_KEYWORD_INTERFACE: {
blockStack.add(new BlockStackItem(token));
requiredSpace = true;
inInterfaceDeclaration = true;
break;
}
case ASTokenTypes.TOKEN_KEYWORD_FUNCTION: {
blockStack.add(new BlockStackItem(token));
inFunctionDeclaration = true;
boolean skipSpace = !settings.insertSpaceAfterFunctionKeywordForAnonymousFunctions
&& (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_PAREN_OPEN);
if (!skipSpace) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_VAR:
case ASTokenTypes.TOKEN_KEYWORD_CONST: {
inVarOrConstDeclaration = true;
requiredSpace = true;
varOrConstChainLevel = blockStack.size();
break;
}
case ASTokenTypes.TOKEN_KEYWORD_CATCH:
case ASTokenTypes.TOKEN_KEYWORD_FOR:
case ASTokenTypes.TOKEN_KEYWORD_IF:
case ASTokenTypes.TOKEN_KEYWORD_WHILE:
case ASTokenTypes.TOKEN_KEYWORD_WITH: {
inControlFlowStatement = true;
BlockStackItem stackItem = new BlockStackItem(token);
stackItem.controlFlow = true;
blockStack.add(stackItem);
if (settings.insertSpaceAfterKeywordsInControlFlowStatements
&& !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_SWITCH: {
inControlFlowStatement = true;
blockStack.add(new SwitchBlockStackItem(token));
if (settings.insertSpaceAfterKeywordsInControlFlowStatements
&& !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_TRY:
case ASTokenTypes.TOKEN_KEYWORD_FINALLY: {
blockStack.add(new BlockStackItem(token));
if (!skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
blockOpenPending = true;
break;
}
case ASTokenTypes.TOKEN_KEYWORD_ELSE: {
if (nextTokenNotComment != null
&& nextTokenNotComment.getType() == ASTokenTypes.TOKEN_KEYWORD_IF) {
requiredSpace = true;
} else {
BlockStackItem stackItem = new BlockStackItem(token);
stackItem.controlFlow = true;
blockStack.add(stackItem);
blockOpenPending = true;
if (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON) {
blockStack.remove(blockStack.size() - 1);
if (!skipWhitespaceBeforeNextSignificantToken) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
} else if (nextToken != null && nextToken.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN
&& nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
&& !skipWhitespaceBeforeNextSignificantToken) {
indent = increaseIndent(indent);
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
stackItem.braces = false;
}
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_DO: {
blockStack.add(new BlockStackItem(token));
blockOpenPending = true;
if (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON) {
blockStack.remove(blockStack.size() - 1);
if (!skipWhitespaceBeforeNextSignificantToken) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
} else if (nextToken != null && nextToken.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN
&& nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
&& !skipWhitespaceBeforeNextSignificantToken) {
indent = increaseIndent(indent);
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
break;
}
case ASTokenTypes.TOKEN_COLON: {
if (ternaryStack > 0) {
ternaryStack--;
requiredSpace = true;
} else if (!inControlFlowStatement && !inVarOrConstDeclaration && !inFunctionDeclaration) {
if (inCaseOrDefaultClause) {
inCaseOrDefaultClause = false;
caseOrDefaultBlockOpenPending = true;
boolean nextIsBlock = nextTokenNotComment != null
&& nextTokenNotComment.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN;
boolean caseOrDefaultContainsOnlyBlock = false;
if (nextIsBlock) {
IASToken afterBlockClose = findTokenAfterBlock(nextTokenNotComment, tokens);
BlockStackItem stackItem = !blockStack.isEmpty() ? blockStack.get(blockStack.size() - 1) : null;
if (stackItem instanceof CaseOrDefaultBlockStackItem) {
CaseOrDefaultBlockStackItem caseOrDefaultStackItem = (CaseOrDefaultBlockStackItem) stackItem;
caseOrDefaultContainsOnlyBlock = afterBlockClose != null
&& (afterBlockClose.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE
|| afterBlockClose.getType() == ASTokenTypes.TOKEN_KEYWORD_CASE
|| afterBlockClose.getType() == ASTokenTypes.TOKEN_KEYWORD_DEFAULT);
caseOrDefaultStackItem.containsOnlyBlock = caseOrDefaultContainsOnlyBlock;
if (caseOrDefaultContainsOnlyBlock) {
blockOpenPending = true;
}
requiredSpace = true;
}
}
if (!caseOrDefaultContainsOnlyBlock || !blockOpenPending) {
indent = increaseIndent(indent);
if (nextToken != null && (nextToken
.getType() == ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
|| nextToken.getType() == ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT)) {
requiredSpace = true;
} else {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
}
}
} else {
requiredSpace = true;
}
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_CASE: {
if (!skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_DEFAULT: {
if (!inCaseOrDefaultClause && !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_KEYWORD_AS:
case ASTokenTypes.TOKEN_KEYWORD_DELETE:
case ASTokenTypes.TOKEN_KEYWORD_IMPORT:
case ASTokenTypes.TOKEN_KEYWORD_IN:
case ASTokenTypes.TOKEN_KEYWORD_INCLUDE:
case ASTokenTypes.TOKEN_KEYWORD_INSTANCEOF:
case ASTokenTypes.TOKEN_KEYWORD_IS:
case ASTokenTypes.TOKEN_KEYWORD_NEW:
case ASTokenTypes.TOKEN_KEYWORD_THROW:
case ASTokenTypes.TOKEN_KEYWORD_TYPEOF:
case ASTokenTypes.TOKEN_KEYWORD_USE:
case ASTokenTypes.TOKEN_RESERVED_WORD_CONFIG:
case ASTokenTypes.TOKEN_RESERVED_WORD_EXTENDS:
case ASTokenTypes.TOKEN_RESERVED_WORD_GET:
case ASTokenTypes.TOKEN_RESERVED_WORD_GOTO:
case ASTokenTypes.TOKEN_RESERVED_WORD_IMPLEMENTS:
case ASTokenTypes.TOKEN_RESERVED_WORD_NAMESPACE:
case ASTokenTypes.TOKEN_RESERVED_WORD_SET:
case ASTokenTypes.TOKEN_MODIFIER_ABSTRACT:
case ASTokenTypes.TOKEN_MODIFIER_DYNAMIC:
case ASTokenTypes.TOKEN_MODIFIER_FINAL:
case ASTokenTypes.TOKEN_MODIFIER_NATIVE:
case ASTokenTypes.TOKEN_MODIFIER_OVERRIDE:
case ASTokenTypes.TOKEN_MODIFIER_STATIC:
case ASTokenTypes.TOKEN_MODIFIER_VIRTUAL:
case ASTokenTypes.TOKEN_NAMESPACE_ANNOTATION: {
if (!skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_NOT_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_STRICT_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_STRICT_NOT_EQUAL:
case ASTokenTypes.TOKEN_OPERATOR_LESS_THAN:
case ASTokenTypes.TOKEN_OPERATOR_GREATER_THAN:
case ASTokenTypes.TOKEN_OPERATOR_LESS_THAN_EQUALS:
case ASTokenTypes.TOKEN_OPERATOR_GREATER_THAN_EQUALS:
case ASTokenTypes.TOKEN_OPERATOR_DIVISION:
case ASTokenTypes.TOKEN_OPERATOR_MODULO:
case ASTokenTypes.TOKEN_OPERATOR_TERNARY:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_AND:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_LEFT_SHIFT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_OR:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_XOR:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_AND:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_OR:
case ASTokenTypes.TOKEN_OPERATOR_NULLISH_COALESCING:
case ASTokenTypes.TOKEN_OPERATOR_PLUS_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_MINUS_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_MULTIPLICATION_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_DIVISION_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_MODULO_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_AND_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_LEFT_SHIFT_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_OR_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_RIGHT_SHIFT_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_XOR_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_AND_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_OR_ASSIGNMENT: {
if (settings.insertSpaceBeforeAndAfterBinaryOperators && !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_STAR: {
boolean isAnyType = checkTokenBeforeAnyType(prevTokenNotComment);
boolean isAnyVectorType = checkTokensForAnyVectorType(prevTokenNotComment, nextTokenNotComment);
if (!isAnyType && !isAnyVectorType && settings.insertSpaceBeforeAndAfterBinaryOperators
&& !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_PLUS:
case ASTokenTypes.TOKEN_OPERATOR_MINUS: {
boolean isUnary = checkTokenBeforePossibleUnaryOperator(prevTokenNotComment);
if (!isUnary && settings.insertSpaceBeforeAndAfterBinaryOperators
&& !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_COMMA: {
if (varOrConstChainLevel == blockStack.size()) {
inVarOrConstDeclaration = true;
}
if (settings.insertSpaceAfterCommaDelimiter && !skipWhitespaceBeforeNextSignificantToken) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT: {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
String trimmed = token.getText().substring(2).trim();
if (!skipFormatting && FORMATTER_TAG_OFF.equals(trimmed)) {
skipFormatting = true;
appendNewLines(builder, 1);
} else if (skipFormatting && FORMATTER_TAG_ON.equals(trimmed)) {
skipFormatting = false;
numRequiredNewLines = 0;
}
break;
}
case ASTokenTypes.TOKEN_ASDOC_COMMENT:
case ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT: {
if (!skipWhitespaceBeforeNextSignificantToken) {
if (nextTokenOrExtra != null && nextTokenOrExtra.getType() == TOKEN_TYPE_EXTRA) {
numRequiredNewLines = Math.max(0, countNewLinesInExtra(nextTokenOrExtra));
}
requiredSpace = true;
}
break;
}
}
}
if ((inPackageDeclaration || inClassDeclaration || inInterfaceDeclaration || inFunctionDeclaration)
&& nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN) {
blockOpenPending = true;
endIndentedStatement();
inPackageDeclaration = false;
inClassDeclaration = false;
inInterfaceDeclaration = false;
inFunctionDeclaration = false;
}
prevToken = token;
prevTokenOrExtra = prevToken;
if (prevToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
&& prevToken.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT
&& prevToken.getType() != ASTokenTypes.TOKEN_ASDOC_COMMENT) {
prevTokenNotComment = prevToken;
}
}
if (blockStack.size() > 0) {
throw new Exception("Unexpected end of file <" + filePath + ">. Blocks still considered open by formatter. This is a bug.");
}
return builder.toString();
}