package com.jetbrains.lang.dart;
import com.intellij.lang.*;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiFile;
import com.intellij.psi.TokenType;
import com.intellij.psi.text.BlockSupport;
import com.intellij.psi.tree.*;
import com.intellij.util.diff.FlyweightCapableTreeStructure;
import com.jetbrains.lang.dart.lexer.DartDocLexer;
import com.jetbrains.lang.dart.lexer.DartLexer;
import com.jetbrains.lang.dart.psi.impl.DartLazyParseableBlockImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.lang.parser.GeneratedParserUtilBase.*;
import static com.jetbrains.lang.dart.DartTokenTypes.*;
public interface DartTokenTypesSets {
IFileElementType DART_FILE = new IFileElementType("DARTFILE", DartLanguage.INSTANCE);
IElementType WHITE_SPACE = TokenType.WHITE_SPACE;
IElementType BAD_CHARACTER = TokenType.BAD_CHARACTER;
// DartLexer returns multiline comments as a single MULTI_LINE_COMMENT or MULTI_LINE_DOC_COMMENT
// DartDocLexer splits MULTI_LINE_DOC_COMMENT in tokens
// can't appear in PSI because merged into MULTI_LINE_COMMENT
IElementType MULTI_LINE_COMMENT_START = new DartElementType("MULTI_LINE_COMMENT_START");
IElementType MULTI_LINE_DOC_COMMENT_START = new DartElementType("MULTI_LINE_DOC_COMMENT_START");
IElementType MULTI_LINE_COMMENT_BODY = new DartElementType("MULTI_LINE_COMMENT_BODY");
IElementType DOC_COMMENT_LEADING_ASTERISK = new DartElementType("DOC_COMMENT_LEADING_ASTERISK");
IElementType MULTI_LINE_COMMENT_END = new DartElementType("MULTI_LINE_COMMENT_END");
IElementType SINGLE_LINE_COMMENT = new DartElementType("SINGLE_LINE_COMMENT");
IElementType SINGLE_LINE_DOC_COMMENT = new DartElementType("SINGLE_LINE_DOC_COMMENT");
IElementType MULTI_LINE_COMMENT = new DartElementType("MULTI_LINE_COMMENT");
IElementType MULTI_LINE_DOC_COMMENT = new DartDocCommentElementType();
IElementType LAZY_PARSEABLE_BLOCK = new DartLazyParseableBlockElementType();
TokenSet STRINGS = TokenSet.create(RAW_SINGLE_QUOTED_STRING, RAW_TRIPLE_QUOTED_STRING, OPEN_QUOTE, CLOSING_QUOTE, REGULAR_STRING_PART);
TokenSet WHITE_SPACES = TokenSet.create(WHITE_SPACE);
TokenSet RESERVED_WORDS = TokenSet.create(ASSERT,
BREAK,
CASE,
CATCH,
CLASS,
CONST,
CONTINUE,
DEFAULT,
DO,
ELSE,
ENUM,
EXTENDS,
FALSE,
FINAL,
FINALLY,
FOR,
IF,
IN,
IS,
NEW,
NULL,
RETHROW,
RETURN,
SUPER,
SWITCH,
THIS,
THROW,
TRUE,
TRY,
VAR,
WHILE,
WITH,
// 'void' is not listed as reserved word in spec but it may only be used as the return type of a function, so may be treated as reserved word
VOID);
TokenSet BUILT_IN_IDENTIFIERS = TokenSet.create(ABSTRACT,
AS,
COVARIANT,
DEFERRED,
EXPORT,
EXTERNAL,
FACTORY,
GET,
IMPLEMENTS,
IMPORT,
LIBRARY,
OPERATOR,
PART,
SET,
STATIC,
TYPEDEF,
// next are not listed in spec, but they seem to have the same sense as BUILT_IN_IDENTIFIERS: somewhere treated as keywords, but can be used as normal identifiers
ON,
OF,
NATIVE,
SHOW,
HIDE,
SYNC,
ASYNC,
AWAIT,
YIELD);
TokenSet OPERATORS = TokenSet.create(
MINUS, MINUS_EQ, MINUS_MINUS, PLUS, PLUS_PLUS, PLUS_EQ, DIV, DIV_EQ, MUL, MUL_EQ, INT_DIV, INT_DIV_EQ, REM_EQ, REM, BIN_NOT, NOT,
EQ, EQ_EQ, NEQ, GT, GT_EQ, GT_GT_EQ, LT, LT_EQ, LT_LT, LT_LT_EQ, OR, OR_EQ, OR_OR, OR_OR_EQ, XOR, XOR_EQ, AND,
AND_EQ, AND_AND, AND_AND_EQ, LBRACKET, RBRACKET, AS, QUEST_QUEST, QUEST_QUEST_EQ
);
TokenSet ASSIGNMENT_OPERATORS = TokenSet.create(
// '=' | '*=' | '/=' | '~/=' | '%=' | '+=' | '-=' | '<<=' | '>>=' | '&=' | '&&=' | '^=' | '|=' | '||=' | '??='
EQ, MUL_EQ, DIV_EQ, INT_DIV_EQ, REM_EQ, PLUS_EQ, MINUS_EQ, LT_LT_EQ, GT_GT_EQ, AND_EQ, AND_AND_EQ, XOR_EQ, OR_EQ, OR_OR_EQ,
QUEST_QUEST_EQ
);
TokenSet BINARY_EXPRESSIONS = TokenSet.create(
IF_NULL_EXPRESSION,
LOGIC_OR_EXPRESSION,
LOGIC_AND_EXPRESSION,
COMPARE_EXPRESSION,
SHIFT_EXPRESSION,
ADDITIVE_EXPRESSION,
MULTIPLICATIVE_EXPRESSION
);
TokenSet BINARY_OPERATORS = TokenSet.create(
// '??
QUEST_QUEST,
// '&&' '||'
AND_AND, OR_OR,
// '==' '!='
EQ_EQ, NEQ,
// '<' '<=' '>' '>='
LT, LT_EQ, GT, GT_EQ,
// '&' '|' '^'
AND, OR, XOR,
// '<<' '>>'
LT_LT, GT_GT,
// '+' '-'
PLUS, MINUS,
// '*' '/' '%' '~/'
MUL, DIV, REM, INT_DIV
);
TokenSet LOGIC_OPERATORS = TokenSet.create(
OR_OR, AND_AND,
// Strictly speaking, this isn't a logical operator, but should be formatted the same.
QUEST_QUEST
);
TokenSet UNARY_OPERATORS = TokenSet.create(
// '-' '!' '~' '++' '--'
MINUS, NOT, BIN_NOT, PLUS_PLUS, MINUS_MINUS
);
TokenSet BITWISE_OPERATORS = TokenSet.create(BITWISE_OPERATOR);
TokenSet FUNCTION_DEFINITION = TokenSet.create(
FUNCTION_FORMAL_PARAMETER,
FUNCTION_DECLARATION_WITH_BODY,
FUNCTION_DECLARATION_WITH_BODY_OR_NATIVE,
METHOD_DECLARATION,
GETTER_DECLARATION,
SETTER_DECLARATION
);
TokenSet COMMENTS = TokenSet.create(SINGLE_LINE_COMMENT, SINGLE_LINE_DOC_COMMENT, MULTI_LINE_COMMENT, MULTI_LINE_DOC_COMMENT);
TokenSet DOC_COMMENT_CONTENTS =
TokenSet.create(MULTI_LINE_DOC_COMMENT_START, MULTI_LINE_COMMENT_BODY, DOC_COMMENT_LEADING_ASTERISK, MULTI_LINE_COMMENT_END);
IElementType EMBEDDED_CONTENT = new DartEmbeddedContentElementType();
TokenSet BLOCKS = TokenSet.create(
BLOCK,
LAZY_PARSEABLE_BLOCK
);
TokenSet BLOCKS_EXT = TokenSet.create(
BLOCK,
LAZY_PARSEABLE_BLOCK,
CLASS_MEMBERS,
DART_FILE,
EMBEDDED_CONTENT
);
TokenSet DECLARATIONS = TokenSet.create(
CLASS_DEFINITION,
FUNCTION_DECLARATION_WITH_BODY,
FUNCTION_DECLARATION_WITH_BODY_OR_NATIVE,
GETTER_DECLARATION,
SETTER_DECLARATION,
VAR_DECLARATION_LIST,
FUNCTION_TYPE_ALIAS
);
class DartDocCommentElementType extends ILazyParseableElementType {
public DartDocCommentElementType() {
super("MULTI_LINE_DOC_COMMENT", DartLanguage.INSTANCE);
}
@Override
public ASTNode parseContents(final ASTNode chameleon) {
final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(chameleon.getTreeParent().getPsi().getProject(),
chameleon,
new DartDocLexer(),
getLanguage(),
chameleon.getChars());
doParse(builder);
return builder.getTreeBuilt().getFirstChildNode();
}
private void doParse(final PsiBuilder builder) {
final PsiBuilder.Marker root = builder.mark();
while (!builder.eof()) {
builder.advanceLexer();
}
root.done(this);
}
}
class DartLazyParseableBlockElementType extends IReparseableElementType {
public DartLazyParseableBlockElementType() {
super("LAZY_PARSEABLE_BLOCK", DartLanguage.INSTANCE);
}
@Override
public boolean isParsable(@NotNull final CharSequence buffer, @NotNull final Language fileLanguage, @NotNull final Project project) {
final Lexer lexer = new DartLexer();
lexer.start(buffer);
if (lexer.getTokenType() != LBRACE) return false;
int balance = 1;
lexer.advance();
while (true) {
final IElementType type = lexer.getTokenType();
if (type == null) break;
if (balance == 0) return false;
if (type == LBRACE) balance++;
if (type == RBRACE) balance--;
lexer.advance();
}
return balance == 0;
}
@Nullable
@Override
public ASTNode createNode(@NotNull final CharSequence text) {
return new DartLazyParseableBlockImpl(this, text);
}
@Override
public ASTNode parseContents(final ASTNode lazyParseableBlock) {
final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(lazyParseableBlock.getTreeParent().getPsi().getProject(),
lazyParseableBlock,
new DartLexer(),
getLanguage(),
lazyParseableBlock.getChars());
if (isSyncOrAsync(lazyParseableBlock)) {
builder.putUserData(DartGeneratedParserUtilBase.INSIDE_SYNC_OR_ASYNC_FUNCTION, true);
}
new DartParser().parseLight(BLOCK, builder);
return builder.getTreeBuilt().getFirstChildNode();
}
private static boolean isSyncOrAsync(@NotNull final ASTNode newBlock) {
final ASTNode oldBlock = Pair.getFirst(newBlock.getUserData(BlockSupport.TREE_TO_BE_REPARSED));
final IElementType type = (oldBlock != null ? oldBlock : newBlock).getTreeParent().getFirstChildNode().getElementType();
return type == SYNC || type == ASYNC;
}
}
class DartEmbeddedContentElementType extends ILazyParseableElementType implements ILightLazyParseableElementType {
public DartEmbeddedContentElementType() {
super("DART_EMBEDDED_CONTENT", DartInHtmlLanguage.INSTANCE);
}
@Override
public FlyweightCapableTreeStructure<LighterASTNode> parseContents(LighterLazyParseableNode chameleon) {
PsiFile file = chameleon.getContainingFile();
assert file != null : chameleon;
final PsiBuilder psiBuilder = PsiBuilderFactory.getInstance().createBuilder(file.getProject(), chameleon);
final PsiBuilder builder = adapt_builder_(EMBEDDED_CONTENT, psiBuilder, new DartParser(), DartParser.EXTENDS_SETS_);
PsiBuilder.Marker marker = enter_section_(builder, 0, _COLLAPSE_, "<code fragment>");
boolean result = DartParser.dartUnit(builder, 0);
exit_section_(builder, 0, marker, EMBEDDED_CONTENT, result, true, TRUE_CONDITION);
return builder.getLightTree();
}
}
}