You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by jo...@apache.org on 2022/07/28 23:08:12 UTC
[royale-compiler] branch develop updated: formatter: refactor .as and .mxml formatters into separate classes for easier maintenance
This is an automated email from the ASF dual-hosted git repository.
joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
The following commit(s) were added to refs/heads/develop by this push:
new 71626012b formatter: refactor .as and .mxml formatters into separate classes for easier maintenance
71626012b is described below
commit 71626012bc3b6ba8dcc3d83f50333f02ea8b72f8
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Thu Jul 28 16:07:56 2022 -0700
formatter: refactor .as and .mxml formatters into separate classes for easier maintenance
---
.../org/apache/royale/formatter/FORMATTER.java | 1766 +-------------------
.../ASTokenFormatter.java} | 1358 ++++-----------
.../formatter/internal/BaseTokenFormatter.java | 81 +
.../formatter/internal/MXMLTokenFormatter.java | 506 ++++++
4 files changed, 879 insertions(+), 2832 deletions(-)
diff --git a/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java b/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
index a0f71dcb2..469b08b61 100644
--- a/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
+++ b/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
@@ -21,16 +21,12 @@ package org.apache.royale.formatter;
import java.io.File;
import java.io.IOException;
-import java.io.StringReader;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -43,23 +39,7 @@ import org.apache.royale.compiler.common.VersionInfo;
import org.apache.royale.compiler.exceptions.ConfigurationException;
import org.apache.royale.compiler.filespecs.FileSpecification;
import org.apache.royale.compiler.internal.config.localization.LocalizationManager;
-import org.apache.royale.compiler.internal.parsing.as.ASParser;
-import org.apache.royale.compiler.internal.parsing.as.ASToken;
-import org.apache.royale.compiler.internal.parsing.as.ASTokenTypes;
-import org.apache.royale.compiler.internal.parsing.as.IncludeHandler;
-import org.apache.royale.compiler.internal.parsing.as.MetaDataPayloadToken;
-import org.apache.royale.compiler.internal.parsing.as.MetadataToken;
-import org.apache.royale.compiler.internal.parsing.as.MetadataTokenTypes;
-import org.apache.royale.compiler.internal.parsing.as.RepairingTokenBuffer;
-import org.apache.royale.compiler.internal.parsing.as.StreamingASTokenizer;
-import org.apache.royale.compiler.internal.parsing.mxml.MXMLToken;
-import org.apache.royale.compiler.internal.parsing.mxml.MXMLTokenizer;
-import org.apache.royale.compiler.internal.tree.as.FileNode;
import org.apache.royale.compiler.internal.workspaces.Workspace;
-import org.apache.royale.compiler.parsing.IASToken;
-import org.apache.royale.compiler.parsing.IMXMLToken;
-import org.apache.royale.compiler.parsing.MXMLTokenTypes;
-import org.apache.royale.compiler.problems.CompilerProblemSeverity;
import org.apache.royale.compiler.problems.ConfigurationProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
@@ -69,20 +49,17 @@ import org.apache.royale.formatter.config.ConfigurationBuffer;
import org.apache.royale.formatter.config.ConfigurationValue;
import org.apache.royale.formatter.config.Configurator;
import org.apache.royale.formatter.config.Semicolons;
+import org.apache.royale.formatter.internal.ASTokenFormatter;
+import org.apache.royale.formatter.internal.MXMLTokenFormatter;
import org.apache.royale.utils.FilenameNormalization;
/**
- * Formats .as source files.
+ * Formats .as and .mxml source files.
*/
public class FORMATTER {
- private static final int TOKEN_TYPE_EXTRA = 999999;
-
private static final String NEWLINE = System.getProperty("line.separator");
private static final String DEFAULT_VAR = "files";
private static final String L10N_CONFIG_PREFIX = "org.apache.royale.compiler.internal.config.configuration";
- private static final Pattern ASDOC_START_LINE_PATTERN = Pattern.compile("^\\*(\\s*)");
- private static final String FORMATTER_TAG_OFF = "@formatter:off";
- private static final String FORMATTER_TAG_ON = "@formatter:on";
static enum ExitCode {
SUCCESS(0), PRINT_HELP(1), FAILED_WITH_ERRORS(2), FAILED_WITH_EXCEPTIONS(3), FAILED_WITH_CONFIG_PROBLEMS(4);
@@ -222,9 +199,11 @@ public class FORMATTER {
filePath = FilenameNormalization.normalize(filePath);
String result = null;
if (filePath.endsWith(".mxml")) {
- result = formatMXMLTextInternal(filePath, text, problems);
+ MXMLTokenFormatter mxmlFormatter = new MXMLTokenFormatter(this);
+ result = mxmlFormatter.format(filePath, text, problems);
} else {
- result = formatAS3TextInternal(filePath, text, problems);
+ ASTokenFormatter asFormatter = new ASTokenFormatter(this);
+ result = asFormatter.format(filePath, text, problems);
}
if (insertFinalNewLine && result.charAt(result.length() - 1) != '\n') {
return result + '\n';
@@ -238,7 +217,8 @@ public class FORMATTER {
public String formatActionScriptText(String text, Collection<ICompilerProblem> problems) {
String filePath = FilenameNormalization.normalize("stdin.as");
- return formatAS3TextInternal(filePath, text, problems);
+ ASTokenFormatter asFormatter = new ASTokenFormatter(this);
+ return asFormatter.format(filePath, text, problems);
}
public String formatActionScriptText(String text) {
@@ -247,7 +227,8 @@ public class FORMATTER {
public String formatMXMLText(String text, Collection<ICompilerProblem> problems) {
String filePath = FilenameNormalization.normalize("stdin.mxml");
- return formatMXMLTextInternal(filePath, text, problems);
+ MXMLTokenFormatter mxmlFormatter = new MXMLTokenFormatter(this);
+ return mxmlFormatter.format(filePath, text, problems);
}
public String formatMXMLText(String text) {
@@ -396,1729 +377,4 @@ public class FORMATTER {
}
}
}
-
- private String formatMXMLScriptElement(String filePath, int line, String text,
- Collection<ICompilerProblem> problems) {
- String indent = "\t";
- if (insertSpaces) {
- indent = "";
- for (int i = 0; i < tabSize; i++) {
- indent += " ";
- }
- }
- StringBuilder builder = new StringBuilder();
- Pattern scriptPattern = Pattern.compile(
- "^<((?:mx|fx):(\\w+))>\\s*(<!\\[CDATA\\[)?((?:.|(?:\\r?\\n))*?)(?:\\]\\]>)?\\s*<\\/(?:mx|fx):(?:\\w+)>$");
- Matcher scriptMatcher = scriptPattern.matcher(text);
- if (!scriptMatcher.matches()) {
- return text;
- }
- if (problems == null) {
- // we need to know if there were problems because it means that we
- // need to return the original, unformatted text
- problems = new ArrayList<ICompilerProblem>();
- }
- String scriptTagText = scriptMatcher.group(1);
- String scriptTagName = scriptMatcher.group(2);
- String cdataText = scriptMatcher.group(3);
- String scriptText = scriptMatcher.group(4);
- boolean requireCdata = cdataText != null || "Script".equals(scriptTagName);
- String formattedScriptText = formatAS3TextInternal(filePath + "@Script[" + line + "]", scriptText, problems);
- if (!ignoreProblems && hasErrors(problems)) {
- return text;
- }
- if (formattedScriptText.length() > 0) {
- String[] formattedLines = formattedScriptText.split("\n");
- String lineIndent = requireCdata ? (indent + indent + indent) : (indent + indent);
- for (int i = 0; i < formattedLines.length; i++) {
- formattedLines[i] = lineIndent + formattedLines[i];
- }
- formattedScriptText = String.join("\n", formattedLines);
- }
- builder.append(indent);
- builder.append("<");
- builder.append(scriptTagText);
- builder.append(">\n");
- if (requireCdata) {
- builder.append(indent);
- builder.append(indent);
- builder.append("<![CDATA[\n");
- }
- if (formattedScriptText.length() > 0) {
- builder.append(formattedScriptText);
- builder.append("\n");
- }
- if (requireCdata) {
- builder.append(indent);
- builder.append(indent);
- builder.append("]]>\n");
- }
- builder.append(indent);
- builder.append("</");
- builder.append(scriptTagText);
- builder.append(">");
-
- return builder.toString();
- }
-
- private String formatAS3TextInternal(String filePath, String text, Collection<ICompilerProblem> problems) {
- if (problems == null) {
- problems = new ArrayList<ICompilerProblem>();
- }
-
- StringReader textReader = new StringReader(text);
- StreamingASTokenizer tokenizer = null;
- ASToken[] streamingTokens = null;
- try {
- tokenizer = StreamingASTokenizer.createForRepairingASTokenizer(textReader, filePath,
- IncludeHandler.creatDefaultIncludeHandler());
- tokenizer.setCollectComments(true);
- tokenizer.setFollowIncludes(false);
- streamingTokens = tokenizer.getTokens(textReader);
- } finally {
- IOUtils.closeQuietly(textReader);
- IOUtils.closeQuietly(tokenizer);
- }
-
- if (tokenizer.hasTokenizationProblems()) {
- problems.addAll(tokenizer.getTokenizationProblems());
- }
-
- if (!ignoreProblems && hasErrors(problems)) {
- return text;
- }
-
- // temporarily remove the comments from the token list because ASParser
- // doesn't know how to deal with them properly.
- // we'll add them back at the same locations after the parser is done.
- List<ASToken> comments = new ArrayList<ASToken>();
- List<ASToken> streamingTokensList = new ArrayList<ASToken>();
- for (ASToken token : streamingTokens) {
- if (token.getType() == ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- || token.getType() == ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT) {
- comments.add(token);
- } else {
- streamingTokensList.add(token);
- }
- }
-
- Workspace workspace = new Workspace();
- RepairingTokenBuffer buffer = new RepairingTokenBuffer(streamingTokensList.toArray(new ASToken[0]));
- ASParser parser = new ASParser(workspace, buffer);
- FileNode node = new FileNode(workspace);
- try {
- parser.file(node);
- } catch (Exception e) {
- parser = null;
- problems.add(new UnexpectedExceptionProblem(e));
- return text;
- }
-
- if (tokenizer.hasTokenizationProblems()) {
- problems.addAll(tokenizer.getTokenizationProblems());
- }
-
- if (parser.getSyntaxProblems().size() > 0) {
- problems.addAll(parser.getSyntaxProblems());
- }
-
- if (!ignoreProblems && hasErrors(problems)) {
- return text;
- }
-
- List<IASToken> repairedTokensList = new ArrayList<IASToken>(Arrays.asList(buffer.getTokens(true)));
- // restore the comments that were removed before parsing
- IASToken nextComment = null;
- for (int i = 0; i < repairedTokensList.size(); i++) {
- if (nextComment == null) {
- if (comments.size() == 0) {
- // no more comments to add
- break;
- }
- nextComment = comments.get(0);
- }
- IASToken currentToken = repairedTokensList.get(i);
- if (nextComment.getAbsoluteStart() <= currentToken.getAbsoluteStart()) {
- repairedTokensList.add(i, nextComment);
- nextComment = null;
- comments.remove(0);
- }
- }
- // there may be some comments left that didn't appear before any
- // of the repaired tokens, so add them all at the end
- repairedTokensList.addAll(comments);
-
- List<IASToken> tokens = insertExtraAS3Tokens(repairedTokensList, text);
- try {
- return parseTokens(filePath, tokens, node);
- } catch (Exception e) {
- if (problems != null) {
- System.err.println(e);
- e.printStackTrace(System.err);
- problems.add(new UnexpectedExceptionProblem(e));
- }
- return text;
- }
-
- }
-
- private List<IASToken> insertExtraAS3Tokens(List<IASToken> originalTokens, String text) {
- ArrayList<IASToken> tokens = new ArrayList<IASToken>();
- IASToken prevToken = null;
- for (IASToken token : originalTokens) {
- if (prevToken != null) {
-
- boolean skipSemicolon = token.getType() == ASTokenTypes.TOKEN_SEMICOLON && token.isImplicit()
- && prevToken != null && (prevToken.getType() == ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- || prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN);
- if (skipSemicolon) {
- continue;
- }
-
- int start = prevToken.getAbsoluteEnd();
- int end = token.getAbsoluteStart();
- if (end > start) {
- String tokenText = text.substring(start, end);
- ASToken extraToken = new ASToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getEndLine(),
- prevToken.getEndColumn(), tokenText);
- extraToken.setEndLine(token.getLine());
- extraToken.setEndLine(token.getColumn());
- tokens.add(extraToken);
- }
- }
- tokens.add(token);
- prevToken = token;
- }
- if (prevToken != null) {
- int start = prevToken.getAbsoluteEnd();
- int end = text.length();
- if (end > start) {
- String tokenText = text.substring(start, end);
- ASToken extraToken = new ASToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getEndLine(),
- prevToken.getEndColumn(), tokenText);
- extraToken.setEndLine(prevToken.getLine());
- extraToken.setEndLine(prevToken.getColumn());
- tokens.add(extraToken);
- }
- }
- return tokens;
- }
-
- private List<IMXMLToken> insertExtraMXMLTokens(IMXMLToken[] originalTokens, String text) {
- ArrayList<IMXMLToken> tokens = new ArrayList<IMXMLToken>();
- IMXMLToken prevToken = null;
- for (IMXMLToken token : originalTokens) {
- if (prevToken != null) {
- int start = prevToken.getEnd();
- int end = token.getStart();
- if (end > start) {
- String tokenText = text.substring(start, end);
- MXMLToken extraToken = new MXMLToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getLine(),
- prevToken.getColumn() + end - start, tokenText);
- extraToken.setEndLine(token.getLine());
- extraToken.setEndLine(token.getColumn());
- tokens.add(extraToken);
- }
- }
- tokens.add(token);
- prevToken = token;
- }
- if (prevToken != null) {
- int start = prevToken.getEnd();
- int end = text.length();
- if (end > start) {
- String tokenText = text.substring(start, end);
- MXMLToken extraToken = new MXMLToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getLine(),
- prevToken.getColumn() + end - start, tokenText);
- extraToken.setEndLine(prevToken.getLine());
- extraToken.setEndLine(prevToken.getColumn());
- tokens.add(extraToken);
- }
- }
- return tokens;
- }
-
- private IASToken getNextTokenSkipExtra(List<IASToken> tokens, int startIndex) {
- for (int i = startIndex; i < tokens.size(); i++) {
- IASToken token = tokens.get(i);
- if (token.getType() != TOKEN_TYPE_EXTRA) {
- return token;
- }
- }
- return null;
- }
-
- private IASToken getNextTokenSkipExtraAndComments(List<IASToken> tokens, int startIndex) {
- for (int i = startIndex; i < tokens.size(); i++) {
- IASToken token = tokens.get(i);
- if (token.getType() != TOKEN_TYPE_EXTRA && token.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- && token.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT
- && token.getType() != ASTokenTypes.TOKEN_ASDOC_COMMENT) {
- return token;
- }
- }
- return null;
- }
-
- private String parseTokens(String filePath, List<IASToken> tokens, FileNode node) throws Exception {
- int indent = 0;
- boolean inCaseOrDefaultClause = false;
- boolean inControlFlowStatement = false;
- boolean inVarOrConstDeclaration = false;
- boolean inFunctionDeclaration = false;
- boolean inPackageDeclaration = false;
- boolean inClassDeclaration = false;
- boolean inInterfaceDeclaration = false;
- boolean blockOpenPending = false;
- boolean indentedStatement = false;
- boolean caseOrDefaultBlockOpenPending = false;
- boolean skipFormatting = false;
- int varOrConstChainLevel = -1;
- List<BlockStackItem> blockStack = new ArrayList<BlockStackItem>();
- int controlFlowParenStack = 0;
- int ternaryStack = 0;
- int numRequiredNewLines = 0;
- boolean requiredSpace = false;
- IASToken prevTokenNotComment = null;
- IASToken prevToken = null;
- IASToken prevTokenOrExtra = null;
- IASToken token = null;
- IASToken nextToken = null;
- IASToken nextTokenOrExtra = null;
- IASToken nextTokenNotComment = null;
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < tokens.size(); i++) {
- token = tokens.get(i);
- 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) {
- 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 && 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) {
- indentedStatement = true;
- indent = increaseIndent(indent);
- }
- }
- }
- }
- prevTokenOrExtra = token;
- continue;
- }
- nextTokenOrExtra = ((i + 1) < tokens.size()) ? tokens.get(i + 1) : null;
- nextToken = getNextTokenSkipExtra(tokens, i + 1);
- nextTokenNotComment = getNextTokenSkipExtraAndComments(tokens, i + 1);
-
- boolean skipWhitespaceBeforeSemicolon = nextToken == null
- || nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON;
-
- // 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) {
- if (indentedStatement) {
- indentedStatement = false;
- indent = decreaseIndent(indent);
- }
- boolean oneLineBlock = nextToken != null
- && nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
- boolean needsNewLine = placeOpenBraceOnNewLine && (!collapseEmptyBlocks || !oneLineBlock);
- if (needsNewLine) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- } else {
- if (oneLineBlock && collapseEmptyBlocks) {
- numRequiredNewLines = 0;
- }
- requiredSpace = true;
- }
- } else {
- // probably an object literal
- blockStack.add(new ObjectLiteralBlockStackItem(token));
- indent = increaseIndent(indent);
- }
- requiredSpace = true;
- break;
- }
- case ASTokenTypes.TOKEN_BLOCK_CLOSE: {
- boolean skipSwitchDecrease = 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;
- if (!collapseEmptyBlocks || !oneLineBlock) {
- indent = decreaseIndent(indent);
- }
- if (stackItem.token.getType() == ASTokenTypes.TOKEN_KEYWORD_CASE
- || stackItem.token.getType() == ASTokenTypes.TOKEN_KEYWORD_DEFAULT) {
- blockStack.remove(blockStack.size() - 1);
- indent = decreaseIndent(indent);
- skipSwitchDecrease = true;
- }
- }
- }
- if (!skipSwitchDecrease && !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 item = blockStack.get(blockStack.size() - 1);
- if (item.token.getType() == ASTokenTypes.TOKEN_SQUARE_OPEN) {
- indent = decreaseIndent(indent);
- blockStack.remove(item);
- }
- }
- break;
- }
- case ASTokenTypes.TOKEN_PAREN_CLOSE: {
- if (!blockStack.isEmpty()) {
- BlockStackItem item = blockStack.get(blockStack.size() - 1);
- if (item.token.getType() == ASTokenTypes.TOKEN_PAREN_OPEN) {
- indent = decreaseIndent(indent);
- blockStack.remove(item);
- }
- }
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_AS:
- case ASTokenTypes.TOKEN_KEYWORD_IS:
- case ASTokenTypes.TOKEN_KEYWORD_IN:
- 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_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_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 (insertSpaceBeforeAndAfterBinaryOperators) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_OPERATOR_STAR: {
- boolean isAnyType = checkTokenBeforeAnyType(prevTokenNotComment);
- boolean isAnyVectorType = checkTokensForAnyVectorType(prevTokenNotComment, nextTokenNotComment);
- if (!isAnyType && !isAnyVectorType && insertSpaceBeforeAndAfterBinaryOperators
- && !skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_OPERATOR_PLUS:
- case ASTokenTypes.TOKEN_OPERATOR_MINUS: {
- boolean isUnary = checkTokenBeforeUnaryOperator(prevTokenNotComment);
- if (!isUnary && insertSpaceBeforeAndAfterBinaryOperators) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_OPERATOR_ASSIGNMENT: {
- inVarOrConstDeclaration = false;
- if (insertSpaceBeforeAndAfterBinaryOperators) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_OPERATOR_TERNARY: {
- ternaryStack++;
- if (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 BlockStackItem(token));
- }
- }
- break;
- }
- case ASTokenTypes.TOKEN_COLON: {
- if (ternaryStack > 0) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_SEMICOLON: {
- if (indentedStatement) {
- indentedStatement = false;
- indent = decreaseIndent(indent);
- }
- 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;
- if (placeOpenBraceOnNewLine && (!collapseEmptyBlocks || !oneLineBlock)) {
- indent = increaseIndent(indent);
- }
- }
- break;
- }
- }
-
- // include the token's own text
- builder.append(getTokenText(token, indent, skipFormatting));
-
- // 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 (insertSpaceAfterSemicolonInForStatements) {
- requiredSpace = true;
- }
- // else no space
- } else {
- boolean checkNext = true;
- 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) {
- 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);
- }
- }
- }
- }
- 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 (blockOpenPending) {
- blockOpenPending = false;
- if (!blockStack.isEmpty()) {
- BlockStackItem item = blockStack.get(blockStack.size() - 1);
- item.blockDepth++;
- }
- boolean oneLineBlock = nextToken != null
- && nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
- if (!collapseEmptyBlocks || !oneLineBlock) {
- if (!placeOpenBraceOnNewLine) {
- indent = increaseIndent(indent);
- }
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- }
- break;
- }
- case ASTokenTypes.TOKEN_BLOCK_CLOSE: {
- if (!blockStack.isEmpty()) {
- BlockStackItem item = blockStack.get(blockStack.size() - 1);
- item.blockDepth--;
- if (item.blockDepth <= 0) {
- blockStack.remove(blockStack.size() - 1);
- }
- if (!(item instanceof ObjectLiteralBlockStackItem)
- && (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:
- indent = increaseIndent(indent);
- blockStack.add(new BlockStackItem(token));
- break;
- case ASTokenTypes.TOKEN_PAREN_OPEN: {
- indent = increaseIndent(indent);
- blockStack.add(new BlockStackItem(token));
- if (inControlFlowStatement) {
- controlFlowParenStack++;
- }
- break;
- }
- case ASTokenTypes.TOKEN_PAREN_CLOSE: {
- if (inControlFlowStatement) {
- controlFlowParenStack--;
- if (controlFlowParenStack <= 0) {
- inControlFlowStatement = false;
- controlFlowParenStack = 0;
- blockOpenPending = true;
- if (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON) {
- blockStack.remove(blockStack.size() - 1);
- if (!skipWhitespaceBeforeSemicolon) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- } else if (nextToken != null && nextToken.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN
- && nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- && !skipWhitespaceBeforeSemicolon) {
- indent = increaseIndent(indent);
- BlockStackItem item = blockStack.get(blockStack.size() - 1);
- item.braces = false;
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- }
- }
- break;
- }
- case ASTokenTypes.TOKEN_OPERATOR_INCREMENT:
- case ASTokenTypes.TOKEN_OPERATOR_DECREMENT: {
- if (!inControlFlowStatement && prevToken != null
- && prevToken.getType() != ASTokenTypes.TOKEN_SEMICOLON && nextToken != null
- && nextToken.getType() != ASTokenTypes.TOKEN_SEMICOLON) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_CONTINUE:
- case ASTokenTypes.TOKEN_KEYWORD_BREAK:
- case ASTokenTypes.TOKEN_KEYWORD_RETURN: {
- if (!skipWhitespaceBeforeSemicolon) {
- 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 = !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;
- blockStack.add(new BlockStackItem(token));
- if (insertSpaceAfterKeywordsInControlFlowStatements && !skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_SWITCH: {
- inControlFlowStatement = true;
- blockStack.add(new SwitchBlockStackItem(token));
- if (insertSpaceAfterKeywordsInControlFlowStatements && !skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_TRY: {
- blockStack.add(new BlockStackItem(token));
- if (!skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- blockOpenPending = true;
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_ELSE: {
- if (nextTokenNotComment != null
- && nextTokenNotComment.getType() == ASTokenTypes.TOKEN_KEYWORD_IF) {
- requiredSpace = true;
- } else {
- blockStack.add(new BlockStackItem(token));
- blockOpenPending = true;
- if (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_SEMICOLON) {
- blockStack.remove(blockStack.size() - 1);
- if (!skipWhitespaceBeforeSemicolon) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- } else if (nextToken != null && nextToken.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN
- && nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- && !skipWhitespaceBeforeSemicolon) {
- indent = increaseIndent(indent);
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- }
- 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 (!skipWhitespaceBeforeSemicolon) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- } else if (nextToken != null && nextToken.getType() != ASTokenTypes.TOKEN_BLOCK_OPEN
- && nextToken.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- && !skipWhitespaceBeforeSemicolon) {
- indent = increaseIndent(indent);
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- break;
- }
- case ASTokenTypes.TOKEN_COLON: {
- if (!inControlFlowStatement && !inVarOrConstDeclaration && !inFunctionDeclaration) {
- if (inCaseOrDefaultClause) {
- inCaseOrDefaultClause = false;
- caseOrDefaultBlockOpenPending = true;
- boolean nextIsBlock = nextTokenNotComment != null
- && nextTokenNotComment.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN;
- if (nextIsBlock) {
- IASToken afterBlockClose = findTokenAfterBlock(nextTokenNotComment, tokens);
- if (afterBlockClose != null) {
- if (afterBlockClose.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE
- || afterBlockClose.getType() == ASTokenTypes.TOKEN_KEYWORD_CASE
- || afterBlockClose.getType() == ASTokenTypes.TOKEN_KEYWORD_DEFAULT) {
- blockOpenPending = true;
- requiredSpace = true;
- blockStack.remove(blockStack.size() - 1);
- }
- }
- }
- if (!nextIsBlock || !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 if (ternaryStack > 0) {
- ternaryStack--;
- requiredSpace = true;
- } else {
- requiredSpace = true;
- }
- }
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_CASE: {
- if (!skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_DEFAULT: {
- if (!inCaseOrDefaultClause && !skipWhitespaceBeforeSemicolon) {
- 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 (!skipWhitespaceBeforeSemicolon) {
- 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_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 (insertSpaceBeforeAndAfterBinaryOperators && !skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_OPERATOR_STAR: {
- boolean isAnyType = checkTokenBeforeAnyType(prevTokenNotComment);
- boolean isAnyVectorType = checkTokensForAnyVectorType(prevTokenNotComment, nextTokenNotComment);
- if (!isAnyType && !isAnyVectorType && insertSpaceBeforeAndAfterBinaryOperators
- && !skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_OPERATOR_PLUS:
- case ASTokenTypes.TOKEN_OPERATOR_MINUS: {
- boolean isUnary = checkTokenBeforeUnaryOperator(prevTokenNotComment);
- if (!isUnary && insertSpaceBeforeAndAfterBinaryOperators && !skipWhitespaceBeforeSemicolon) {
- requiredSpace = true;
- }
- break;
- }
- case ASTokenTypes.TOKEN_COMMA: {
- if (varOrConstChainLevel == blockStack.size()) {
- inVarOrConstDeclaration = true;
- }
- if (insertSpaceAfterCommaDelimiter && !skipWhitespaceBeforeSemicolon) {
- 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 (!skipWhitespaceBeforeSemicolon) {
- if (nextTokenOrExtra != null && nextTokenOrExtra.getType() == TOKEN_TYPE_EXTRA) {
- requiredSpace = true;
- }
- }
- break;
- }
- }
- }
- if ((inPackageDeclaration || inClassDeclaration || inInterfaceDeclaration || inFunctionDeclaration)
- && nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN) {
- blockOpenPending = true;
- 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("Block stack size too large");
- }
- return builder.toString();
- }
-
- private IASToken findTokenAfterBlock(IASToken tokenBlockOpen, List<IASToken> tokens) {
- List<IASToken> stack = new ArrayList<IASToken>();
- int startIndex = tokens.indexOf(tokenBlockOpen) + 1;
- for (int i = startIndex; i < tokens.size(); i++) {
- IASToken current = tokens.get(i);
- if (current.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN) {
- stack.add(current);
- } else if (current.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE) {
- if (stack.size() == 0) {
- return getNextTokenSkipExtraAndComments(tokens, i + 1);
- }
- stack.remove(stack.size() - 1);
- }
- }
- return null;
- }
-
- private int countNewLinesInExtra(IASToken tokenOrExtra) {
- if (tokenOrExtra == null || tokenOrExtra.getType() != TOKEN_TYPE_EXTRA) {
- return 0;
- }
- int numNewLinesInWhitespace = 0;
- String whitespace = tokenOrExtra.getText();
- int index = -1;
- while ((index = whitespace.indexOf('\n', index + 1)) != -1) {
- numNewLinesInWhitespace++;
- }
- return numNewLinesInWhitespace;
- }
-
- private String formatSingleLineComment(String comment) {
- comment = comment.substring(2).trim();
- StringBuilder builder = new StringBuilder();
- builder.append("//");
- if (insertSpaceAtStartOfLineComment) {
- builder.append(" ");
- }
- builder.append(comment);
- return builder.toString();
- }
-
- private String formatMultiLineComment(String comment) {
- return comment;
- }
-
- private String formatLiteralString(String string) {
- String charsToEscape = "\b\t\n\f\r\\";
- String escapeChars = "btnfr\\";
- int escapeIndex = -1;
- char currChar;
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < string.length(); ++i) {
- currChar = string.charAt(i);
- if (i == 0) {
- charsToEscape += currChar;
- escapeChars += currChar;
- builder.append(currChar);
- continue;
- }
- if (i == string.length() - 1) {
- builder.append(currChar);
- continue;
- }
- escapeIndex = charsToEscape.indexOf(currChar);
- if (escapeIndex != -1) {
- builder.append("\\");
- builder.append(escapeChars.charAt(escapeIndex));
- } else {
- builder.append(currChar);
- }
- }
- return builder.toString();
- }
-
- private boolean isInForStatement(List<BlockStackItem> blockStack) {
- for (int i = blockStack.size() - 1; i >= 0; i--) {
- BlockStackItem item = blockStack.get(i);
- switch (item.token.getType()) {
- case ASTokenTypes.TOKEN_BLOCK_OPEN:
- case ASTokenTypes.TOKEN_SQUARE_OPEN:
- case ASTokenTypes.TOKEN_PAREN_OPEN: {
- // these tokens are fine, keep searching
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_FOR: {
- return true;
- }
- default: {
- return false;
- }
- }
- }
- return false;
- }
-
- private boolean isInListing(String lineText, boolean alreadyInListing) {
- int searchIndex = 0;
- boolean inListing = alreadyInListing;
- while (searchIndex < lineText.length()) {
- if (!inListing) {
- searchIndex = lineText.indexOf("<listing", searchIndex);
- if (searchIndex == -1) {
- return false;
- }
- searchIndex += 8;
- inListing = true;
- }
- searchIndex = lineText.indexOf("</listing>", searchIndex);
- if (searchIndex == -1) {
- return true;
- }
- searchIndex += 10;
- inListing = false;
- }
- return inListing;
- }
-
- private String formatASDocComment(String comment, int indent) {
- String[] lines = comment.split("\n");
- StringBuilder builder = new StringBuilder();
- String lineText = lines[0].trim();
- builder.append(lineText);
- boolean inListing = isInListing(lineText, false);
- if (lines.length > 1) {
- builder.append('\n');
- }
- String listingIndent = null;
- for (int i = 1; i < lines.length - 1; i++) {
- lineText = lines[i].trim();
- if (inListing) {
- Matcher startMatcher = ASDOC_START_LINE_PATTERN.matcher(lineText);
- if (startMatcher.find()) {
- if (listingIndent == null) {
- listingIndent = startMatcher.group(1);
- } else if (startMatcher.group().length() >= lineText.length()) {
- lineText = "*" + listingIndent;
- }
- }
- }
- appendIndent(builder, indent);
- builder.append(' ');
- builder.append(lineText);
- builder.append('\n');
- inListing = isInListing(lineText, inListing);
- if (!inListing) {
- listingIndent = null;
- }
- }
- if (lines.length > 1) {
- appendIndent(builder, indent);
- builder.append(' ');
- builder.append(lines[lines.length - 1].trim());
- }
- return builder.toString();
- }
-
- private String getTokenText(IASToken token, int indent, boolean skipFormatting) {
-
- if (token instanceof MetaDataPayloadToken) {
- MetaDataPayloadToken metaPlayloadToken = (MetaDataPayloadToken) token;
- return formatMetadataToken(metaPlayloadToken);
- } else {
- switch (token.getType()) {
- case ASTokenTypes.TOKEN_ASDOC_COMMENT: {
- if (skipFormatting) {
- return token.getText();
- }
- return formatASDocComment(token.getText(), indent);
- }
- case ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT: {
- if (skipFormatting) {
- return token.getText();
- }
- return formatSingleLineComment(token.getText());
- }
- case ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT: {
- if (skipFormatting) {
- return token.getText();
- }
- return formatMultiLineComment(token.getText());
- }
- case ASTokenTypes.TOKEN_LITERAL_STRING: {
- return formatLiteralString(token.getText());
- }
- case ASTokenTypes.TOKEN_SEMICOLON: {
- if (skipFormatting) {
- return token.isImplicit() ? "" : token.getText();
- }
- boolean skipSemicolon = Semicolons.REMOVE.equals(semicolons)
- || (Semicolons.IGNORE.equals(semicolons) && token.isImplicit());
- if (!skipSemicolon) {
- return token.getText();
- }
- return null;
- }
- default: {
- return token.getText();
- }
- }
- }
- }
-
- private String formatMetadataToken(MetaDataPayloadToken token) {
- // metadata doesn't include all of its text as tokens, so we need to
- // insert some extra characters here and there
- StringBuilder builder = new StringBuilder();
- boolean needsComma = false;
- List<MetadataToken> payload = token.getPayload();
- for (int i = 0; i < payload.size(); i++) {
- MetadataToken metaToken = payload.get(i);
- switch (metaToken.getType()) {
- case MetadataTokenTypes.TOKEN_ATTR_NAME:
- case MetadataTokenTypes.TOKEN_ATTR_EVENT:
- case MetadataTokenTypes.TOKEN_ATTR_FORMAT:
- case MetadataTokenTypes.TOKEN_ATTR_TYPE:
- case MetadataTokenTypes.TOKEN_ATTR_ARRAY_TYPE:
- case MetadataTokenTypes.TOKEN_ATTR_INHERITS:
- case MetadataTokenTypes.TOKEN_ATTR_ENUM:
- case MetadataTokenTypes.TOKEN_ATTR_UNKNOWN:
- case MetadataTokenTypes.TOKEN_ATTR_ENV:
- case MetadataTokenTypes.TOKEN_ATTR_VERBOSE:
- case MetadataTokenTypes.TOKEN_ATTR_CATEGORY:
- case MetadataTokenTypes.TOKEN_ATTR_VARIABLE:
- case MetadataTokenTypes.TOKEN_ATTR_DEFAULT_VALUE:
- case MetadataTokenTypes.TOKEN_ATTR_STATES:
- case MetadataTokenTypes.TOKEN_ATTR_IMPLEMENTATION:
- case MetadataTokenTypes.TOKEN_ATTR_OPERATOR_NS_QUALIFIER: {
- if (needsComma) {
- builder.append(",");
- if (insertSpaceBetweenMetadataAttributes) {
- builder.append(" ");
- }
- }
- needsComma = true;
- builder.append(metaToken.getText());
- MetadataToken nextToken = payload.get(i + 1);
- if (nextToken.getType() == 8) {
- builder.append("=");
- builder.append("\"");
- builder.append(nextToken.getText());
- builder.append("\"");
- i++;
- }
- break;
- }
- case MetadataTokenTypes.TOKEN_STRING: {
- if (needsComma) {
- builder.append(",");
- if (insertSpaceBetweenMetadataAttributes) {
- builder.append(" ");
- }
- }
- builder.append("\"");
- builder.append(metaToken.getText());
- builder.append("\"");
- needsComma = true;
- break;
- }
- default: {
- builder.append(metaToken.getText());
- }
- }
- }
- return builder.toString();
- }
-
- private boolean checkTokenBeforeAnyType(IASToken token) {
- return token.getType() == ASTokenTypes.TOKEN_COLON;
- }
-
- private boolean checkTokensForAnyVectorType(IASToken prevToken, IASToken nextToken) {
- return prevToken != null && nextToken != null
- && ((prevToken.getType() == ASTokenTypes.TOKEN_TYPED_COLLECTION_OPEN
- && nextToken.getType() == ASTokenTypes.TOKEN_TYPED_COLLECTION_CLOSE)
- || (prevToken.getType() == ASTokenTypes.TOKEN_TYPED_LITERAL_OPEN
- && nextToken.getType() == ASTokenTypes.TOKEN_TYPED_LITERAL_CLOSE));
- }
-
- private boolean checkTokenBeforeUnaryOperator(IASToken token) {
- return (token instanceof ASToken) ? ((ASToken) token).isOperator()
- || token.getType() == ASTokenTypes.TOKEN_SQUARE_OPEN || token.getType() == ASTokenTypes.TOKEN_PAREN_OPEN
- || token.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN || token.getType() == ASTokenTypes.TOKEN_SEMICOLON
- || token.getType() == ASTokenTypes.TOKEN_KEYWORD_RETURN || token.getType() == ASTokenTypes.TOKEN_COMMA
- || token.getType() == ASTokenTypes.TOKEN_COLON : (token == null);
- }
-
- private int increaseIndent(int indent) {
- return indent + 1;
- }
-
- private int decreaseIndent(int indent) {
- return Math.max(0, indent - 1);
- }
-
- private String getIndent() {
- if (insertSpaces) {
- String result = "";
- for (int j = 0; j < tabSize; j++) {
- result += " ";
- }
- return result;
- }
- return "\t";
- }
-
- private String getAttributeIndent(IMXMLToken openTagToken) {
- if (!mxmlAlignAttributes) {
- return getIndent();
- }
- int indentSize = openTagToken.getText().length() + 1;
- String result = "";
- while (indentSize >= tabSize) {
- result += getIndent();
- indentSize -= tabSize;
- }
- for (int i = 0; i < indentSize; i++) {
- result += " ";
- }
- return result;
- }
-
- private void appendIndent(StringBuilder builder, int indent) {
- String indentString = getIndent();
- for (int i = 0; i < indent; i++) {
- builder.append(indentString);
- }
- }
-
- private void appendNewLines(StringBuilder builder, int numRequiredNewLines) {
- if (maxPreserveNewLines != 0) {
- numRequiredNewLines = Math.min(maxPreserveNewLines, numRequiredNewLines);
- }
- for (int j = 0; j < numRequiredNewLines; j++) {
- builder.append('\n');
- }
- }
-
- private boolean hasErrors(Collection<ICompilerProblem> problems) {
- CompilerProblemCategorizer categorizer = new CompilerProblemCategorizer(null);
- for (ICompilerProblem problem : problems) {
- CompilerProblemSeverity severity = categorizer.getProblemSeverity(problem);
- if (CompilerProblemSeverity.ERROR.equals(severity)) {
- return true;
- }
- }
- return false;
- }
-
- private static class BlockStackItem {
- public BlockStackItem(IASToken token) {
- this.token = token;
- }
-
- public IASToken token;
- public int blockDepth = 0;
- public boolean braces = true;
- }
-
- private static class ObjectLiteralBlockStackItem extends BlockStackItem {
- public ObjectLiteralBlockStackItem(IASToken token) {
- super(token);
- }
- }
-
- private static class SwitchBlockStackItem extends BlockStackItem {
- public SwitchBlockStackItem(IASToken token) {
- super(token);
- }
-
- public int clauseCount = 0;
- }
-
- private String formatMXMLTextInternal(String filePath, String text, Collection<ICompilerProblem> problems) {
- if (problems == null) {
- problems = new ArrayList<ICompilerProblem>();
- }
-
- StringReader textReader = new StringReader(text);
- MXMLTokenizer mxmlTokenizer = new MXMLTokenizer();
- IMXMLToken[] originalTokens = null;
- try {
- originalTokens = mxmlTokenizer.getTokens(textReader);
- } finally {
- IOUtils.closeQuietly(textReader);
- IOUtils.closeQuietly(mxmlTokenizer);
- }
-
- if (mxmlTokenizer.hasTokenizationProblems()) {
- problems.addAll(mxmlTokenizer.getTokenizationProblems());
- }
-
- if (!ignoreProblems && hasErrors(problems)) {
- return text;
- }
-
- Pattern scriptStartPattern = Pattern.compile("<((?:mx|fx):(Script|Metadata))");
-
- List<IMXMLToken> tokens = insertExtraMXMLTokens(originalTokens, text);
-
- int indent = 0;
- int numRequiredNewLines = 0;
- boolean requiredSpace = false;
- boolean inOpenTag = false;
- boolean inCloseTag = false;
- boolean skipFormatting = false;
- String attributeIndent = "";
- IMXMLToken prevToken = null;
- IMXMLToken prevTokenOrExtra = null;
- IMXMLToken token = null;
- IMXMLToken nextToken = null;
- List<ElementStackItem> elementStack = new ArrayList<ElementStackItem>();
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < tokens.size(); i++) {
- token = tokens.get(i);
- nextToken = null;
- if (i < (tokens.size() - 1)) {
- nextToken = tokens.get(i + 1);
- }
- 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;
- }
- numRequiredNewLines = Math.max(numRequiredNewLines, countNewLinesInExtra(token));
- }
- prevTokenOrExtra = token;
- continue;
- } else if (token.getType() == MXMLTokenTypes.TOKEN_WHITESPACE) {
- if (skipFormatting) {
- builder.append(token.getText());
- } else {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- numRequiredNewLines = Math.max(numRequiredNewLines, countNewLinesInExtra(token));
- } else {
- // if the parent element contains text, treat whitespace
- // the same as text, and don't reformat it
- // text is never reformatted because some components use it
- // without collapsing whitespace, and developers would be
- // confused if whitespace that they deliberately added were
- // to be removed
- builder.append(token.getText());
- }
- 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, numRequiredNewLines);
- appendNewLines(builder, numRequiredNewLines);
- }
- }
- continue;
- } else if (token.getType() == MXMLTokenTypes.TOKEN_OPEN_TAG_START
- && scriptStartPattern.matcher(token.getText()).matches()) {
-
- if (prevToken != null && numRequiredNewLines > 0) {
- appendNewLines(builder, numRequiredNewLines);
- }
- StringBuilder scriptBuilder = new StringBuilder();
- scriptBuilder.append(token.getText());
- boolean inScriptCloseTag = false;
- while (i < (tokens.size() - 1)) {
- i++;
- token = tokens.get(i);
- scriptBuilder.append(token.getText());
- if (token.getType() == MXMLTokenTypes.TOKEN_CLOSE_TAG_START) {
- inScriptCloseTag = true;
- } else if (inScriptCloseTag && token.getType() == MXMLTokenTypes.TOKEN_TAG_END) {
- break;
- }
- }
- if (problems == null) {
- // we need to know if there were problems because it means that we
- // need to return the original, unformatted text
- problems = new ArrayList<ICompilerProblem>();
- }
- builder.append(formatMXMLScriptElement(filePath, token.getLine(), scriptBuilder.toString(), problems));
- if (hasErrors(problems)) {
- return text;
- }
- prevToken = token;
- prevTokenOrExtra = token;
- requiredSpace = false;
- numRequiredNewLines = 1;
- continue;
- }
-
- // characters that must appear before the token
- switch (token.getType()) {
- case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
- inOpenTag = true;
- // if the parent contains text, children should be the same
- boolean containsText = !elementStack.isEmpty()
- && elementStack.get(elementStack.size() - 1).containsText;
- elementStack.add(new ElementStackItem(token, token.getText().substring(1), containsText));
- break;
- }
- case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- indent = decreaseIndent(indent);
- }
- inCloseTag = true;
- break;
- }
- case MXMLTokenTypes.TOKEN_NAME: {
- requiredSpace = true;
- break;
- }
- }
-
- if (!skipFormatting && prevToken != null) {
- if (numRequiredNewLines > 0) {
- appendNewLines(builder, numRequiredNewLines);
- appendIndent(builder, indent);
- if (attributeIndent.length() > 0) {
- builder.append(attributeIndent);
- }
- } else if (requiredSpace) {
- builder.append(' ');
- }
- }
-
- // include the token's own text
- // no token gets reformatted before being appended
- // whitespace is the only special case, but that's not handled here
- builder.append(token.getText());
-
- // characters that must appear after the token
- requiredSpace = false;
- numRequiredNewLines = 0;
-
- switch (token.getType()) {
- case MXMLTokenTypes.TOKEN_PROCESSING_INSTRUCTION: {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- break;
- }
- case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
- if (nextToken != null && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
- && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END
- && nextToken.getType() != TOKEN_TYPE_EXTRA) {
- requiredSpace = true;
- }
- if (elementStack.isEmpty()) {
- // something is very wrong!
- return text;
- }
- String elementName = token.getText().substring(2);
- ElementStackItem elementItem = elementStack.remove(elementStack.size() - 1);
- if (!elementName.equals(elementItem.elementName)) {
- // there's a unclosed tag with a different name somewhere
- return text;
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
- if (nextToken != null && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
- && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
- attributeIndent = getAttributeIndent(token);
- if (nextToken.getType() != TOKEN_TYPE_EXTRA) {
- requiredSpace = true;
- }
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_TAG_END: {
- if (inOpenTag) {
- ElementStackItem element = elementStack.get(elementStack.size() - 1);
- if (!element.containsText) {
- element.containsText = elementContainsText(tokens, i + 1, element.token);
- }
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- indent = increaseIndent(indent);
- }
- } else {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- }
- inOpenTag = false;
- attributeIndent = "";
- inCloseTag = false;
- break;
- }
- case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
- if (inOpenTag) {
- elementStack.remove(elementStack.size() - 1);
- } else {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- }
- inOpenTag = false;
- // no need to change nested indent after this tag
- // however, we may need to remove attribute indent
- attributeIndent = "";
- // we shouldn't find an empty close tag, but clear flag anyway
- inCloseTag = false;
- break;
- }
- case MXMLTokenTypes.TOKEN_STRING: {
- if (inOpenTag && mxmlInsertNewLineBetweenAttributes && nextToken != null
- && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
- && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_COMMENT: {
- String tokenText = token.getText();
- String trimmed = tokenText.substring(4, tokenText.length() - 3).trim();
- if (!skipFormatting && FORMATTER_TAG_OFF.equals(trimmed)) {
- skipFormatting = true;
- } else if (skipFormatting && FORMATTER_TAG_ON.equals(trimmed)) {
- skipFormatting = false;
- }
- break;
- }
- }
-
- prevToken = token;
- prevTokenOrExtra = token;
- }
-
- return builder.toString();
- }
-
- private boolean elementContainsText(List<IMXMLToken> tokens, int startIndex, IMXMLToken openTagToken) {
- ArrayList<IMXMLToken> elementStack = new ArrayList<IMXMLToken>();
- elementStack.add(openTagToken);
- for (int i = startIndex; i < tokens.size(); i++) {
- IMXMLToken token = tokens.get(i);
- switch (token.getType()) {
- case MXMLTokenTypes.TOKEN_TEXT: {
- if (elementStack.size() == 1) {
- return true;
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
- elementStack.add(token);
- break;
- }
- case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
- elementStack.remove(elementStack.size() - 1);
- if (elementStack.size() == 0) {
- return false;
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
- elementStack.remove(elementStack.size() - 1);
- if (elementStack.size() == 0) {
- return false;
- }
- break;
- }
- }
- }
- return false;
- }
-
- private int countNewLinesInExtra(IMXMLToken token) {
- if (token == null
- || (token.getType() != MXMLTokenTypes.TOKEN_WHITESPACE && token.getType() != TOKEN_TYPE_EXTRA)) {
- return 0;
- }
- int numNewLinesInWhitespace = 0;
- String whitespace = token.getText();
- int index = -1;
- while ((index = whitespace.indexOf('\n', index + 1)) != -1) {
- numNewLinesInWhitespace++;
- }
- return numNewLinesInWhitespace;
- }
-
- private static class ElementStackItem {
- public ElementStackItem(IMXMLToken token, String elementName, boolean containsText) {
- this.token = token;
- this.elementName = elementName;
- this.containsText = containsText;
- }
-
- public IMXMLToken token;
- public String elementName;
- public boolean containsText = false;
- }
}
\ No newline at end of file
diff --git a/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java b/formatter/src/main/java/org/apache/royale/formatter/internal/ASTokenFormatter.java
similarity index 59%
copy from formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
copy to formatter/src/main/java/org/apache/royale/formatter/internal/ASTokenFormatter.java
index a0f71dcb2..97c0b18f4 100644
--- a/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
+++ b/formatter/src/main/java/org/apache/royale/formatter/internal/ASTokenFormatter.java
@@ -17,32 +17,17 @@
//
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.formatter;
+package org.apache.royale.formatter.internal;
-import java.io.File;
-import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Scanner;
-import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
-import org.apache.royale.compiler.clients.problems.CompilerProblemCategorizer;
-import org.apache.royale.compiler.clients.problems.ProblemFormatter;
-import org.apache.royale.compiler.clients.problems.ProblemPrinter;
-import org.apache.royale.compiler.clients.problems.ProblemQuery;
-import org.apache.royale.compiler.clients.problems.WorkspaceProblemFormatter;
-import org.apache.royale.compiler.common.VersionInfo;
-import org.apache.royale.compiler.exceptions.ConfigurationException;
-import org.apache.royale.compiler.filespecs.FileSpecification;
-import org.apache.royale.compiler.internal.config.localization.LocalizationManager;
import org.apache.royale.compiler.internal.parsing.as.ASParser;
import org.apache.royale.compiler.internal.parsing.as.ASToken;
import org.apache.royale.compiler.internal.parsing.as.ASTokenTypes;
@@ -52,416 +37,51 @@ import org.apache.royale.compiler.internal.parsing.as.MetadataToken;
import org.apache.royale.compiler.internal.parsing.as.MetadataTokenTypes;
import org.apache.royale.compiler.internal.parsing.as.RepairingTokenBuffer;
import org.apache.royale.compiler.internal.parsing.as.StreamingASTokenizer;
-import org.apache.royale.compiler.internal.parsing.mxml.MXMLToken;
-import org.apache.royale.compiler.internal.parsing.mxml.MXMLTokenizer;
import org.apache.royale.compiler.internal.tree.as.FileNode;
import org.apache.royale.compiler.internal.workspaces.Workspace;
import org.apache.royale.compiler.parsing.IASToken;
-import org.apache.royale.compiler.parsing.IMXMLToken;
-import org.apache.royale.compiler.parsing.MXMLTokenTypes;
-import org.apache.royale.compiler.problems.CompilerProblemSeverity;
-import org.apache.royale.compiler.problems.ConfigurationProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
-import org.apache.royale.formatter.config.CommandLineConfigurator;
-import org.apache.royale.formatter.config.Configuration;
-import org.apache.royale.formatter.config.ConfigurationBuffer;
-import org.apache.royale.formatter.config.ConfigurationValue;
-import org.apache.royale.formatter.config.Configurator;
+import org.apache.royale.formatter.FORMATTER;
import org.apache.royale.formatter.config.Semicolons;
-import org.apache.royale.utils.FilenameNormalization;
-/**
- * Formats .as source files.
- */
-public class FORMATTER {
+public class ASTokenFormatter extends BaseTokenFormatter {
private static final int TOKEN_TYPE_EXTRA = 999999;
-
- private static final String NEWLINE = System.getProperty("line.separator");
- private static final String DEFAULT_VAR = "files";
- private static final String L10N_CONFIG_PREFIX = "org.apache.royale.compiler.internal.config.configuration";
private static final Pattern ASDOC_START_LINE_PATTERN = Pattern.compile("^\\*(\\s*)");
private static final String FORMATTER_TAG_OFF = "@formatter:off";
private static final String FORMATTER_TAG_ON = "@formatter:on";
- static enum ExitCode {
- SUCCESS(0), PRINT_HELP(1), FAILED_WITH_ERRORS(2), FAILED_WITH_EXCEPTIONS(3), FAILED_WITH_CONFIG_PROBLEMS(4);
-
- ExitCode(int code) {
- this.code = code;
- }
-
- final int code;
-
- int getCode() {
- return code;
- }
- }
-
- /**
- * Java program entry point.
- *
- * @param args command line arguments
- */
- public static void main(final String[] args) {
- FORMATTER formatter = new FORMATTER();
- int exitCode = formatter.execute(args);
- System.exit(exitCode);
- }
-
- public FORMATTER() {
-
- }
-
- public int tabSize = 4;
- public boolean insertSpaces = false;
- public boolean insertFinalNewLine = false;
- public boolean placeOpenBraceOnNewLine = true;
- public boolean insertSpaceAfterSemicolonInForStatements = true;
- public boolean insertSpaceAfterKeywordsInControlFlowStatements = true;
- public boolean insertSpaceAfterFunctionKeywordForAnonymousFunctions = false;
- public boolean insertSpaceBeforeAndAfterBinaryOperators = true;
- public boolean insertSpaceAfterCommaDelimiter = true;
- public boolean insertSpaceBetweenMetadataAttributes = true;
- public boolean insertSpaceAtStartOfLineComment = true;
- public int maxPreserveNewLines = 2;
- public Semicolons semicolons = Semicolons.INSERT;
- public boolean ignoreProblems = false;
- public boolean collapseEmptyBlocks = false;
- public boolean mxmlAlignAttributes = false;
- public boolean mxmlInsertNewLineBetweenAttributes = false;
-
- private ProblemQuery problemQuery;
- private List<File> inputFiles = new ArrayList<File>();
- private boolean writeBackToInputFiles = false;
- private boolean listChangedFiles = false;
- private Configuration configuration;
- private ConfigurationBuffer configBuffer;
-
- public int execute(String[] args) {
- ExitCode exitCode = ExitCode.SUCCESS;
- problemQuery = new ProblemQuery();
- problemQuery.setShowWarnings(false);
-
- try {
- boolean continueFormatting = configure(args, problemQuery);
- if (continueFormatting) {
- if (inputFiles.size() == 0) {
- StringBuilder builder = new StringBuilder();
- Scanner sysInScanner = new Scanner(System.in);
- try {
- while (sysInScanner.hasNext()) {
- builder.append(sysInScanner.next());
- }
- } finally {
- IOUtils.closeQuietly(sysInScanner);
- }
- String filePath = FilenameNormalization.normalize("stdin.as");
- String fileText = builder.toString();
- String formattedText = formatFileText(filePath, fileText, problemQuery.getProblems());
- if (!fileText.equals(formattedText)) {
- if (listChangedFiles) {
- System.out.println(filePath);
- }
- }
- if (!listChangedFiles) {
- System.out.println(formattedText);
- }
- } else {
- for (File inputFile : inputFiles) {
- String filePath = FilenameNormalization.normalize(inputFile.getAbsolutePath());
- FileSpecification fileSpec = new FileSpecification(filePath);
- String fileText = IOUtils.toString(fileSpec.createReader());
- String formattedText = formatFileText(filePath, fileText, problemQuery.getProblems());
- if (!fileText.equals(formattedText)) {
- if (listChangedFiles) {
- System.out.println(filePath);
- }
- if (writeBackToInputFiles) {
- FileUtils.write(inputFile, formattedText, "utf8");
- }
- }
- if (!listChangedFiles && !writeBackToInputFiles) {
- System.out.println(formattedText);
- }
- }
- }
- } else if (problemQuery.hasFilteredProblems()) {
- exitCode = ExitCode.FAILED_WITH_CONFIG_PROBLEMS;
- } else {
- exitCode = ExitCode.PRINT_HELP;
- }
- } catch (Exception e) {
- problemQuery.add(new UnexpectedExceptionProblem(e));
- System.err.println(e.getMessage());
- exitCode = ExitCode.FAILED_WITH_EXCEPTIONS;
- } finally {
- if (problemQuery.hasFilteredProblems()) {
- final Workspace workspace = new Workspace();
- final CompilerProblemCategorizer categorizer = new CompilerProblemCategorizer();
- final ProblemFormatter formatter = new WorkspaceProblemFormatter(workspace, categorizer);
- final ProblemPrinter printer = new ProblemPrinter(formatter);
- printer.printProblems(problemQuery.getFilteredProblems());
- }
- }
- return exitCode.getCode();
- }
-
- public String formatFile(File file, Collection<ICompilerProblem> problems) throws IOException {
- String filePath = FilenameNormalization.normalize(file.getAbsolutePath());
- FileSpecification fileSpec = new FileSpecification(filePath);
- String fileText = IOUtils.toString(fileSpec.createReader());
- return formatFileText(filePath, fileText, problems);
- }
-
- public String formatFile(File file) throws IOException {
- return formatFile(file, null);
- }
-
- public String formatFileText(String filePath, String text, Collection<ICompilerProblem> problems) {
- filePath = FilenameNormalization.normalize(filePath);
- String result = null;
- if (filePath.endsWith(".mxml")) {
- result = formatMXMLTextInternal(filePath, text, problems);
- } else {
- result = formatAS3TextInternal(filePath, text, problems);
- }
- if (insertFinalNewLine && result.charAt(result.length() - 1) != '\n') {
- return result + '\n';
- }
- return result;
- }
-
- public String formatFileText(String filePath, String text) {
- return formatFileText(filePath, text, null);
- }
-
- public String formatActionScriptText(String text, Collection<ICompilerProblem> problems) {
- String filePath = FilenameNormalization.normalize("stdin.as");
- return formatAS3TextInternal(filePath, text, problems);
- }
-
- public String formatActionScriptText(String text) {
- return formatActionScriptText(text, null);
- }
-
- public String formatMXMLText(String text, Collection<ICompilerProblem> problems) {
- String filePath = FilenameNormalization.normalize("stdin.mxml");
- return formatMXMLTextInternal(filePath, text, problems);
- }
-
- public String formatMXMLText(String text) {
- return formatMXMLText(text, null);
- }
-
- /**
- * Get the start up message that contains the program name with the copyright
- * notice.
- *
- * @return The startup message.
- */
- protected String getStartMessage() {
- // This message should not be localized.
- String message = "Apache Royale ActionScript Formatter (asformat)" + NEWLINE + VersionInfo.buildMessage()
- + NEWLINE;
- return message;
- }
-
- /**
- * Get my program name.
- *
- * @return always "asformat".
- */
- protected String getProgramName() {
- return "asformat";
- }
-
- /**
- * Print detailed help information if -help is provided.
- */
- private void processHelp(final List<ConfigurationValue> helpVar) {
- final Set<String> keywords = new LinkedHashSet<String>();
- if (helpVar != null) {
- for (final ConfigurationValue val : helpVar) {
- for (final Object element : val.getArgs()) {
- String keyword = (String) element;
- while (keyword.startsWith("-"))
- keyword = keyword.substring(1);
- keywords.add(keyword);
- }
- }
- }
-
- if (keywords.size() == 0)
- keywords.add("help");
-
- final String usages = CommandLineConfigurator.usage(getProgramName(), DEFAULT_VAR, configBuffer, keywords,
- LocalizationManager.get(), L10N_CONFIG_PREFIX);
- System.out.println(getStartMessage());
- System.out.println(usages);
- }
-
- private boolean configure(String[] args, ProblemQuery problems) {
- try {
- Configurator configurator = new Configurator();
- configurator.setConfiguration(args, "files");
- configuration = configurator.getConfiguration();
- configBuffer = configurator.getConfigurationBuffer();
-
- problems.addAll(configurator.getConfigurationProblems());
-
- if (configBuffer.getVar("version") != null) {
- System.out.println(VersionInfo.buildMessage());
- return false;
- }
-
- // Print help if "-help" is present.
- final List<ConfigurationValue> helpVar = configBuffer.getVar("help");
- if (helpVar != null || args.length == 0) {
- processHelp(helpVar);
- return false;
- }
-
- if (problems.hasErrors()) {
- return false;
- }
-
- collapseEmptyBlocks = configuration.getCollapseEmptyBlocks();
- ignoreProblems = configuration.getIgnoreParsingProblems();
- insertFinalNewLine = configuration.getInsertFinalNewLine();
- insertSpaceAfterCommaDelimiter = configuration.getInsertSpaceAfterCommaDelimiter();
- insertSpaceBetweenMetadataAttributes = configuration.getInsertSpaceBetweenMetadataAttributes();
- insertSpaceAfterFunctionKeywordForAnonymousFunctions = configuration
- .getInsertSpaceAfterFunctionKeywordForAnonymousFunctions();
- insertSpaceAfterKeywordsInControlFlowStatements = configuration
- .getInsertSpaceAfterKeywordsInControlFlowStatements();
- insertSpaceAfterSemicolonInForStatements = configuration.getInsertSpaceAfterSemicolonInForStatements();
- insertSpaceBeforeAndAfterBinaryOperators = configuration.getInsertSpaceBeforeAndAfterBinaryOperators();
- insertSpaceAtStartOfLineComment = configuration.getInsertSpaceAtStartOfLineComment();
- insertSpaces = configuration.getInsertSpaces();
- mxmlInsertNewLineBetweenAttributes = configuration.getMxmlInsertNewLineBetweenAttributes();
- mxmlAlignAttributes = configuration.getMxmlAlignAttributes();
- listChangedFiles = configuration.getListFiles();
- maxPreserveNewLines = configuration.getMaxPreserveNewLines();
- placeOpenBraceOnNewLine = configuration.getPlaceOpenBraceOnNewLine();
- semicolons = Semicolons.valueOf(configuration.getSemicolons().toUpperCase());
- tabSize = configuration.getTabSize();
- writeBackToInputFiles = configuration.getWriteFiles();
- for (String filePath : configuration.getFiles()) {
- File inputFile = new File(filePath);
- if (!inputFile.exists()) {
- throw new ConfigurationException("Input file does not exist: " + filePath, null, -1);
- }
- if (inputFile.isDirectory()) {
- addDirectory(inputFile);
- } else {
- inputFiles.add(inputFile);
- }
- }
- if (inputFiles.size() == 0 && listChangedFiles) {
- throw new ConfigurationException("Cannot use -list-files with standard input", null, -1);
- }
- if (writeBackToInputFiles) {
- if (inputFiles.size() == 0) {
- throw new ConfigurationException("Cannot use -write-files with standard input", null, -1);
- }
- for (File inputFile : inputFiles) {
- if (!inputFile.canWrite()) {
- throw new ConfigurationException("File is read-only: " + inputFile.getPath(), null, -1);
- }
- }
- }
- return true;
- } catch (ConfigurationException e) {
- final ICompilerProblem problem = new ConfigurationProblem(e);
- problems.add(problem);
- return false;
- } catch (Exception e) {
- final ICompilerProblem problem = new ConfigurationProblem(null, -1, -1, -1, -1, e.getMessage());
- problems.add(problem);
- return false;
- }
- }
-
- private void addDirectory(File inputFile) {
- for (File file : inputFile.listFiles()) {
- String fileName = file.getName();
- if (fileName.startsWith(".")) {
- continue;
- }
- if (file.isDirectory()) {
- addDirectory(file);
- } else if (fileName.endsWith(".as") || fileName.endsWith(".mxml")) {
- inputFiles.add(file);
- }
- }
- }
-
- private String formatMXMLScriptElement(String filePath, int line, String text,
- Collection<ICompilerProblem> problems) {
- String indent = "\t";
- if (insertSpaces) {
- indent = "";
- for (int i = 0; i < tabSize; i++) {
- indent += " ";
- }
- }
- StringBuilder builder = new StringBuilder();
- Pattern scriptPattern = Pattern.compile(
- "^<((?:mx|fx):(\\w+))>\\s*(<!\\[CDATA\\[)?((?:.|(?:\\r?\\n))*?)(?:\\]\\]>)?\\s*<\\/(?:mx|fx):(?:\\w+)>$");
- Matcher scriptMatcher = scriptPattern.matcher(text);
- if (!scriptMatcher.matches()) {
- return text;
- }
- if (problems == null) {
- // we need to know if there were problems because it means that we
- // need to return the original, unformatted text
- problems = new ArrayList<ICompilerProblem>();
- }
- String scriptTagText = scriptMatcher.group(1);
- String scriptTagName = scriptMatcher.group(2);
- String cdataText = scriptMatcher.group(3);
- String scriptText = scriptMatcher.group(4);
- boolean requireCdata = cdataText != null || "Script".equals(scriptTagName);
- String formattedScriptText = formatAS3TextInternal(filePath + "@Script[" + line + "]", scriptText, problems);
- if (!ignoreProblems && hasErrors(problems)) {
- return text;
- }
- if (formattedScriptText.length() > 0) {
- String[] formattedLines = formattedScriptText.split("\n");
- String lineIndent = requireCdata ? (indent + indent + indent) : (indent + indent);
- for (int i = 0; i < formattedLines.length; i++) {
- formattedLines[i] = lineIndent + formattedLines[i];
- }
- formattedScriptText = String.join("\n", formattedLines);
- }
- builder.append(indent);
- builder.append("<");
- builder.append(scriptTagText);
- builder.append(">\n");
- if (requireCdata) {
- builder.append(indent);
- builder.append(indent);
- builder.append("<![CDATA[\n");
- }
- if (formattedScriptText.length() > 0) {
- builder.append(formattedScriptText);
- builder.append("\n");
- }
- if (requireCdata) {
- builder.append(indent);
- builder.append(indent);
- builder.append("]]>\n");
- }
- builder.append(indent);
- builder.append("</");
- builder.append(scriptTagText);
- builder.append(">");
-
- return builder.toString();
+ public ASTokenFormatter(FORMATTER formatter) {
+ super(formatter);
}
- private String formatAS3TextInternal(String filePath, String text, Collection<ICompilerProblem> problems) {
+ private int indent;
+ private boolean inCaseOrDefaultClause;
+ private boolean inControlFlowStatement;
+ private boolean inVarOrConstDeclaration;
+ private boolean inFunctionDeclaration;
+ private boolean inPackageDeclaration;
+ private boolean inClassDeclaration;
+ private boolean inInterfaceDeclaration;
+ private boolean blockOpenPending;
+ private boolean indentedStatement;
+ private boolean caseOrDefaultBlockOpenPending;
+ private boolean skipFormatting;
+ private int varOrConstChainLevel;
+ private List<BlockStackItem> blockStack;
+ private int controlFlowParenStack;
+ private int ternaryStack;
+ private int numRequiredNewLines;
+ private boolean requiredSpace;
+ private IASToken prevTokenNotComment;
+ private IASToken prevToken;
+ private IASToken prevTokenOrExtra;
+ private IASToken token;
+ private IASToken nextToken;
+ private IASToken nextTokenOrExtra;
+ private IASToken nextTokenNotComment;
+
+ public String format(String filePath, String text, Collection<ICompilerProblem> problems) {
if (problems == null) {
problems = new ArrayList<ICompilerProblem>();
}
@@ -484,7 +104,7 @@ public class FORMATTER {
problems.addAll(tokenizer.getTokenizationProblems());
}
- if (!ignoreProblems && hasErrors(problems)) {
+ if (!formatter.ignoreProblems && hasErrors(problems)) {
return text;
}
@@ -522,7 +142,7 @@ public class FORMATTER {
problems.addAll(parser.getSyntaxProblems());
}
- if (!ignoreProblems && hasErrors(problems)) {
+ if (!formatter.ignoreProblems && hasErrors(problems)) {
return text;
}
@@ -550,7 +170,7 @@ public class FORMATTER {
List<IASToken> tokens = insertExtraAS3Tokens(repairedTokensList, text);
try {
- return parseTokens(filePath, tokens, node);
+ return parseTokens(tokens);
} catch (Exception e) {
if (problems != null) {
System.err.println(e);
@@ -559,133 +179,35 @@ public class FORMATTER {
}
return text;
}
-
- }
-
- private List<IASToken> insertExtraAS3Tokens(List<IASToken> originalTokens, String text) {
- ArrayList<IASToken> tokens = new ArrayList<IASToken>();
- IASToken prevToken = null;
- for (IASToken token : originalTokens) {
- if (prevToken != null) {
-
- boolean skipSemicolon = token.getType() == ASTokenTypes.TOKEN_SEMICOLON && token.isImplicit()
- && prevToken != null && (prevToken.getType() == ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- || prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN);
- if (skipSemicolon) {
- continue;
- }
-
- int start = prevToken.getAbsoluteEnd();
- int end = token.getAbsoluteStart();
- if (end > start) {
- String tokenText = text.substring(start, end);
- ASToken extraToken = new ASToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getEndLine(),
- prevToken.getEndColumn(), tokenText);
- extraToken.setEndLine(token.getLine());
- extraToken.setEndLine(token.getColumn());
- tokens.add(extraToken);
- }
- }
- tokens.add(token);
- prevToken = token;
- }
- if (prevToken != null) {
- int start = prevToken.getAbsoluteEnd();
- int end = text.length();
- if (end > start) {
- String tokenText = text.substring(start, end);
- ASToken extraToken = new ASToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getEndLine(),
- prevToken.getEndColumn(), tokenText);
- extraToken.setEndLine(prevToken.getLine());
- extraToken.setEndLine(prevToken.getColumn());
- tokens.add(extraToken);
- }
- }
- return tokens;
- }
-
- private List<IMXMLToken> insertExtraMXMLTokens(IMXMLToken[] originalTokens, String text) {
- ArrayList<IMXMLToken> tokens = new ArrayList<IMXMLToken>();
- IMXMLToken prevToken = null;
- for (IMXMLToken token : originalTokens) {
- if (prevToken != null) {
- int start = prevToken.getEnd();
- int end = token.getStart();
- if (end > start) {
- String tokenText = text.substring(start, end);
- MXMLToken extraToken = new MXMLToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getLine(),
- prevToken.getColumn() + end - start, tokenText);
- extraToken.setEndLine(token.getLine());
- extraToken.setEndLine(token.getColumn());
- tokens.add(extraToken);
- }
- }
- tokens.add(token);
- prevToken = token;
- }
- if (prevToken != null) {
- int start = prevToken.getEnd();
- int end = text.length();
- if (end > start) {
- String tokenText = text.substring(start, end);
- MXMLToken extraToken = new MXMLToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getLine(),
- prevToken.getColumn() + end - start, tokenText);
- extraToken.setEndLine(prevToken.getLine());
- extraToken.setEndLine(prevToken.getColumn());
- tokens.add(extraToken);
- }
- }
- return tokens;
- }
-
- private IASToken getNextTokenSkipExtra(List<IASToken> tokens, int startIndex) {
- for (int i = startIndex; i < tokens.size(); i++) {
- IASToken token = tokens.get(i);
- if (token.getType() != TOKEN_TYPE_EXTRA) {
- return token;
- }
- }
- return null;
}
- private IASToken getNextTokenSkipExtraAndComments(List<IASToken> tokens, int startIndex) {
- for (int i = startIndex; i < tokens.size(); i++) {
- IASToken token = tokens.get(i);
- if (token.getType() != TOKEN_TYPE_EXTRA && token.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
- && token.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT
- && token.getType() != ASTokenTypes.TOKEN_ASDOC_COMMENT) {
- return token;
- }
- }
- return null;
- }
+ private String parseTokens(List<IASToken> tokens) throws Exception {
+ indent = 0;
+ inCaseOrDefaultClause = false;
+ inControlFlowStatement = false;
+ inVarOrConstDeclaration = false;
+ inFunctionDeclaration = false;
+ inPackageDeclaration = false;
+ inClassDeclaration = false;
+ inInterfaceDeclaration = false;
+ blockOpenPending = 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;
- private String parseTokens(String filePath, List<IASToken> tokens, FileNode node) throws Exception {
- int indent = 0;
- boolean inCaseOrDefaultClause = false;
- boolean inControlFlowStatement = false;
- boolean inVarOrConstDeclaration = false;
- boolean inFunctionDeclaration = false;
- boolean inPackageDeclaration = false;
- boolean inClassDeclaration = false;
- boolean inInterfaceDeclaration = false;
- boolean blockOpenPending = false;
- boolean indentedStatement = false;
- boolean caseOrDefaultBlockOpenPending = false;
- boolean skipFormatting = false;
- int varOrConstChainLevel = -1;
- List<BlockStackItem> blockStack = new ArrayList<BlockStackItem>();
- int controlFlowParenStack = 0;
- int ternaryStack = 0;
- int numRequiredNewLines = 0;
- boolean requiredSpace = false;
- IASToken prevTokenNotComment = null;
- IASToken prevToken = null;
- IASToken prevTokenOrExtra = null;
- IASToken token = null;
- IASToken nextToken = null;
- IASToken nextTokenOrExtra = null;
- IASToken nextTokenNotComment = null;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < tokens.size(); i++) {
token = tokens.get(i);
@@ -707,7 +229,7 @@ public class FORMATTER {
}
boolean oneLineBlock = prevToken != null && prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN
&& nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
- if (oneLineBlock && collapseEmptyBlocks) {
+ if (oneLineBlock && formatter.collapseEmptyBlocks) {
newLinesInExtra = 0;
}
numRequiredNewLines = Math.max(numRequiredNewLines, newLinesInExtra);
@@ -769,11 +291,11 @@ public class FORMATTER {
}
boolean oneLineBlock = nextToken != null
&& nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
- boolean needsNewLine = placeOpenBraceOnNewLine && (!collapseEmptyBlocks || !oneLineBlock);
+ boolean needsNewLine = formatter.placeOpenBraceOnNewLine && (!formatter.collapseEmptyBlocks || !oneLineBlock);
if (needsNewLine) {
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
} else {
- if (oneLineBlock && collapseEmptyBlocks) {
+ if (oneLineBlock && formatter.collapseEmptyBlocks) {
numRequiredNewLines = 0;
}
requiredSpace = true;
@@ -793,7 +315,7 @@ public class FORMATTER {
if (stackItem.blockDepth <= 1) {
boolean oneLineBlock = prevToken != null
&& prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN;
- if (!collapseEmptyBlocks || !oneLineBlock) {
+ if (!formatter.collapseEmptyBlocks || !oneLineBlock) {
indent = decreaseIndent(indent);
}
if (stackItem.token.getType() == ASTokenTypes.TOKEN_KEYWORD_CASE
@@ -880,7 +402,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_XOR_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_AND_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_OR_ASSIGNMENT: {
- if (insertSpaceBeforeAndAfterBinaryOperators) {
+ if (formatter.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
@@ -888,7 +410,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_OPERATOR_STAR: {
boolean isAnyType = checkTokenBeforeAnyType(prevTokenNotComment);
boolean isAnyVectorType = checkTokensForAnyVectorType(prevTokenNotComment, nextTokenNotComment);
- if (!isAnyType && !isAnyVectorType && insertSpaceBeforeAndAfterBinaryOperators
+ if (!isAnyType && !isAnyVectorType && formatter.insertSpaceBeforeAndAfterBinaryOperators
&& !skipWhitespaceBeforeSemicolon) {
requiredSpace = true;
}
@@ -897,21 +419,21 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_OPERATOR_PLUS:
case ASTokenTypes.TOKEN_OPERATOR_MINUS: {
boolean isUnary = checkTokenBeforeUnaryOperator(prevTokenNotComment);
- if (!isUnary && insertSpaceBeforeAndAfterBinaryOperators) {
+ if (!isUnary && formatter.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_ASSIGNMENT: {
inVarOrConstDeclaration = false;
- if (insertSpaceBeforeAndAfterBinaryOperators) {
+ if (formatter.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
}
case ASTokenTypes.TOKEN_OPERATOR_TERNARY: {
ternaryStack++;
- if (insertSpaceBeforeAndAfterBinaryOperators) {
+ if (formatter.insertSpaceBeforeAndAfterBinaryOperators) {
requiredSpace = true;
}
break;
@@ -987,7 +509,7 @@ public class FORMATTER {
if (blockOpenPending) {
boolean oneLineBlock = nextToken != null
&& nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
- if (placeOpenBraceOnNewLine && (!collapseEmptyBlocks || !oneLineBlock)) {
+ if (formatter.placeOpenBraceOnNewLine && (!formatter.collapseEmptyBlocks || !oneLineBlock)) {
indent = increaseIndent(indent);
}
}
@@ -1018,7 +540,7 @@ public class FORMATTER {
switch (token.getType()) {
case ASTokenTypes.TOKEN_SEMICOLON: {
if (inControlFlowStatement && isInForStatement(blockStack)) {
- if (insertSpaceAfterSemicolonInForStatements) {
+ if (formatter.insertSpaceAfterSemicolonInForStatements) {
requiredSpace = true;
}
// else no space
@@ -1060,8 +582,8 @@ public class FORMATTER {
}
boolean oneLineBlock = nextToken != null
&& nextToken.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE;
- if (!collapseEmptyBlocks || !oneLineBlock) {
- if (!placeOpenBraceOnNewLine) {
+ if (!formatter.collapseEmptyBlocks || !oneLineBlock) {
+ if (!formatter.placeOpenBraceOnNewLine) {
indent = increaseIndent(indent);
}
numRequiredNewLines = Math.max(numRequiredNewLines, 1);
@@ -1161,7 +683,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_KEYWORD_FUNCTION: {
blockStack.add(new BlockStackItem(token));
inFunctionDeclaration = true;
- boolean skipSpace = !insertSpaceAfterFunctionKeywordForAnonymousFunctions
+ boolean skipSpace = !formatter.insertSpaceAfterFunctionKeywordForAnonymousFunctions
&& (nextToken != null && nextToken.getType() == ASTokenTypes.TOKEN_PAREN_OPEN);
if (!skipSpace) {
requiredSpace = true;
@@ -1182,7 +704,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_KEYWORD_WITH: {
inControlFlowStatement = true;
blockStack.add(new BlockStackItem(token));
- if (insertSpaceAfterKeywordsInControlFlowStatements && !skipWhitespaceBeforeSemicolon) {
+ if (formatter.insertSpaceAfterKeywordsInControlFlowStatements && !skipWhitespaceBeforeSemicolon) {
requiredSpace = true;
}
break;
@@ -1190,7 +712,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_KEYWORD_SWITCH: {
inControlFlowStatement = true;
blockStack.add(new SwitchBlockStackItem(token));
- if (insertSpaceAfterKeywordsInControlFlowStatements && !skipWhitespaceBeforeSemicolon) {
+ if (formatter.insertSpaceAfterKeywordsInControlFlowStatements && !skipWhitespaceBeforeSemicolon) {
requiredSpace = true;
}
break;
@@ -1354,7 +876,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_OPERATOR_BITWISE_XOR_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_AND_ASSIGNMENT:
case ASTokenTypes.TOKEN_OPERATOR_LOGICAL_OR_ASSIGNMENT: {
- if (insertSpaceBeforeAndAfterBinaryOperators && !skipWhitespaceBeforeSemicolon) {
+ if (formatter.insertSpaceBeforeAndAfterBinaryOperators && !skipWhitespaceBeforeSemicolon) {
requiredSpace = true;
}
break;
@@ -1362,7 +884,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_OPERATOR_STAR: {
boolean isAnyType = checkTokenBeforeAnyType(prevTokenNotComment);
boolean isAnyVectorType = checkTokensForAnyVectorType(prevTokenNotComment, nextTokenNotComment);
- if (!isAnyType && !isAnyVectorType && insertSpaceBeforeAndAfterBinaryOperators
+ if (!isAnyType && !isAnyVectorType && formatter.insertSpaceBeforeAndAfterBinaryOperators
&& !skipWhitespaceBeforeSemicolon) {
requiredSpace = true;
}
@@ -1371,7 +893,7 @@ public class FORMATTER {
case ASTokenTypes.TOKEN_OPERATOR_PLUS:
case ASTokenTypes.TOKEN_OPERATOR_MINUS: {
boolean isUnary = checkTokenBeforeUnaryOperator(prevTokenNotComment);
- if (!isUnary && insertSpaceBeforeAndAfterBinaryOperators && !skipWhitespaceBeforeSemicolon) {
+ if (!isUnary && formatter.insertSpaceBeforeAndAfterBinaryOperators && !skipWhitespaceBeforeSemicolon) {
requiredSpace = true;
}
break;
@@ -1380,7 +902,7 @@ public class FORMATTER {
if (varOrConstChainLevel == blockStack.size()) {
inVarOrConstDeclaration = true;
}
- if (insertSpaceAfterCommaDelimiter && !skipWhitespaceBeforeSemicolon) {
+ if (formatter.insertSpaceAfterCommaDelimiter && !skipWhitespaceBeforeSemicolon) {
requiredSpace = true;
}
break;
@@ -1431,164 +953,29 @@ public class FORMATTER {
return builder.toString();
}
- private IASToken findTokenAfterBlock(IASToken tokenBlockOpen, List<IASToken> tokens) {
- List<IASToken> stack = new ArrayList<IASToken>();
- int startIndex = tokens.indexOf(tokenBlockOpen) + 1;
+ private IASToken getNextTokenSkipExtra(List<IASToken> tokens, int startIndex) {
for (int i = startIndex; i < tokens.size(); i++) {
- IASToken current = tokens.get(i);
- if (current.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN) {
- stack.add(current);
- } else if (current.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE) {
- if (stack.size() == 0) {
- return getNextTokenSkipExtraAndComments(tokens, i + 1);
- }
- stack.remove(stack.size() - 1);
+ IASToken token = tokens.get(i);
+ if (token.getType() != TOKEN_TYPE_EXTRA) {
+ return token;
}
}
return null;
}
- private int countNewLinesInExtra(IASToken tokenOrExtra) {
- if (tokenOrExtra == null || tokenOrExtra.getType() != TOKEN_TYPE_EXTRA) {
- return 0;
- }
- int numNewLinesInWhitespace = 0;
- String whitespace = tokenOrExtra.getText();
- int index = -1;
- while ((index = whitespace.indexOf('\n', index + 1)) != -1) {
- numNewLinesInWhitespace++;
- }
- return numNewLinesInWhitespace;
- }
-
- private String formatSingleLineComment(String comment) {
- comment = comment.substring(2).trim();
- StringBuilder builder = new StringBuilder();
- builder.append("//");
- if (insertSpaceAtStartOfLineComment) {
- builder.append(" ");
+ private IASToken getNextTokenSkipExtraAndComments(List<IASToken> tokens, int startIndex) {
+ for (int i = startIndex; i < tokens.size(); i++) {
+ IASToken token = tokens.get(i);
+ if (token.getType() != TOKEN_TYPE_EXTRA && token.getType() != ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
+ && token.getType() != ASTokenTypes.HIDDEN_TOKEN_MULTI_LINE_COMMENT
+ && token.getType() != ASTokenTypes.TOKEN_ASDOC_COMMENT) {
+ return token;
+ }
}
- builder.append(comment);
- return builder.toString();
- }
-
- private String formatMultiLineComment(String comment) {
- return comment;
- }
-
- private String formatLiteralString(String string) {
- String charsToEscape = "\b\t\n\f\r\\";
- String escapeChars = "btnfr\\";
- int escapeIndex = -1;
- char currChar;
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < string.length(); ++i) {
- currChar = string.charAt(i);
- if (i == 0) {
- charsToEscape += currChar;
- escapeChars += currChar;
- builder.append(currChar);
- continue;
- }
- if (i == string.length() - 1) {
- builder.append(currChar);
- continue;
- }
- escapeIndex = charsToEscape.indexOf(currChar);
- if (escapeIndex != -1) {
- builder.append("\\");
- builder.append(escapeChars.charAt(escapeIndex));
- } else {
- builder.append(currChar);
- }
- }
- return builder.toString();
- }
-
- private boolean isInForStatement(List<BlockStackItem> blockStack) {
- for (int i = blockStack.size() - 1; i >= 0; i--) {
- BlockStackItem item = blockStack.get(i);
- switch (item.token.getType()) {
- case ASTokenTypes.TOKEN_BLOCK_OPEN:
- case ASTokenTypes.TOKEN_SQUARE_OPEN:
- case ASTokenTypes.TOKEN_PAREN_OPEN: {
- // these tokens are fine, keep searching
- break;
- }
- case ASTokenTypes.TOKEN_KEYWORD_FOR: {
- return true;
- }
- default: {
- return false;
- }
- }
- }
- return false;
- }
-
- private boolean isInListing(String lineText, boolean alreadyInListing) {
- int searchIndex = 0;
- boolean inListing = alreadyInListing;
- while (searchIndex < lineText.length()) {
- if (!inListing) {
- searchIndex = lineText.indexOf("<listing", searchIndex);
- if (searchIndex == -1) {
- return false;
- }
- searchIndex += 8;
- inListing = true;
- }
- searchIndex = lineText.indexOf("</listing>", searchIndex);
- if (searchIndex == -1) {
- return true;
- }
- searchIndex += 10;
- inListing = false;
- }
- return inListing;
- }
-
- private String formatASDocComment(String comment, int indent) {
- String[] lines = comment.split("\n");
- StringBuilder builder = new StringBuilder();
- String lineText = lines[0].trim();
- builder.append(lineText);
- boolean inListing = isInListing(lineText, false);
- if (lines.length > 1) {
- builder.append('\n');
- }
- String listingIndent = null;
- for (int i = 1; i < lines.length - 1; i++) {
- lineText = lines[i].trim();
- if (inListing) {
- Matcher startMatcher = ASDOC_START_LINE_PATTERN.matcher(lineText);
- if (startMatcher.find()) {
- if (listingIndent == null) {
- listingIndent = startMatcher.group(1);
- } else if (startMatcher.group().length() >= lineText.length()) {
- lineText = "*" + listingIndent;
- }
- }
- }
- appendIndent(builder, indent);
- builder.append(' ');
- builder.append(lineText);
- builder.append('\n');
- inListing = isInListing(lineText, inListing);
- if (!inListing) {
- listingIndent = null;
- }
- }
- if (lines.length > 1) {
- appendIndent(builder, indent);
- builder.append(' ');
- builder.append(lines[lines.length - 1].trim());
- }
- return builder.toString();
+ return null;
}
private String getTokenText(IASToken token, int indent, boolean skipFormatting) {
-
if (token instanceof MetaDataPayloadToken) {
MetaDataPayloadToken metaPlayloadToken = (MetaDataPayloadToken) token;
return formatMetadataToken(metaPlayloadToken);
@@ -1619,8 +1006,8 @@ public class FORMATTER {
if (skipFormatting) {
return token.isImplicit() ? "" : token.getText();
}
- boolean skipSemicolon = Semicolons.REMOVE.equals(semicolons)
- || (Semicolons.IGNORE.equals(semicolons) && token.isImplicit());
+ boolean skipSemicolon = Semicolons.REMOVE.equals(formatter.semicolons)
+ || (Semicolons.IGNORE.equals(formatter.semicolons) && token.isImplicit());
if (!skipSemicolon) {
return token.getText();
}
@@ -1660,7 +1047,7 @@ public class FORMATTER {
case MetadataTokenTypes.TOKEN_ATTR_OPERATOR_NS_QUALIFIER: {
if (needsComma) {
builder.append(",");
- if (insertSpaceBetweenMetadataAttributes) {
+ if (formatter.insertSpaceBetweenMetadataAttributes) {
builder.append(" ");
}
}
@@ -1679,7 +1066,7 @@ public class FORMATTER {
case MetadataTokenTypes.TOKEN_STRING: {
if (needsComma) {
builder.append(",");
- if (insertSpaceBetweenMetadataAttributes) {
+ if (formatter.insertSpaceBetweenMetadataAttributes) {
builder.append(" ");
}
}
@@ -1697,6 +1084,111 @@ public class FORMATTER {
return builder.toString();
}
+ private String formatSingleLineComment(String comment) {
+ comment = comment.substring(2).trim();
+ StringBuilder builder = new StringBuilder();
+ builder.append("//");
+ if (formatter.insertSpaceAtStartOfLineComment) {
+ builder.append(" ");
+ }
+ builder.append(comment);
+ return builder.toString();
+ }
+
+ private String formatMultiLineComment(String comment) {
+ return comment;
+ }
+
+ private String formatLiteralString(String string) {
+ String charsToEscape = "\b\t\n\f\r\\";
+ String escapeChars = "btnfr\\";
+ int escapeIndex = -1;
+ char currChar;
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < string.length(); ++i) {
+ currChar = string.charAt(i);
+ if (i == 0) {
+ charsToEscape += currChar;
+ escapeChars += currChar;
+ builder.append(currChar);
+ continue;
+ }
+ if (i == string.length() - 1) {
+ builder.append(currChar);
+ continue;
+ }
+ escapeIndex = charsToEscape.indexOf(currChar);
+ if (escapeIndex != -1) {
+ builder.append("\\");
+ builder.append(escapeChars.charAt(escapeIndex));
+ } else {
+ builder.append(currChar);
+ }
+ }
+ return builder.toString();
+ }
+
+ private boolean isInListing(String lineText, boolean alreadyInListing) {
+ int searchIndex = 0;
+ boolean inListing = alreadyInListing;
+ while (searchIndex < lineText.length()) {
+ if (!inListing) {
+ searchIndex = lineText.indexOf("<listing", searchIndex);
+ if (searchIndex == -1) {
+ return false;
+ }
+ searchIndex += 8;
+ inListing = true;
+ }
+ searchIndex = lineText.indexOf("</listing>", searchIndex);
+ if (searchIndex == -1) {
+ return true;
+ }
+ searchIndex += 10;
+ inListing = false;
+ }
+ return inListing;
+ }
+
+ private String formatASDocComment(String comment, int indent) {
+ String[] lines = comment.split("\n");
+ StringBuilder builder = new StringBuilder();
+ String lineText = lines[0].trim();
+ builder.append(lineText);
+ boolean inListing = isInListing(lineText, false);
+ if (lines.length > 1) {
+ builder.append('\n');
+ }
+ String listingIndent = null;
+ for (int i = 1; i < lines.length - 1; i++) {
+ lineText = lines[i].trim();
+ if (inListing) {
+ Matcher startMatcher = ASDOC_START_LINE_PATTERN.matcher(lineText);
+ if (startMatcher.find()) {
+ if (listingIndent == null) {
+ listingIndent = startMatcher.group(1);
+ } else if (startMatcher.group().length() >= lineText.length()) {
+ lineText = "*" + listingIndent;
+ }
+ }
+ }
+ appendIndent(builder, indent);
+ builder.append(' ');
+ builder.append(lineText);
+ builder.append('\n');
+ inListing = isInListing(lineText, inListing);
+ if (!inListing) {
+ listingIndent = null;
+ }
+ }
+ if (lines.length > 1) {
+ appendIndent(builder, indent);
+ builder.append(' ');
+ builder.append(lines[lines.length - 1].trim());
+ }
+ return builder.toString();
+ }
+
private boolean checkTokenBeforeAnyType(IASToken token) {
return token.getType() == ASTokenTypes.TOKEN_COLON;
}
@@ -1717,66 +1209,97 @@ public class FORMATTER {
|| token.getType() == ASTokenTypes.TOKEN_COLON : (token == null);
}
- private int increaseIndent(int indent) {
- return indent + 1;
- }
-
- private int decreaseIndent(int indent) {
- return Math.max(0, indent - 1);
+ private boolean isInForStatement(List<BlockStackItem> blockStack) {
+ for (int i = blockStack.size() - 1; i >= 0; i--) {
+ BlockStackItem item = blockStack.get(i);
+ switch (item.token.getType()) {
+ case ASTokenTypes.TOKEN_BLOCK_OPEN:
+ case ASTokenTypes.TOKEN_SQUARE_OPEN:
+ case ASTokenTypes.TOKEN_PAREN_OPEN: {
+ // these tokens are fine, keep searching
+ break;
+ }
+ case ASTokenTypes.TOKEN_KEYWORD_FOR: {
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+ }
+ return false;
}
- private String getIndent() {
- if (insertSpaces) {
- String result = "";
- for (int j = 0; j < tabSize; j++) {
- result += " ";
+ private IASToken findTokenAfterBlock(IASToken tokenBlockOpen, List<IASToken> tokens) {
+ List<IASToken> stack = new ArrayList<IASToken>();
+ int startIndex = tokens.indexOf(tokenBlockOpen) + 1;
+ for (int i = startIndex; i < tokens.size(); i++) {
+ IASToken current = tokens.get(i);
+ if (current.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN) {
+ stack.add(current);
+ } else if (current.getType() == ASTokenTypes.TOKEN_BLOCK_CLOSE) {
+ if (stack.size() == 0) {
+ return getNextTokenSkipExtraAndComments(tokens, i + 1);
+ }
+ stack.remove(stack.size() - 1);
}
- return result;
}
- return "\t";
+ return null;
}
- private String getAttributeIndent(IMXMLToken openTagToken) {
- if (!mxmlAlignAttributes) {
- return getIndent();
- }
- int indentSize = openTagToken.getText().length() + 1;
- String result = "";
- while (indentSize >= tabSize) {
- result += getIndent();
- indentSize -= tabSize;
+ private int countNewLinesInExtra(IASToken tokenOrExtra) {
+ if (tokenOrExtra == null || tokenOrExtra.getType() != TOKEN_TYPE_EXTRA) {
+ return 0;
}
- for (int i = 0; i < indentSize; i++) {
- result += " ";
+ int numNewLinesInWhitespace = 0;
+ String whitespace = tokenOrExtra.getText();
+ int index = -1;
+ while ((index = whitespace.indexOf('\n', index + 1)) != -1) {
+ numNewLinesInWhitespace++;
}
- return result;
+ return numNewLinesInWhitespace;
}
- private void appendIndent(StringBuilder builder, int indent) {
- String indentString = getIndent();
- for (int i = 0; i < indent; i++) {
- builder.append(indentString);
- }
- }
+ private List<IASToken> insertExtraAS3Tokens(List<IASToken> originalTokens, String text) {
+ ArrayList<IASToken> tokens = new ArrayList<IASToken>();
+ IASToken prevToken = null;
+ for (IASToken token : originalTokens) {
+ if (prevToken != null) {
- private void appendNewLines(StringBuilder builder, int numRequiredNewLines) {
- if (maxPreserveNewLines != 0) {
- numRequiredNewLines = Math.min(maxPreserveNewLines, numRequiredNewLines);
- }
- for (int j = 0; j < numRequiredNewLines; j++) {
- builder.append('\n');
- }
- }
+ boolean skipSemicolon = token.getType() == ASTokenTypes.TOKEN_SEMICOLON && token.isImplicit()
+ && prevToken != null && (prevToken.getType() == ASTokenTypes.HIDDEN_TOKEN_SINGLE_LINE_COMMENT
+ || prevToken.getType() == ASTokenTypes.TOKEN_BLOCK_OPEN);
+ if (skipSemicolon) {
+ continue;
+ }
- private boolean hasErrors(Collection<ICompilerProblem> problems) {
- CompilerProblemCategorizer categorizer = new CompilerProblemCategorizer(null);
- for (ICompilerProblem problem : problems) {
- CompilerProblemSeverity severity = categorizer.getProblemSeverity(problem);
- if (CompilerProblemSeverity.ERROR.equals(severity)) {
- return true;
+ int start = prevToken.getAbsoluteEnd();
+ int end = token.getAbsoluteStart();
+ if (end > start) {
+ String tokenText = text.substring(start, end);
+ ASToken extraToken = new ASToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getEndLine(),
+ prevToken.getEndColumn(), tokenText);
+ extraToken.setEndLine(token.getLine());
+ extraToken.setEndLine(token.getColumn());
+ tokens.add(extraToken);
+ }
}
+ tokens.add(token);
+ prevToken = token;
}
- return false;
+ if (prevToken != null) {
+ int start = prevToken.getAbsoluteEnd();
+ int end = text.length();
+ if (end > start) {
+ String tokenText = text.substring(start, end);
+ ASToken extraToken = new ASToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getEndLine(),
+ prevToken.getEndColumn(), tokenText);
+ extraToken.setEndLine(prevToken.getLine());
+ extraToken.setEndLine(prevToken.getColumn());
+ tokens.add(extraToken);
+ }
+ }
+ return tokens;
}
private static class BlockStackItem {
@@ -1802,323 +1325,4 @@ public class FORMATTER {
public int clauseCount = 0;
}
-
- private String formatMXMLTextInternal(String filePath, String text, Collection<ICompilerProblem> problems) {
- if (problems == null) {
- problems = new ArrayList<ICompilerProblem>();
- }
-
- StringReader textReader = new StringReader(text);
- MXMLTokenizer mxmlTokenizer = new MXMLTokenizer();
- IMXMLToken[] originalTokens = null;
- try {
- originalTokens = mxmlTokenizer.getTokens(textReader);
- } finally {
- IOUtils.closeQuietly(textReader);
- IOUtils.closeQuietly(mxmlTokenizer);
- }
-
- if (mxmlTokenizer.hasTokenizationProblems()) {
- problems.addAll(mxmlTokenizer.getTokenizationProblems());
- }
-
- if (!ignoreProblems && hasErrors(problems)) {
- return text;
- }
-
- Pattern scriptStartPattern = Pattern.compile("<((?:mx|fx):(Script|Metadata))");
-
- List<IMXMLToken> tokens = insertExtraMXMLTokens(originalTokens, text);
-
- int indent = 0;
- int numRequiredNewLines = 0;
- boolean requiredSpace = false;
- boolean inOpenTag = false;
- boolean inCloseTag = false;
- boolean skipFormatting = false;
- String attributeIndent = "";
- IMXMLToken prevToken = null;
- IMXMLToken prevTokenOrExtra = null;
- IMXMLToken token = null;
- IMXMLToken nextToken = null;
- List<ElementStackItem> elementStack = new ArrayList<ElementStackItem>();
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < tokens.size(); i++) {
- token = tokens.get(i);
- nextToken = null;
- if (i < (tokens.size() - 1)) {
- nextToken = tokens.get(i + 1);
- }
- 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;
- }
- numRequiredNewLines = Math.max(numRequiredNewLines, countNewLinesInExtra(token));
- }
- prevTokenOrExtra = token;
- continue;
- } else if (token.getType() == MXMLTokenTypes.TOKEN_WHITESPACE) {
- if (skipFormatting) {
- builder.append(token.getText());
- } else {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- numRequiredNewLines = Math.max(numRequiredNewLines, countNewLinesInExtra(token));
- } else {
- // if the parent element contains text, treat whitespace
- // the same as text, and don't reformat it
- // text is never reformatted because some components use it
- // without collapsing whitespace, and developers would be
- // confused if whitespace that they deliberately added were
- // to be removed
- builder.append(token.getText());
- }
- 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, numRequiredNewLines);
- appendNewLines(builder, numRequiredNewLines);
- }
- }
- continue;
- } else if (token.getType() == MXMLTokenTypes.TOKEN_OPEN_TAG_START
- && scriptStartPattern.matcher(token.getText()).matches()) {
-
- if (prevToken != null && numRequiredNewLines > 0) {
- appendNewLines(builder, numRequiredNewLines);
- }
- StringBuilder scriptBuilder = new StringBuilder();
- scriptBuilder.append(token.getText());
- boolean inScriptCloseTag = false;
- while (i < (tokens.size() - 1)) {
- i++;
- token = tokens.get(i);
- scriptBuilder.append(token.getText());
- if (token.getType() == MXMLTokenTypes.TOKEN_CLOSE_TAG_START) {
- inScriptCloseTag = true;
- } else if (inScriptCloseTag && token.getType() == MXMLTokenTypes.TOKEN_TAG_END) {
- break;
- }
- }
- if (problems == null) {
- // we need to know if there were problems because it means that we
- // need to return the original, unformatted text
- problems = new ArrayList<ICompilerProblem>();
- }
- builder.append(formatMXMLScriptElement(filePath, token.getLine(), scriptBuilder.toString(), problems));
- if (hasErrors(problems)) {
- return text;
- }
- prevToken = token;
- prevTokenOrExtra = token;
- requiredSpace = false;
- numRequiredNewLines = 1;
- continue;
- }
-
- // characters that must appear before the token
- switch (token.getType()) {
- case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
- inOpenTag = true;
- // if the parent contains text, children should be the same
- boolean containsText = !elementStack.isEmpty()
- && elementStack.get(elementStack.size() - 1).containsText;
- elementStack.add(new ElementStackItem(token, token.getText().substring(1), containsText));
- break;
- }
- case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- indent = decreaseIndent(indent);
- }
- inCloseTag = true;
- break;
- }
- case MXMLTokenTypes.TOKEN_NAME: {
- requiredSpace = true;
- break;
- }
- }
-
- if (!skipFormatting && prevToken != null) {
- if (numRequiredNewLines > 0) {
- appendNewLines(builder, numRequiredNewLines);
- appendIndent(builder, indent);
- if (attributeIndent.length() > 0) {
- builder.append(attributeIndent);
- }
- } else if (requiredSpace) {
- builder.append(' ');
- }
- }
-
- // include the token's own text
- // no token gets reformatted before being appended
- // whitespace is the only special case, but that's not handled here
- builder.append(token.getText());
-
- // characters that must appear after the token
- requiredSpace = false;
- numRequiredNewLines = 0;
-
- switch (token.getType()) {
- case MXMLTokenTypes.TOKEN_PROCESSING_INSTRUCTION: {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- break;
- }
- case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
- if (nextToken != null && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
- && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END
- && nextToken.getType() != TOKEN_TYPE_EXTRA) {
- requiredSpace = true;
- }
- if (elementStack.isEmpty()) {
- // something is very wrong!
- return text;
- }
- String elementName = token.getText().substring(2);
- ElementStackItem elementItem = elementStack.remove(elementStack.size() - 1);
- if (!elementName.equals(elementItem.elementName)) {
- // there's a unclosed tag with a different name somewhere
- return text;
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
- if (nextToken != null && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
- && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
- attributeIndent = getAttributeIndent(token);
- if (nextToken.getType() != TOKEN_TYPE_EXTRA) {
- requiredSpace = true;
- }
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_TAG_END: {
- if (inOpenTag) {
- ElementStackItem element = elementStack.get(elementStack.size() - 1);
- if (!element.containsText) {
- element.containsText = elementContainsText(tokens, i + 1, element.token);
- }
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- indent = increaseIndent(indent);
- }
- } else {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- }
- inOpenTag = false;
- attributeIndent = "";
- inCloseTag = false;
- break;
- }
- case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
- if (inOpenTag) {
- elementStack.remove(elementStack.size() - 1);
- } else {
- if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- }
- inOpenTag = false;
- // no need to change nested indent after this tag
- // however, we may need to remove attribute indent
- attributeIndent = "";
- // we shouldn't find an empty close tag, but clear flag anyway
- inCloseTag = false;
- break;
- }
- case MXMLTokenTypes.TOKEN_STRING: {
- if (inOpenTag && mxmlInsertNewLineBetweenAttributes && nextToken != null
- && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
- && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
- numRequiredNewLines = Math.max(numRequiredNewLines, 1);
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_COMMENT: {
- String tokenText = token.getText();
- String trimmed = tokenText.substring(4, tokenText.length() - 3).trim();
- if (!skipFormatting && FORMATTER_TAG_OFF.equals(trimmed)) {
- skipFormatting = true;
- } else if (skipFormatting && FORMATTER_TAG_ON.equals(trimmed)) {
- skipFormatting = false;
- }
- break;
- }
- }
-
- prevToken = token;
- prevTokenOrExtra = token;
- }
-
- return builder.toString();
- }
-
- private boolean elementContainsText(List<IMXMLToken> tokens, int startIndex, IMXMLToken openTagToken) {
- ArrayList<IMXMLToken> elementStack = new ArrayList<IMXMLToken>();
- elementStack.add(openTagToken);
- for (int i = startIndex; i < tokens.size(); i++) {
- IMXMLToken token = tokens.get(i);
- switch (token.getType()) {
- case MXMLTokenTypes.TOKEN_TEXT: {
- if (elementStack.size() == 1) {
- return true;
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
- elementStack.add(token);
- break;
- }
- case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
- elementStack.remove(elementStack.size() - 1);
- if (elementStack.size() == 0) {
- return false;
- }
- break;
- }
- case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
- elementStack.remove(elementStack.size() - 1);
- if (elementStack.size() == 0) {
- return false;
- }
- break;
- }
- }
- }
- return false;
- }
-
- private int countNewLinesInExtra(IMXMLToken token) {
- if (token == null
- || (token.getType() != MXMLTokenTypes.TOKEN_WHITESPACE && token.getType() != TOKEN_TYPE_EXTRA)) {
- return 0;
- }
- int numNewLinesInWhitespace = 0;
- String whitespace = token.getText();
- int index = -1;
- while ((index = whitespace.indexOf('\n', index + 1)) != -1) {
- numNewLinesInWhitespace++;
- }
- return numNewLinesInWhitespace;
- }
-
- private static class ElementStackItem {
- public ElementStackItem(IMXMLToken token, String elementName, boolean containsText) {
- this.token = token;
- this.elementName = elementName;
- this.containsText = containsText;
- }
-
- public IMXMLToken token;
- public String elementName;
- public boolean containsText = false;
- }
-}
\ No newline at end of file
+}
diff --git a/formatter/src/main/java/org/apache/royale/formatter/internal/BaseTokenFormatter.java b/formatter/src/main/java/org/apache/royale/formatter/internal/BaseTokenFormatter.java
new file mode 100644
index 000000000..158f64237
--- /dev/null
+++ b/formatter/src/main/java/org/apache/royale/formatter/internal/BaseTokenFormatter.java
@@ -0,0 +1,81 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package org.apache.royale.formatter.internal;
+
+import java.util.Collection;
+
+import org.apache.royale.compiler.clients.problems.CompilerProblemCategorizer;
+import org.apache.royale.compiler.problems.CompilerProblemSeverity;
+import org.apache.royale.compiler.problems.ICompilerProblem;
+import org.apache.royale.formatter.FORMATTER;
+
+public abstract class BaseTokenFormatter {
+ protected FORMATTER formatter;
+
+ protected BaseTokenFormatter(FORMATTER formatter) {
+ this.formatter = formatter;
+ }
+
+ protected boolean hasErrors(Collection<ICompilerProblem> problems) {
+ CompilerProblemCategorizer categorizer = new CompilerProblemCategorizer(null);
+ for (ICompilerProblem problem : problems) {
+ CompilerProblemSeverity severity = categorizer.getProblemSeverity(problem);
+ if (CompilerProblemSeverity.ERROR.equals(severity)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected int increaseIndent(int indent) {
+ return indent + 1;
+ }
+
+ protected int decreaseIndent(int indent) {
+ return Math.max(0, indent - 1);
+ }
+
+ protected String getIndent() {
+ if (formatter.insertSpaces) {
+ String result = "";
+ for (int j = 0; j < formatter.tabSize; j++) {
+ result += " ";
+ }
+ return result;
+ }
+ return "\t";
+ }
+
+ protected void appendIndent(StringBuilder builder, int indent) {
+ String indentString = getIndent();
+ for (int i = 0; i < indent; i++) {
+ builder.append(indentString);
+ }
+ }
+
+ protected void appendNewLines(StringBuilder builder, int numRequiredNewLines) {
+ if (formatter.maxPreserveNewLines != 0) {
+ numRequiredNewLines = Math.min(formatter.maxPreserveNewLines, numRequiredNewLines);
+ }
+ for (int j = 0; j < numRequiredNewLines; j++) {
+ builder.append('\n');
+ }
+ }
+}
diff --git a/formatter/src/main/java/org/apache/royale/formatter/internal/MXMLTokenFormatter.java b/formatter/src/main/java/org/apache/royale/formatter/internal/MXMLTokenFormatter.java
new file mode 100644
index 000000000..662a3b798
--- /dev/null
+++ b/formatter/src/main/java/org/apache/royale/formatter/internal/MXMLTokenFormatter.java
@@ -0,0 +1,506 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package org.apache.royale.formatter.internal;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.royale.compiler.internal.parsing.mxml.MXMLToken;
+import org.apache.royale.compiler.internal.parsing.mxml.MXMLTokenizer;
+import org.apache.royale.compiler.parsing.IMXMLToken;
+import org.apache.royale.compiler.parsing.MXMLTokenTypes;
+import org.apache.royale.compiler.problems.ICompilerProblem;
+import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
+import org.apache.royale.formatter.FORMATTER;
+
+public class MXMLTokenFormatter extends BaseTokenFormatter {
+ private static final int TOKEN_TYPE_EXTRA = 999999;
+ private static final Pattern SCRIPT_START_PATTERN = Pattern.compile("<((?:mx|fx):(Script|Metadata))");
+ private static final String FORMATTER_TAG_OFF = "@formatter:off";
+ private static final String FORMATTER_TAG_ON = "@formatter:on";
+
+ public MXMLTokenFormatter(FORMATTER formatter) {
+ super(formatter);
+ }
+
+ private int indent;
+ private int numRequiredNewLines;
+ private boolean requiredSpace;
+ private boolean inOpenTag;
+ private boolean inCloseTag;
+ private boolean skipFormatting;
+ private String attributeIndent;
+ private IMXMLToken prevToken;
+ private IMXMLToken prevTokenOrExtra;
+ private IMXMLToken token;
+ private IMXMLToken nextToken;
+ private List<ElementStackItem> elementStack;
+
+ public String format(String filePath, String text, Collection<ICompilerProblem> problems) {
+ if (problems == null) {
+ problems = new ArrayList<ICompilerProblem>();
+ }
+
+ StringReader textReader = new StringReader(text);
+ MXMLTokenizer mxmlTokenizer = new MXMLTokenizer();
+ IMXMLToken[] originalTokens = null;
+ try {
+ originalTokens = mxmlTokenizer.getTokens(textReader);
+ } finally {
+ IOUtils.closeQuietly(textReader);
+ IOUtils.closeQuietly(mxmlTokenizer);
+ }
+
+ if (mxmlTokenizer.hasTokenizationProblems()) {
+ problems.addAll(mxmlTokenizer.getTokenizationProblems());
+ }
+
+ if (!formatter.ignoreProblems && hasErrors(problems)) {
+ return text;
+ }
+
+ List<IMXMLToken> tokens = insertExtraMXMLTokens(originalTokens, text);
+ try {
+ return parseTokens(filePath, text, tokens, problems);
+ } catch (Exception e) {
+ if (problems != null) {
+ System.err.println(e);
+ e.printStackTrace(System.err);
+ problems.add(new UnexpectedExceptionProblem(e));
+ }
+ return text;
+ }
+
+ }
+
+ private String parseTokens(String filePath, String text, List<IMXMLToken> tokens, Collection<ICompilerProblem> problems) throws Exception {
+ indent = 0;
+ numRequiredNewLines = 0;
+ requiredSpace = false;
+ inOpenTag = false;
+ inCloseTag = false;
+ skipFormatting = false;
+ attributeIndent = "";
+ prevToken = null;
+ prevTokenOrExtra = null;
+ token = null;
+ nextToken = null;
+ elementStack = new ArrayList<ElementStackItem>();
+
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < tokens.size(); i++) {
+ token = tokens.get(i);
+ nextToken = null;
+ if (i < (tokens.size() - 1)) {
+ nextToken = tokens.get(i + 1);
+ }
+ 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;
+ }
+ numRequiredNewLines = Math.max(numRequiredNewLines, countNewLinesInExtra(token));
+ }
+ prevTokenOrExtra = token;
+ continue;
+ } else if (token.getType() == MXMLTokenTypes.TOKEN_WHITESPACE) {
+ if (skipFormatting) {
+ builder.append(token.getText());
+ } else {
+ if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+ numRequiredNewLines = Math.max(numRequiredNewLines, countNewLinesInExtra(token));
+ } else {
+ // if the parent element contains text, treat whitespace
+ // the same as text, and don't reformat it
+ // text is never reformatted because some components use it
+ // without collapsing whitespace, and developers would be
+ // confused if whitespace that they deliberately added were
+ // to be removed
+ builder.append(token.getText());
+ }
+ 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, numRequiredNewLines);
+ appendNewLines(builder, numRequiredNewLines);
+ }
+ }
+ continue;
+ } else if (token.getType() == MXMLTokenTypes.TOKEN_OPEN_TAG_START
+ && SCRIPT_START_PATTERN.matcher(token.getText()).matches()) {
+
+ if (prevToken != null && numRequiredNewLines > 0) {
+ appendNewLines(builder, numRequiredNewLines);
+ }
+ StringBuilder scriptBuilder = new StringBuilder();
+ scriptBuilder.append(token.getText());
+ boolean inScriptCloseTag = false;
+ while (i < (tokens.size() - 1)) {
+ i++;
+ token = tokens.get(i);
+ scriptBuilder.append(token.getText());
+ if (token.getType() == MXMLTokenTypes.TOKEN_CLOSE_TAG_START) {
+ inScriptCloseTag = true;
+ } else if (inScriptCloseTag && token.getType() == MXMLTokenTypes.TOKEN_TAG_END) {
+ break;
+ }
+ }
+ if (problems == null) {
+ // we need to know if there were problems because it means that we
+ // need to return the original, unformatted text
+ problems = new ArrayList<ICompilerProblem>();
+ }
+ builder.append(formatMXMLScriptElement(filePath, token.getLine(), scriptBuilder.toString(), problems));
+ if (hasErrors(problems)) {
+ return text;
+ }
+ prevToken = token;
+ prevTokenOrExtra = token;
+ requiredSpace = false;
+ numRequiredNewLines = 1;
+ continue;
+ }
+
+ // characters that must appear before the token
+ switch (token.getType()) {
+ case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
+ inOpenTag = true;
+ // if the parent contains text, children should be the same
+ boolean containsText = !elementStack.isEmpty()
+ && elementStack.get(elementStack.size() - 1).containsText;
+ elementStack.add(new ElementStackItem(token, token.getText().substring(1), containsText));
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
+ if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+ indent = decreaseIndent(indent);
+ }
+ inCloseTag = true;
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_NAME: {
+ requiredSpace = true;
+ break;
+ }
+ }
+
+ if (!skipFormatting && prevToken != null) {
+ if (numRequiredNewLines > 0) {
+ appendNewLines(builder, numRequiredNewLines);
+ appendIndent(builder, indent);
+ if (attributeIndent.length() > 0) {
+ builder.append(attributeIndent);
+ }
+ } else if (requiredSpace) {
+ builder.append(' ');
+ }
+ }
+
+ // include the token's own text
+ // no token gets reformatted before being appended
+ // whitespace is the only special case, but that's not handled here
+ builder.append(token.getText());
+
+ // characters that must appear after the token
+ requiredSpace = false;
+ numRequiredNewLines = 0;
+
+ switch (token.getType()) {
+ case MXMLTokenTypes.TOKEN_PROCESSING_INSTRUCTION: {
+ numRequiredNewLines = Math.max(numRequiredNewLines, 1);
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
+ if (nextToken != null && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
+ && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END
+ && nextToken.getType() != TOKEN_TYPE_EXTRA) {
+ requiredSpace = true;
+ }
+ if (elementStack.isEmpty()) {
+ // something is very wrong!
+ return text;
+ }
+ String elementName = token.getText().substring(2);
+ ElementStackItem elementItem = elementStack.remove(elementStack.size() - 1);
+ if (!elementName.equals(elementItem.elementName)) {
+ // there's a unclosed tag with a different name somewhere
+ return text;
+ }
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
+ if (nextToken != null && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
+ && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
+ attributeIndent = getAttributeIndent(token);
+ if (nextToken.getType() != TOKEN_TYPE_EXTRA) {
+ requiredSpace = true;
+ }
+ }
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_TAG_END: {
+ if (inOpenTag) {
+ ElementStackItem element = elementStack.get(elementStack.size() - 1);
+ if (!element.containsText) {
+ element.containsText = elementContainsText(tokens, i + 1, element.token);
+ }
+ if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+ indent = increaseIndent(indent);
+ }
+ } else {
+ if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+ numRequiredNewLines = Math.max(numRequiredNewLines, 1);
+ }
+ }
+ inOpenTag = false;
+ attributeIndent = "";
+ inCloseTag = false;
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
+ if (inOpenTag) {
+ elementStack.remove(elementStack.size() - 1);
+ } else {
+ if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+ numRequiredNewLines = Math.max(numRequiredNewLines, 1);
+ }
+ }
+ inOpenTag = false;
+ // no need to change nested indent after this tag
+ // however, we may need to remove attribute indent
+ attributeIndent = "";
+ // we shouldn't find an empty close tag, but clear flag anyway
+ inCloseTag = false;
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_STRING: {
+ if (inOpenTag && formatter.mxmlInsertNewLineBetweenAttributes && nextToken != null
+ && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
+ && nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
+ numRequiredNewLines = Math.max(numRequiredNewLines, 1);
+ }
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_COMMENT: {
+ String tokenText = token.getText();
+ String trimmed = tokenText.substring(4, tokenText.length() - 3).trim();
+ if (!skipFormatting && FORMATTER_TAG_OFF.equals(trimmed)) {
+ skipFormatting = true;
+ } else if (skipFormatting && FORMATTER_TAG_ON.equals(trimmed)) {
+ skipFormatting = false;
+ }
+ break;
+ }
+ }
+
+ prevToken = token;
+ prevTokenOrExtra = token;
+ }
+
+ return builder.toString();
+ }
+
+ private String formatMXMLScriptElement(String filePath, int line, String text,
+ Collection<ICompilerProblem> problems) {
+ String indent = "\t";
+ if (formatter.insertSpaces) {
+ indent = "";
+ for (int i = 0; i < formatter.tabSize; i++) {
+ indent += " ";
+ }
+ }
+ StringBuilder builder = new StringBuilder();
+ Pattern scriptPattern = Pattern.compile(
+ "^<((?:mx|fx):(\\w+))>\\s*(<!\\[CDATA\\[)?((?:.|(?:\\r?\\n))*?)(?:\\]\\]>)?\\s*<\\/(?:mx|fx):(?:\\w+)>$");
+ Matcher scriptMatcher = scriptPattern.matcher(text);
+ if (!scriptMatcher.matches()) {
+ return text;
+ }
+ if (problems == null) {
+ // we need to know if there were problems because it means that we
+ // need to return the original, unformatted text
+ problems = new ArrayList<ICompilerProblem>();
+ }
+ String scriptTagText = scriptMatcher.group(1);
+ String scriptTagName = scriptMatcher.group(2);
+ String cdataText = scriptMatcher.group(3);
+ String scriptText = scriptMatcher.group(4);
+ boolean requireCdata = cdataText != null || "Script".equals(scriptTagName);
+ ASTokenFormatter asFormatter = new ASTokenFormatter(formatter);
+ String formattedScriptText = asFormatter.format(filePath + "@Script[" + line + "]", scriptText, problems);
+ if (!formatter.ignoreProblems && hasErrors(problems)) {
+ return text;
+ }
+ if (formattedScriptText.length() > 0) {
+ String[] formattedLines = formattedScriptText.split("\n");
+ String lineIndent = requireCdata ? (indent + indent + indent) : (indent + indent);
+ for (int i = 0; i < formattedLines.length; i++) {
+ formattedLines[i] = lineIndent + formattedLines[i];
+ }
+ formattedScriptText = String.join("\n", formattedLines);
+ }
+ builder.append(indent);
+ builder.append("<");
+ builder.append(scriptTagText);
+ builder.append(">\n");
+ if (requireCdata) {
+ builder.append(indent);
+ builder.append(indent);
+ builder.append("<![CDATA[\n");
+ }
+ if (formattedScriptText.length() > 0) {
+ builder.append(formattedScriptText);
+ builder.append("\n");
+ }
+ if (requireCdata) {
+ builder.append(indent);
+ builder.append(indent);
+ builder.append("]]>\n");
+ }
+ builder.append(indent);
+ builder.append("</");
+ builder.append(scriptTagText);
+ builder.append(">");
+
+ return builder.toString();
+ }
+
+ private boolean elementContainsText(List<IMXMLToken> tokens, int startIndex, IMXMLToken openTagToken) {
+ ArrayList<IMXMLToken> elementStack = new ArrayList<IMXMLToken>();
+ elementStack.add(openTagToken);
+ for (int i = startIndex; i < tokens.size(); i++) {
+ IMXMLToken token = tokens.get(i);
+ switch (token.getType()) {
+ case MXMLTokenTypes.TOKEN_TEXT: {
+ if (elementStack.size() == 1) {
+ return true;
+ }
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
+ elementStack.add(token);
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
+ elementStack.remove(elementStack.size() - 1);
+ if (elementStack.size() == 0) {
+ return false;
+ }
+ break;
+ }
+ case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
+ elementStack.remove(elementStack.size() - 1);
+ if (elementStack.size() == 0) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int countNewLinesInExtra(IMXMLToken token) {
+ if (token == null
+ || (token.getType() != MXMLTokenTypes.TOKEN_WHITESPACE && token.getType() != TOKEN_TYPE_EXTRA)) {
+ return 0;
+ }
+ int numNewLinesInWhitespace = 0;
+ String whitespace = token.getText();
+ int index = -1;
+ while ((index = whitespace.indexOf('\n', index + 1)) != -1) {
+ numNewLinesInWhitespace++;
+ }
+ return numNewLinesInWhitespace;
+ }
+
+ private String getAttributeIndent(IMXMLToken openTagToken) {
+ if (!formatter.mxmlAlignAttributes) {
+ return getIndent();
+ }
+ int indentSize = openTagToken.getText().length() + 1;
+ String result = "";
+ while (indentSize >= formatter.tabSize) {
+ result += getIndent();
+ indentSize -= formatter.tabSize;
+ }
+ for (int i = 0; i < indentSize; i++) {
+ result += " ";
+ }
+ return result;
+ }
+
+ private List<IMXMLToken> insertExtraMXMLTokens(IMXMLToken[] originalTokens, String text) {
+ ArrayList<IMXMLToken> tokens = new ArrayList<IMXMLToken>();
+ IMXMLToken prevToken = null;
+ for (IMXMLToken token : originalTokens) {
+ if (prevToken != null) {
+ int start = prevToken.getEnd();
+ int end = token.getStart();
+ if (end > start) {
+ String tokenText = text.substring(start, end);
+ MXMLToken extraToken = new MXMLToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getLine(),
+ prevToken.getColumn() + end - start, tokenText);
+ extraToken.setEndLine(token.getLine());
+ extraToken.setEndLine(token.getColumn());
+ tokens.add(extraToken);
+ }
+ }
+ tokens.add(token);
+ prevToken = token;
+ }
+ if (prevToken != null) {
+ int start = prevToken.getEnd();
+ int end = text.length();
+ if (end > start) {
+ String tokenText = text.substring(start, end);
+ MXMLToken extraToken = new MXMLToken(TOKEN_TYPE_EXTRA, start, end, prevToken.getLine(),
+ prevToken.getColumn() + end - start, tokenText);
+ extraToken.setEndLine(prevToken.getLine());
+ extraToken.setEndLine(prevToken.getColumn());
+ tokens.add(extraToken);
+ }
+ }
+ return tokens;
+ }
+
+ private static class ElementStackItem {
+ public ElementStackItem(IMXMLToken token, String elementName, boolean containsText) {
+ this.token = token;
+ this.elementName = elementName;
+ this.containsText = containsText;
+ }
+
+ public IMXMLToken token;
+ public String elementName;
+ public boolean containsText = false;
+ }
+}