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 <[email protected]>
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;
+ }
+}