Parser: raise corpus parse rate from 57% to 69%
Grammar gains: array types, directive flags, declaration-level directive modifiers, parameter markers, backticked declaration names, notes after a block-valued declaration, 'if cond then stmt', 'ifx c else v', '#module_parameters' two-group form, '(.*)' prefix dereference, and '#asm' bodies consumed opaquely (they are x86-64 assembly, not Jai). Return items no longer take a default value: allowing one made 'f: (K) -> u32 = null' swallow the enclosing parameter's default and read the rest of the parameter list as extra return values.
This commit is contained in:
@@ -39,14 +39,14 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
create_token_set_(ADD_EXPR, AND_EXPR, ARRAY_LITERAL_EXPR, ARRAY_TYPE_EXPR,
|
||||
ASSIGN_EXPR, AUTO_CAST_EXPR, BACKTICK_EXPR, BIT_AND_EXPR,
|
||||
BIT_OR_EXPR, BIT_XOR_EXPR, BUILTIN_CALL_EXPR, CALL_EXPR,
|
||||
CAST_EXPR, DEREF_EXPR, DIRECTIVE_EXPR, ENUM_EXPR,
|
||||
EQUALITY_EXPR, EXPR, IFX_EXPR, INDEX_EXPR,
|
||||
INLINE_EXPR, INTERFACE_EXPR, LAMBDA_EXPR, LITERAL_EXPR,
|
||||
MEMBER_EXPR, MUL_EXPR, OR_EXPR, PAREN_EXPR,
|
||||
PREFIX_EXPR, PRIMARY_EXPR, PROC_LITERAL_EXPR, RANGE_EXPR,
|
||||
REF_EXPR, RELATIONAL_EXPR, SHIFT_EXPR, STRUCT_EXPR,
|
||||
STRUCT_LITERAL_EXPR, TYPED_ARRAY_LITERAL_EXPR, TYPED_STRUCT_LITERAL_EXPR, UNARY_DOT_EXPR,
|
||||
UNINITIALIZED_EXPR, UNION_EXPR),
|
||||
CAST_EXPR, DEREF_CAST_EXPR, DEREF_EXPR, DIRECTIVE_EXPR,
|
||||
ENUM_EXPR, EQUALITY_EXPR, EXPR, IFX_EXPR,
|
||||
INDEX_EXPR, INLINE_EXPR, INTERFACE_EXPR, LAMBDA_EXPR,
|
||||
LITERAL_EXPR, MEMBER_EXPR, MUL_EXPR, OR_EXPR,
|
||||
PAREN_EXPR, PREFIX_EXPR, PRIMARY_EXPR, PROC_LITERAL_EXPR,
|
||||
RANGE_EXPR, REF_EXPR, RELATIONAL_EXPR, SHIFT_EXPR,
|
||||
STRUCT_EXPR, STRUCT_LITERAL_EXPR, TYPED_ARRAY_LITERAL_EXPR, TYPED_STRUCT_LITERAL_EXPR,
|
||||
UNARY_DOT_EXPR, UNINITIALIZED_EXPR, UNION_EXPR),
|
||||
};
|
||||
|
||||
/* ********************************************************** */
|
||||
@@ -326,31 +326,49 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<dirPlain>> | 'using'
|
||||
// procModifier | 'using'
|
||||
static boolean declModifier_(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declModifier_")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dirPlain(builder_, level_ + 1);
|
||||
result_ = procModifier(builder_, level_ + 1);
|
||||
if (!result_) result_ = consumeToken(builder_, KW_USING);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// IDENT (',' IDENT)*
|
||||
public static boolean declNames(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declNames")) return false;
|
||||
if (!nextTokenIs(builder_, IDENT)) return false;
|
||||
// ['`'] IDENT
|
||||
public static boolean declName(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declName")) return false;
|
||||
if (!nextTokenIs(builder_, "<decl name>", BACKTICK, IDENT)) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = consumeToken(builder_, IDENT);
|
||||
result_ = result_ && declNames_1(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, DECL_NAMES, result_);
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, DECL_NAME, "<decl name>");
|
||||
result_ = declName_0(builder_, level_ + 1);
|
||||
result_ = result_ && consumeToken(builder_, IDENT);
|
||||
exit_section_(builder_, level_, marker_, result_, false, null);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// (',' IDENT)*
|
||||
// ['`']
|
||||
private static boolean declName_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declName_0")) return false;
|
||||
consumeToken(builder_, BACKTICK);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// declName (',' declName)*
|
||||
public static boolean declNames(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declNames")) return false;
|
||||
if (!nextTokenIs(builder_, "<decl names>", BACKTICK, IDENT)) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, DECL_NAMES, "<decl names>");
|
||||
result_ = declName(builder_, level_ + 1);
|
||||
result_ = result_ && declNames_1(builder_, level_ + 1);
|
||||
exit_section_(builder_, level_, marker_, result_, false, null);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// (',' declName)*
|
||||
private static boolean declNames_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declNames_1")) return false;
|
||||
while (true) {
|
||||
@@ -361,18 +379,19 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ',' IDENT
|
||||
// ',' declName
|
||||
private static boolean declNames_1_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declNames_1_0")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = consumeTokens(builder_, 0, COMMA, IDENT);
|
||||
result_ = consumeToken(builder_, COMMA);
|
||||
result_ = result_ && declName(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// ':' [<<exprNoAssign>>] [('=' | ':') initializer]
|
||||
// ':' [<<exprNoAssign>>] procModifier* [('=' | ':') initializer]
|
||||
// | ':=' initializer
|
||||
// | '::' initializer
|
||||
static boolean declTail_(PsiBuilder builder_, int level_) {
|
||||
@@ -386,7 +405,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// ':' [<<exprNoAssign>>] [('=' | ':') initializer]
|
||||
// ':' [<<exprNoAssign>>] procModifier* [('=' | ':') initializer]
|
||||
private static boolean declTail__0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declTail__0")) return false;
|
||||
boolean result_;
|
||||
@@ -394,6 +413,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
result_ = consumeToken(builder_, COLON);
|
||||
result_ = result_ && declTail__0_1(builder_, level_ + 1);
|
||||
result_ = result_ && declTail__0_2(builder_, level_ + 1);
|
||||
result_ = result_ && declTail__0_3(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
@@ -405,27 +425,38 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
// [('=' | ':') initializer]
|
||||
// procModifier*
|
||||
private static boolean declTail__0_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declTail__0_2")) return false;
|
||||
declTail__0_2_0(builder_, level_ + 1);
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!procModifier(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "declTail__0_2", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// [('=' | ':') initializer]
|
||||
private static boolean declTail__0_3(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declTail__0_3")) return false;
|
||||
declTail__0_3_0(builder_, level_ + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ('=' | ':') initializer
|
||||
private static boolean declTail__0_2_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declTail__0_2_0")) return false;
|
||||
private static boolean declTail__0_3_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declTail__0_3_0")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = declTail__0_2_0_0(builder_, level_ + 1);
|
||||
result_ = declTail__0_3_0_0(builder_, level_ + 1);
|
||||
result_ = result_ && initializer(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// '=' | ':'
|
||||
private static boolean declTail__0_2_0_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declTail__0_2_0_0")) return false;
|
||||
private static boolean declTail__0_3_0_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declTail__0_3_0_0")) return false;
|
||||
boolean result_;
|
||||
result_ = consumeToken(builder_, EQ);
|
||||
if (!result_) result_ = consumeToken(builder_, COLON);
|
||||
@@ -455,7 +486,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<isDeclarationAhead>> declModifier_* declNames declTail_ NOTE* semi
|
||||
// <<isDeclarationAhead>> declModifier_* declNames declTail_ semiWithNotes_
|
||||
public static boolean declaration(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declaration")) return false;
|
||||
boolean result_;
|
||||
@@ -464,8 +495,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
result_ = result_ && declaration_1(builder_, level_ + 1);
|
||||
result_ = result_ && declNames(builder_, level_ + 1);
|
||||
result_ = result_ && declTail_(builder_, level_ + 1);
|
||||
result_ = result_ && declaration_4(builder_, level_ + 1);
|
||||
result_ = result_ && semi(builder_, level_ + 1);
|
||||
result_ = result_ && semiWithNotes_(builder_, level_ + 1);
|
||||
exit_section_(builder_, level_, marker_, result_, false, null);
|
||||
return result_;
|
||||
}
|
||||
@@ -481,17 +511,6 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE*
|
||||
private static boolean declaration_4(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "declaration_4")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!consumeToken(builder_, NOTE)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "declaration_4", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// ['`'] 'defer' statement
|
||||
public static boolean deferStatement(PsiBuilder builder_, int level_) {
|
||||
@@ -514,10 +533,12 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<dir "#assert">> expr [expr]
|
||||
// | <<dirWithBlock>> [',' IDENT] block
|
||||
// | <<dirWithOperand>> [',' IDENT] [expr]
|
||||
// | <<dirPlain>> [',' IDENT]
|
||||
// <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
|
||||
// | <<dir "#assert">> expr [expr]
|
||||
// | <<dir "#module_parameters">> '(' [paramList] ')' ['(' [paramList] ')'] [block]
|
||||
// | <<dirWithBlock>> directiveFlag_* block
|
||||
// | <<dirWithOperand>> directiveFlag_* [expr]
|
||||
// | <<dirPlain>> directiveFlag_*
|
||||
public static boolean directiveExpr(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr")) return false;
|
||||
boolean result_;
|
||||
@@ -526,94 +547,198 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
if (!result_) result_ = directiveExpr_1(builder_, level_ + 1);
|
||||
if (!result_) result_ = directiveExpr_2(builder_, level_ + 1);
|
||||
if (!result_) result_ = directiveExpr_3(builder_, level_ + 1);
|
||||
if (!result_) result_ = directiveExpr_4(builder_, level_ + 1);
|
||||
if (!result_) result_ = directiveExpr_5(builder_, level_ + 1);
|
||||
exit_section_(builder_, level_, marker_, result_, false, null);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// <<dir "#assert">> expr [expr]
|
||||
// <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
|
||||
private static boolean directiveExpr_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_0")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dir(builder_, level_ + 1, "#asm");
|
||||
result_ = result_ && directiveExpr_0_1(builder_, level_ + 1);
|
||||
result_ = result_ && opaqueBlock(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// directiveFlag_*
|
||||
private static boolean directiveExpr_0_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_0_1")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "directiveExpr_0_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// <<dir "#assert">> expr [expr]
|
||||
private static boolean directiveExpr_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_1")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dir(builder_, level_ + 1, "#assert");
|
||||
result_ = result_ && expr(builder_, level_ + 1, -1);
|
||||
result_ = result_ && directiveExpr_0_2(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_1_2(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [expr]
|
||||
private static boolean directiveExpr_0_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_0_2")) return false;
|
||||
private static boolean directiveExpr_1_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_1_2")) return false;
|
||||
expr(builder_, level_ + 1, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// <<dirWithBlock>> [',' IDENT] block
|
||||
private static boolean directiveExpr_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_1")) return false;
|
||||
// <<dir "#module_parameters">> '(' [paramList] ')' ['(' [paramList] ')'] [block]
|
||||
private static boolean directiveExpr_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dir(builder_, level_ + 1, "#module_parameters");
|
||||
result_ = result_ && consumeToken(builder_, LPAREN);
|
||||
result_ = result_ && directiveExpr_2_2(builder_, level_ + 1);
|
||||
result_ = result_ && consumeToken(builder_, RPAREN);
|
||||
result_ = result_ && directiveExpr_2_4(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_2_5(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [paramList]
|
||||
private static boolean directiveExpr_2_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2_2")) return false;
|
||||
paramList(builder_, level_ + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ['(' [paramList] ')']
|
||||
private static boolean directiveExpr_2_4(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2_4")) return false;
|
||||
directiveExpr_2_4_0(builder_, level_ + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// '(' [paramList] ')'
|
||||
private static boolean directiveExpr_2_4_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2_4_0")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = consumeToken(builder_, LPAREN);
|
||||
result_ = result_ && directiveExpr_2_4_0_1(builder_, level_ + 1);
|
||||
result_ = result_ && consumeToken(builder_, RPAREN);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [paramList]
|
||||
private static boolean directiveExpr_2_4_0_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2_4_0_1")) return false;
|
||||
paramList(builder_, level_ + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// [block]
|
||||
private static boolean directiveExpr_2_5(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2_5")) return false;
|
||||
block(builder_, level_ + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// <<dirWithBlock>> directiveFlag_* block
|
||||
private static boolean directiveExpr_3(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_3")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dirWithBlock(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_1_1(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_3_1(builder_, level_ + 1);
|
||||
result_ = result_ && block(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [',' IDENT]
|
||||
private static boolean directiveExpr_1_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_1_1")) return false;
|
||||
parseTokens(builder_, 0, COMMA, IDENT);
|
||||
// directiveFlag_*
|
||||
private static boolean directiveExpr_3_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_3_1")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "directiveExpr_3_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// <<dirWithOperand>> [',' IDENT] [expr]
|
||||
private static boolean directiveExpr_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2")) return false;
|
||||
// <<dirWithOperand>> directiveFlag_* [expr]
|
||||
private static boolean directiveExpr_4(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_4")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dirWithOperand(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_2_1(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_2_2(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_4_1(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_4_2(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [',' IDENT]
|
||||
private static boolean directiveExpr_2_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2_1")) return false;
|
||||
parseTokens(builder_, 0, COMMA, IDENT);
|
||||
// directiveFlag_*
|
||||
private static boolean directiveExpr_4_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_4_1")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "directiveExpr_4_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// [expr]
|
||||
private static boolean directiveExpr_2_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_2_2")) return false;
|
||||
private static boolean directiveExpr_4_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_4_2")) return false;
|
||||
expr(builder_, level_ + 1, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// <<dirPlain>> [',' IDENT]
|
||||
private static boolean directiveExpr_3(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_3")) return false;
|
||||
// <<dirPlain>> directiveFlag_*
|
||||
private static boolean directiveExpr_5(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_5")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dirPlain(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_3_1(builder_, level_ + 1);
|
||||
result_ = result_ && directiveExpr_5_1(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [',' IDENT]
|
||||
private static boolean directiveExpr_3_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_3_1")) return false;
|
||||
parseTokens(builder_, 0, COMMA, IDENT);
|
||||
// directiveFlag_*
|
||||
private static boolean directiveExpr_5_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveExpr_5_1")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "directiveExpr_5_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<dirBare>> [',' IDENT] [';']
|
||||
// ',' IDENT
|
||||
static boolean directiveFlag_(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveFlag_")) return false;
|
||||
if (!nextTokenIs(builder_, COMMA)) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = consumeTokens(builder_, 0, COMMA, IDENT);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<dirBare>> directiveFlag_* [';']
|
||||
public static boolean directiveStatement(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveStatement")) return false;
|
||||
boolean result_;
|
||||
@@ -625,10 +750,14 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [',' IDENT]
|
||||
// directiveFlag_*
|
||||
private static boolean directiveStatement_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "directiveStatement_1")) return false;
|
||||
parseTokens(builder_, 0, COMMA, IDENT);
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "directiveStatement_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -716,15 +845,14 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// expr (',' expr)* NOTE* semi
|
||||
// expr (',' expr)* semiWithNotes_
|
||||
public static boolean expressionStatement(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "expressionStatement")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, EXPRESSION_STATEMENT, "<expression statement>");
|
||||
result_ = expr(builder_, level_ + 1, -1);
|
||||
result_ = result_ && expressionStatement_1(builder_, level_ + 1);
|
||||
result_ = result_ && expressionStatement_2(builder_, level_ + 1);
|
||||
result_ = result_ && semi(builder_, level_ + 1);
|
||||
result_ = result_ && semiWithNotes_(builder_, level_ + 1);
|
||||
exit_section_(builder_, level_, marker_, result_, false, null);
|
||||
return result_;
|
||||
}
|
||||
@@ -751,17 +879,6 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// NOTE*
|
||||
private static boolean expressionStatement_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "expressionStatement_2")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!consumeToken(builder_, NOTE)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "expressionStatement_2", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// '<' | '*'
|
||||
static boolean forModifier_(PsiBuilder builder_, int level_) {
|
||||
@@ -1069,7 +1186,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// 'operator' operatorSymbol '::' expr NOTE* semi
|
||||
// 'operator' operatorSymbol '::' expr semiWithNotes_
|
||||
public static boolean operatorDeclaration(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "operatorDeclaration")) return false;
|
||||
if (!nextTokenIs(builder_, KW_OPERATOR)) return false;
|
||||
@@ -1079,23 +1196,11 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
result_ = result_ && operatorSymbol(builder_, level_ + 1);
|
||||
result_ = result_ && consumeToken(builder_, COLON_COLON);
|
||||
result_ = result_ && expr(builder_, level_ + 1, -1);
|
||||
result_ = result_ && operatorDeclaration_4(builder_, level_ + 1);
|
||||
result_ = result_ && semi(builder_, level_ + 1);
|
||||
result_ = result_ && semiWithNotes_(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, OPERATOR_DECLARATION, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// NOTE*
|
||||
private static boolean operatorDeclaration_4(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "operatorDeclaration_4")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!consumeToken(builder_, NOTE)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "operatorDeclaration_4", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// '+' | '-' | '*' | '/' | '%' | '==' | '!=' | '<' | '>' | '<=' | '>='
|
||||
// | '&' | '|' | '^' | '~' | '<<' | '>>' | '<<<' | '>>>'
|
||||
@@ -1171,6 +1276,18 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<dirPlain>> | 'using'
|
||||
static boolean paramModifier_(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "paramModifier_")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dirPlain(builder_, level_ + 1);
|
||||
if (!result_) result_ = consumeToken(builder_, KW_USING);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// ['$' | '$$'] IDENT
|
||||
public static boolean paramName(PsiBuilder builder_, int level_) {
|
||||
@@ -1308,7 +1425,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// ['using'] parameterTail_
|
||||
// paramModifier_* parameterTail_
|
||||
public static boolean parameter(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "parameter")) return false;
|
||||
boolean result_;
|
||||
@@ -1319,10 +1436,14 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// ['using']
|
||||
// paramModifier_*
|
||||
private static boolean parameter_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "parameter_0")) return false;
|
||||
consumeToken(builder_, KW_USING);
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!paramModifier_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "parameter_0", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1527,9 +1648,9 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<dirWithBlock>> block
|
||||
// | <<dirWithOperand>> [',' IDENT] [expr]
|
||||
// | <<dirPlain>> [',' IDENT]
|
||||
// <<dirWithBlock>> directiveFlag_* block
|
||||
// | <<dirWithOperand>> directiveFlag_* [expr]
|
||||
// | <<dirPlain>> directiveFlag_*
|
||||
public static boolean procModifier(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "procModifier")) return false;
|
||||
boolean result_;
|
||||
@@ -1541,18 +1662,30 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// <<dirWithBlock>> block
|
||||
// <<dirWithBlock>> directiveFlag_* block
|
||||
private static boolean procModifier_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "procModifier_0")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = dirWithBlock(builder_, level_ + 1);
|
||||
result_ = result_ && procModifier_0_1(builder_, level_ + 1);
|
||||
result_ = result_ && block(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// <<dirWithOperand>> [',' IDENT] [expr]
|
||||
// directiveFlag_*
|
||||
private static boolean procModifier_0_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "procModifier_0_1")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "procModifier_0_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// <<dirWithOperand>> directiveFlag_* [expr]
|
||||
private static boolean procModifier_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "procModifier_1")) return false;
|
||||
boolean result_;
|
||||
@@ -1564,10 +1697,14 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [',' IDENT]
|
||||
// directiveFlag_*
|
||||
private static boolean procModifier_1_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "procModifier_1_1")) return false;
|
||||
parseTokens(builder_, 0, COMMA, IDENT);
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "procModifier_1_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1578,7 +1715,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
// <<dirPlain>> [',' IDENT]
|
||||
// <<dirPlain>> directiveFlag_*
|
||||
private static boolean procModifier_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "procModifier_2")) return false;
|
||||
boolean result_;
|
||||
@@ -1589,10 +1726,14 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// [',' IDENT]
|
||||
// directiveFlag_*
|
||||
private static boolean procModifier_2_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "procModifier_2_1")) return false;
|
||||
parseTokens(builder_, 0, COMMA, IDENT);
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!directiveFlag_(builder_, level_ + 1)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "procModifier_2_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1706,14 +1847,13 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// [<<isParamNameAhead>> IDENT ':'] <<exprNoAssign>> ['=' initializer]
|
||||
// [<<isParamNameAhead>> IDENT ':'] <<exprNoAssign>>
|
||||
public static boolean returnItem(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "returnItem")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, RETURN_ITEM, "<return item>");
|
||||
result_ = returnItem_0(builder_, level_ + 1);
|
||||
result_ = result_ && exprNoAssign(builder_, level_ + 1);
|
||||
result_ = result_ && returnItem_2(builder_, level_ + 1);
|
||||
exit_section_(builder_, level_, marker_, result_, false, null);
|
||||
return result_;
|
||||
}
|
||||
@@ -1736,26 +1876,8 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// ['=' initializer]
|
||||
private static boolean returnItem_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "returnItem_2")) return false;
|
||||
returnItem_2_0(builder_, level_ + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// '=' initializer
|
||||
private static boolean returnItem_2_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "returnItem_2_0")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = consumeToken(builder_, EQ);
|
||||
result_ = result_ && initializer(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// 'return' [expr (',' expr)*] NOTE* semi
|
||||
// 'return' [expr (',' expr)*] semiWithNotes_
|
||||
public static boolean returnStatement(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "returnStatement")) return false;
|
||||
if (!nextTokenIs(builder_, KW_RETURN)) return false;
|
||||
@@ -1763,8 +1885,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = consumeToken(builder_, KW_RETURN);
|
||||
result_ = result_ && returnStatement_1(builder_, level_ + 1);
|
||||
result_ = result_ && returnStatement_2(builder_, level_ + 1);
|
||||
result_ = result_ && semi(builder_, level_ + 1);
|
||||
result_ = result_ && semiWithNotes_(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, RETURN_STATEMENT, result_);
|
||||
return result_;
|
||||
}
|
||||
@@ -1809,17 +1930,6 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// NOTE*
|
||||
private static boolean returnStatement_2(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "returnStatement_2")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!consumeToken(builder_, NOTE)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "returnStatement_2", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<isReturnGroupAhead>> returnGroup | returnItem (',' returnItem)*
|
||||
static boolean returnTypes_(PsiBuilder builder_, int level_) {
|
||||
@@ -1888,6 +1998,62 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// <<prevEndsConstruct>> NOTE* | NOTE* ';'
|
||||
static boolean semiWithNotes_(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "semiWithNotes_")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = semiWithNotes__0(builder_, level_ + 1);
|
||||
if (!result_) result_ = semiWithNotes__1(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// <<prevEndsConstruct>> NOTE*
|
||||
private static boolean semiWithNotes__0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "semiWithNotes__0")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = prevEndsConstruct(builder_, level_ + 1);
|
||||
result_ = result_ && semiWithNotes__0_1(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// NOTE*
|
||||
private static boolean semiWithNotes__0_1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "semiWithNotes__0_1")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!consumeToken(builder_, NOTE)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "semiWithNotes__0_1", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE* ';'
|
||||
private static boolean semiWithNotes__1(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "semiWithNotes__1")) return false;
|
||||
boolean result_;
|
||||
Marker marker_ = enter_section_(builder_);
|
||||
result_ = semiWithNotes__1_0(builder_, level_ + 1);
|
||||
result_ = result_ && consumeToken(builder_, SEMICOLON);
|
||||
exit_section_(builder_, marker_, null, result_);
|
||||
return result_;
|
||||
}
|
||||
|
||||
// NOTE*
|
||||
private static boolean semiWithNotes__1_0(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "semiWithNotes__1_0")) return false;
|
||||
while (true) {
|
||||
int pos_ = current_position_(builder_);
|
||||
if (!consumeToken(builder_, NOTE)) break;
|
||||
if (!empty_element_parsed_guard_(builder_, "semiWithNotes__1_0", pos_)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// ';'
|
||||
// | block
|
||||
@@ -1903,8 +2069,8 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
// | operatorDeclaration
|
||||
// | usingStatement
|
||||
// | noteStatement
|
||||
// | directiveStatement
|
||||
// | declaration
|
||||
// | directiveStatement
|
||||
// | expressionStatement
|
||||
public static boolean statement(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "statement")) return false;
|
||||
@@ -1924,8 +2090,8 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
if (!result_) result_ = operatorDeclaration(builder_, level_ + 1);
|
||||
if (!result_) result_ = usingStatement(builder_, level_ + 1);
|
||||
if (!result_) result_ = noteStatement(builder_, level_ + 1);
|
||||
if (!result_) result_ = directiveStatement(builder_, level_ + 1);
|
||||
if (!result_) result_ = declaration(builder_, level_ + 1);
|
||||
if (!result_) result_ = directiveStatement(builder_, level_ + 1);
|
||||
if (!result_) result_ = expressionStatement(builder_, level_ + 1);
|
||||
exit_section_(builder_, level_, marker_, result_, false, null);
|
||||
return result_;
|
||||
@@ -2169,24 +2335,26 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
// 11: BINARY(addExpr)
|
||||
// 12: BINARY(mulExpr)
|
||||
// 13: PREFIX(prefixExpr)
|
||||
// 14: ATOM(arrayTypeExpr)
|
||||
// 15: ATOM(castExpr)
|
||||
// 16: PREFIX(autoCastExpr)
|
||||
// 17: PREFIX(inlineExpr)
|
||||
// 18: ATOM(ifxExpr)
|
||||
// 19: POSTFIX(callExpr)
|
||||
// 20: POSTFIX(indexExpr)
|
||||
// 21: POSTFIX(memberExpr)
|
||||
// 22: POSTFIX(derefExpr)
|
||||
// 23: POSTFIX(typedStructLiteralExpr)
|
||||
// 24: POSTFIX(typedArrayLiteralExpr)
|
||||
// 25: ATOM(primaryExpr)
|
||||
// 14: PREFIX(derefCastExpr)
|
||||
// 15: ATOM(arrayTypeExpr)
|
||||
// 16: ATOM(castExpr)
|
||||
// 17: PREFIX(autoCastExpr)
|
||||
// 18: PREFIX(inlineExpr)
|
||||
// 19: ATOM(ifxExpr)
|
||||
// 20: POSTFIX(callExpr)
|
||||
// 21: POSTFIX(indexExpr)
|
||||
// 22: POSTFIX(memberExpr)
|
||||
// 23: POSTFIX(derefExpr)
|
||||
// 24: POSTFIX(typedStructLiteralExpr)
|
||||
// 25: POSTFIX(typedArrayLiteralExpr)
|
||||
// 26: ATOM(primaryExpr)
|
||||
public static boolean expr(PsiBuilder builder_, int level_, int priority_) {
|
||||
if (!recursion_guard_(builder_, level_, "expr")) return false;
|
||||
addVariant(builder_, "<expr>");
|
||||
boolean result_, pinned_;
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, "<expr>");
|
||||
result_ = prefixExpr(builder_, level_ + 1);
|
||||
if (!result_) result_ = derefCastExpr(builder_, level_ + 1);
|
||||
if (!result_) result_ = arrayTypeExpr(builder_, level_ + 1);
|
||||
if (!result_) result_ = castExpr(builder_, level_ + 1);
|
||||
if (!result_) result_ = autoCastExpr(builder_, level_ + 1);
|
||||
@@ -2256,27 +2424,27 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
result_ = expr(builder_, level_, 12);
|
||||
exit_section_(builder_, level_, marker_, MUL_EXPR, result_, true, null);
|
||||
}
|
||||
else if (priority_ < 19 && callExpr_0(builder_, level_ + 1)) {
|
||||
else if (priority_ < 20 && callExpr_0(builder_, level_ + 1)) {
|
||||
result_ = true;
|
||||
exit_section_(builder_, level_, marker_, CALL_EXPR, result_, true, null);
|
||||
}
|
||||
else if (priority_ < 20 && indexExpr_0(builder_, level_ + 1)) {
|
||||
else if (priority_ < 21 && indexExpr_0(builder_, level_ + 1)) {
|
||||
result_ = true;
|
||||
exit_section_(builder_, level_, marker_, INDEX_EXPR, result_, true, null);
|
||||
}
|
||||
else if (priority_ < 21 && memberExpr_0(builder_, level_ + 1)) {
|
||||
else if (priority_ < 22 && memberExpr_0(builder_, level_ + 1)) {
|
||||
result_ = true;
|
||||
exit_section_(builder_, level_, marker_, MEMBER_EXPR, result_, true, null);
|
||||
}
|
||||
else if (priority_ < 22 && consumeTokenSmart(builder_, POSTFIX_DEREFERENCE)) {
|
||||
else if (priority_ < 23 && consumeTokenSmart(builder_, POSTFIX_DEREFERENCE)) {
|
||||
result_ = true;
|
||||
exit_section_(builder_, level_, marker_, DEREF_EXPR, result_, true, null);
|
||||
}
|
||||
else if (priority_ < 23 && typedStructLiteralExpr_0(builder_, level_ + 1)) {
|
||||
else if (priority_ < 24 && typedStructLiteralExpr_0(builder_, level_ + 1)) {
|
||||
result_ = true;
|
||||
exit_section_(builder_, level_, marker_, TYPED_STRUCT_LITERAL_EXPR, result_, true, null);
|
||||
}
|
||||
else if (priority_ < 24 && typedArrayLiteralExpr_0(builder_, level_ + 1)) {
|
||||
else if (priority_ < 25 && typedArrayLiteralExpr_0(builder_, level_ + 1)) {
|
||||
result_ = true;
|
||||
exit_section_(builder_, level_, marker_, TYPED_ARRAY_LITERAL_EXPR, result_, true, null);
|
||||
}
|
||||
@@ -2352,6 +2520,18 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_ || pinned_;
|
||||
}
|
||||
|
||||
public static boolean derefCastExpr(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "derefCastExpr")) return false;
|
||||
if (!nextTokenIsSmart(builder_, LPAREN)) return false;
|
||||
boolean result_, pinned_;
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
|
||||
result_ = parseTokensSmart(builder_, 0, LPAREN, POSTFIX_DEREFERENCE, RPAREN);
|
||||
pinned_ = result_;
|
||||
result_ = pinned_ && expr(builder_, level_, 14);
|
||||
exit_section_(builder_, level_, marker_, DEREF_CAST_EXPR, result_, pinned_, null);
|
||||
return result_ || pinned_;
|
||||
}
|
||||
|
||||
// '[' ['..' | expr] ']' expr
|
||||
public static boolean arrayTypeExpr(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "arrayTypeExpr")) return false;
|
||||
@@ -2419,7 +2599,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
|
||||
result_ = autoCastExpr_0(builder_, level_ + 1);
|
||||
pinned_ = result_;
|
||||
result_ = pinned_ && expr(builder_, level_, 16);
|
||||
result_ = pinned_ && expr(builder_, level_, 17);
|
||||
exit_section_(builder_, level_, marker_, AUTO_CAST_EXPR, result_, pinned_, null);
|
||||
return result_ || pinned_;
|
||||
}
|
||||
@@ -2449,7 +2629,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
Marker marker_ = enter_section_(builder_, level_, _NONE_, null);
|
||||
result_ = inlineExpr_0(builder_, level_ + 1);
|
||||
pinned_ = result_;
|
||||
result_ = pinned_ && expr(builder_, level_, 17);
|
||||
result_ = pinned_ && expr(builder_, level_, 18);
|
||||
exit_section_(builder_, level_, marker_, INLINE_EXPR, result_, pinned_, null);
|
||||
return result_ || pinned_;
|
||||
}
|
||||
@@ -2463,7 +2643,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return result_;
|
||||
}
|
||||
|
||||
// 'ifx' expr ['then'] expr ['else' expr]
|
||||
// 'ifx' expr ['then'] [expr] ['else' expr]
|
||||
public static boolean ifxExpr(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "ifxExpr")) return false;
|
||||
if (!nextTokenIsSmart(builder_, KW_IFX)) return false;
|
||||
@@ -2472,7 +2652,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
result_ = consumeTokenSmart(builder_, KW_IFX);
|
||||
result_ = result_ && expr(builder_, level_ + 1, -1);
|
||||
result_ = result_ && ifxExpr_2(builder_, level_ + 1);
|
||||
result_ = result_ && expr(builder_, level_ + 1, -1);
|
||||
result_ = result_ && ifxExpr_3(builder_, level_ + 1);
|
||||
result_ = result_ && ifxExpr_4(builder_, level_ + 1);
|
||||
exit_section_(builder_, marker_, IFX_EXPR, result_);
|
||||
return result_;
|
||||
@@ -2485,6 +2665,13 @@ public class JaiParser implements PsiParser, LightPsiParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
// [expr]
|
||||
private static boolean ifxExpr_3(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "ifxExpr_3")) return false;
|
||||
expr(builder_, level_ + 1, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ['else' expr]
|
||||
private static boolean ifxExpr_4(PsiBuilder builder_, int level_) {
|
||||
if (!recursion_guard_(builder_, level_, "ifxExpr_4")) return false;
|
||||
|
||||
10
src/main/gen/dev/hgh/jai/psi/JaiDeclName.java
Normal file
10
src/main/gen/dev/hgh/jai/psi/JaiDeclName.java
Normal file
@@ -0,0 +1,10 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package dev.hgh.jai.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface JaiDeclName extends PsiElement {
|
||||
|
||||
}
|
||||
@@ -7,4 +7,7 @@ import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface JaiDeclNames extends PsiElement {
|
||||
|
||||
@NotNull
|
||||
List<JaiDeclName> getDeclNameList();
|
||||
|
||||
}
|
||||
|
||||
@@ -13,4 +13,7 @@ public interface JaiDeclaration extends PsiElement {
|
||||
@Nullable
|
||||
JaiInitializer getInitializer();
|
||||
|
||||
@NotNull
|
||||
List<JaiProcModifier> getProcModifierList();
|
||||
|
||||
}
|
||||
|
||||
13
src/main/gen/dev/hgh/jai/psi/JaiDerefCastExpr.java
Normal file
13
src/main/gen/dev/hgh/jai/psi/JaiDerefCastExpr.java
Normal file
@@ -0,0 +1,13 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package dev.hgh.jai.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface JaiDerefCastExpr extends JaiExpr {
|
||||
|
||||
@Nullable
|
||||
JaiExpr getExpr();
|
||||
|
||||
}
|
||||
@@ -13,4 +13,7 @@ public interface JaiDirectiveExpr extends JaiExpr {
|
||||
@NotNull
|
||||
List<JaiExpr> getExprList();
|
||||
|
||||
@NotNull
|
||||
List<JaiParameter> getParameterList();
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,4 @@ import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface JaiReturnItem extends PsiElement {
|
||||
|
||||
@Nullable
|
||||
JaiInitializer getInitializer();
|
||||
|
||||
}
|
||||
|
||||
@@ -28,8 +28,10 @@ public interface JaiTypes {
|
||||
IElementType CAST_EXPR = new JaiElementType("CAST_EXPR");
|
||||
IElementType CONTINUE_STATEMENT = new JaiElementType("CONTINUE_STATEMENT");
|
||||
IElementType DECLARATION = new JaiElementType("DECLARATION");
|
||||
IElementType DECL_NAME = new JaiElementType("DECL_NAME");
|
||||
IElementType DECL_NAMES = new JaiElementType("DECL_NAMES");
|
||||
IElementType DEFER_STATEMENT = new JaiElementType("DEFER_STATEMENT");
|
||||
IElementType DEREF_CAST_EXPR = new JaiElementType("DEREF_CAST_EXPR");
|
||||
IElementType DEREF_EXPR = new JaiElementType("DEREF_EXPR");
|
||||
IElementType DIRECTIVE_EXPR = new JaiElementType("DIRECTIVE_EXPR");
|
||||
IElementType DIRECTIVE_STATEMENT = new JaiElementType("DIRECTIVE_STATEMENT");
|
||||
@@ -253,12 +255,18 @@ public interface JaiTypes {
|
||||
else if (type == DECLARATION) {
|
||||
return new JaiDeclarationImpl(node);
|
||||
}
|
||||
else if (type == DECL_NAME) {
|
||||
return new JaiDeclNameImpl(node);
|
||||
}
|
||||
else if (type == DECL_NAMES) {
|
||||
return new JaiDeclNamesImpl(node);
|
||||
}
|
||||
else if (type == DEFER_STATEMENT) {
|
||||
return new JaiDeferStatementImpl(node);
|
||||
}
|
||||
else if (type == DEREF_CAST_EXPR) {
|
||||
return new JaiDerefCastExprImpl(node);
|
||||
}
|
||||
else if (type == DEREF_EXPR) {
|
||||
return new JaiDerefExprImpl(node);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,10 @@ public class JaiVisitor extends PsiElementVisitor {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitDeclName(@NotNull JaiDeclName o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitDeclNames(@NotNull JaiDeclNames o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
@@ -91,6 +95,10 @@ public class JaiVisitor extends PsiElementVisitor {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitDerefCastExpr(@NotNull JaiDerefCastExpr o) {
|
||||
visitExpr(o);
|
||||
}
|
||||
|
||||
public void visitDerefExpr(@NotNull JaiDerefExpr o) {
|
||||
visitExpr(o);
|
||||
}
|
||||
|
||||
30
src/main/gen/dev/hgh/jai/psi/impl/JaiDeclNameImpl.java
Normal file
30
src/main/gen/dev/hgh/jai/psi/impl/JaiDeclNameImpl.java
Normal file
@@ -0,0 +1,30 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package dev.hgh.jai.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static dev.hgh.jai.psi.JaiTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import dev.hgh.jai.psi.*;
|
||||
|
||||
public class JaiDeclNameImpl extends ASTWrapperPsiElement implements JaiDeclName {
|
||||
|
||||
public JaiDeclNameImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull JaiVisitor visitor) {
|
||||
visitor.visitDeclName(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JaiVisitor) accept((JaiVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,4 +27,10 @@ public class JaiDeclNamesImpl extends ASTWrapperPsiElement implements JaiDeclNam
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JaiDeclName> getDeclNameList() {
|
||||
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiDeclName.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,4 +39,10 @@ public class JaiDeclarationImpl extends ASTWrapperPsiElement implements JaiDecla
|
||||
return findChildByClass(JaiInitializer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JaiProcModifier> getProcModifierList() {
|
||||
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiProcModifier.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
36
src/main/gen/dev/hgh/jai/psi/impl/JaiDerefCastExprImpl.java
Normal file
36
src/main/gen/dev/hgh/jai/psi/impl/JaiDerefCastExprImpl.java
Normal file
@@ -0,0 +1,36 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package dev.hgh.jai.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static dev.hgh.jai.psi.JaiTypes.*;
|
||||
import dev.hgh.jai.psi.*;
|
||||
|
||||
public class JaiDerefCastExprImpl extends JaiExprImpl implements JaiDerefCastExpr {
|
||||
|
||||
public JaiDerefCastExprImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull JaiVisitor visitor) {
|
||||
visitor.visitDerefCastExpr(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JaiVisitor) accept((JaiVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JaiExpr getExpr() {
|
||||
return findChildByClass(JaiExpr.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,4 +39,10 @@ public class JaiDirectiveExprImpl extends JaiExprImpl implements JaiDirectiveExp
|
||||
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiExpr.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JaiParameter> getParameterList() {
|
||||
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiParameter.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,10 +27,4 @@ public class JaiReturnItemImpl extends ASTWrapperPsiElement implements JaiReturn
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JaiInitializer getInitializer() {
|
||||
return findChildByClass(JaiInitializer.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ statement ::= ';'
|
||||
| operatorDeclaration
|
||||
| usingStatement
|
||||
| noteStatement
|
||||
| directiveStatement
|
||||
| declaration
|
||||
| directiveStatement
|
||||
| expressionStatement
|
||||
|
||||
block ::= '{' statement* '}'
|
||||
@@ -167,13 +167,17 @@ block ::= '{' statement* '}'
|
||||
// `BODY :: #string DONE … DONE`. `x := 1` still needs one.
|
||||
private semi ::= ';' | <<prevEndsConstruct>>
|
||||
|
||||
// Notes attach to the end of a declaration or statement. `<<prevEndsConstruct>>` has
|
||||
// to be checked *before* the notes, because `} @NoProfile` ends at the `}`.
|
||||
private semiWithNotes_ ::= <<prevEndsConstruct>> NOTE* | NOTE* ';'
|
||||
|
||||
noteStatement ::= NOTE+
|
||||
|
||||
// `#scope_file`, `#no_padding`, `#placeholder foo` … a directive that takes no operand
|
||||
// is a statement on its own and carries no `;`. Directives that *do* take an operand
|
||||
// (`#run f()`, `#import "Basic"`) fall through to expressionStatement, which requires
|
||||
// one.
|
||||
directiveStatement ::= <<dirBare>> [',' IDENT] [';']
|
||||
directiveStatement ::= <<dirBare>> directiveFlag_* [';']
|
||||
|
||||
// `#if` is spelled as a directive but is structurally an `if`, and it pairs with the
|
||||
// ordinary `else` keyword (see modules/File_Watcher/module.jai).
|
||||
@@ -194,7 +198,7 @@ forStatement ::= 'for' [':' expr] forModifier_* [<<isForNamesAhead>> forNames ':
|
||||
private forModifier_ ::= '<' | '*'
|
||||
forNames ::= IDENT (',' IDENT)*
|
||||
|
||||
returnStatement ::= 'return' [expr (',' expr)*] NOTE* semi
|
||||
returnStatement ::= 'return' [expr (',' expr)*] semiWithNotes_
|
||||
breakStatement ::= 'break' [IDENT] semi
|
||||
continueStatement ::= 'continue' [IDENT] semi
|
||||
removeStatement ::= 'remove' [expr] semi
|
||||
@@ -202,23 +206,25 @@ deferStatement ::= ['`'] 'defer' statement
|
||||
pushContextStatement ::= ['`'] 'push_context' expr block
|
||||
usingStatement ::= 'using' [',' expr] expr semi
|
||||
|
||||
expressionStatement ::= expr (',' expr)* NOTE* semi
|
||||
expressionStatement ::= expr (',' expr)* semiWithNotes_
|
||||
|
||||
// ------------------------------------------------------------------- declarations
|
||||
|
||||
// Jai has no declaration keyword: `a : int = 1`, `a := 1`, `a :: 1`, `Foo :: struct {}`
|
||||
// and `main :: () {}` are all the same shape. The guard is what separates them from
|
||||
// an expression statement such as `foo();`.
|
||||
declaration ::= <<isDeclarationAhead>> declModifier_* declNames declTail_ NOTE* semi
|
||||
private declModifier_ ::= <<dirPlain>> | 'using'
|
||||
declNames ::= IDENT (',' IDENT)*
|
||||
private declTail_ ::= ':' [<<exprNoAssign>>] [('=' | ':') initializer]
|
||||
declaration ::= <<isDeclarationAhead>> declModifier_* declNames declTail_ semiWithNotes_
|
||||
// `#as using base: Document;`, `#overlay (unknown.vtable) using vtable: *Vtable;`
|
||||
private declModifier_ ::= procModifier | 'using'
|
||||
declNames ::= declName (',' declName)*
|
||||
declName ::= ['`'] IDENT
|
||||
private declTail_ ::= ':' [<<exprNoAssign>>] procModifier* [('=' | ':') initializer]
|
||||
| ':=' initializer
|
||||
| '::' initializer
|
||||
initializer ::= '---' | expr
|
||||
|
||||
// `operator + :: (a: T, b: T) -> T { }`
|
||||
operatorDeclaration ::= 'operator' operatorSymbol '::' expr NOTE* semi
|
||||
operatorDeclaration ::= 'operator' operatorSymbol '::' expr semiWithNotes_
|
||||
operatorSymbol ::= '+' | '-' | '*' | '/' | '%' | '==' | '!=' | '<' | '>' | '<=' | '>='
|
||||
| '&' | '|' | '^' | '~' | '<<' | '>>' | '<<<' | '>>>'
|
||||
| '[' ']' | '[' ']' '='
|
||||
@@ -239,6 +245,7 @@ expr ::= assignExpr
|
||||
| addExpr
|
||||
| mulExpr
|
||||
| prefixExpr
|
||||
| derefCastExpr
|
||||
| arrayTypeExpr
|
||||
| castExpr
|
||||
| autoCastExpr
|
||||
@@ -279,10 +286,14 @@ private prefixOp_ ::= '-' | '+' | '!' | '~' | '*' | '..' | '$' | '$$' | '<<' | '
|
||||
// element type. Distinct from indexExpr, which needs a left operand.
|
||||
arrayTypeExpr ::= '[' ['..' | expr] ']' expr
|
||||
|
||||
// `(.*) cast(*u32) p` — the postfix dereference written prefix-style in parentheses
|
||||
// (modules/Shared_Memory_Channel/module.jai:113).
|
||||
derefCastExpr ::= '(' '.*' ')' expr
|
||||
|
||||
castExpr ::= 'cast' [',' IDENT] '(' [expr] ')' expr
|
||||
autoCastExpr ::= 'xx' [',' IDENT] expr
|
||||
inlineExpr ::= ('inline' | 'no_inline') expr
|
||||
ifxExpr ::= 'ifx' expr ['then'] expr ['else' expr]
|
||||
ifxExpr ::= 'ifx' expr ['then'] [expr] ['else' expr]
|
||||
|
||||
callExpr ::= expr '(' [argList] ')'
|
||||
indexExpr ::= expr '[' [expr] ']'
|
||||
@@ -339,7 +350,8 @@ procLiteralExpr ::= <<isProcHeaderAhead>> '(' [paramList] ')' ['->' returnTypes_
|
||||
| '->' returnTypes_ procModifier* [block]
|
||||
|
||||
private paramList ::= parameter (',' parameter)* [',']
|
||||
parameter ::= ['using'] parameterTail_
|
||||
parameter ::= paramModifier_* parameterTail_
|
||||
private paramModifier_ ::= <<dirPlain>> | 'using'
|
||||
private parameterTail_ ::= <<isParamNameAhead>> paramNames paramTypeTail_ | '..' | expr
|
||||
paramNames ::= paramName (',' paramName)*
|
||||
paramName ::= ['$' | '$$'] IDENT
|
||||
@@ -349,12 +361,12 @@ private paramTypeTail_ ::= ':' [<<exprNoAssign>>] ['=' initializer]
|
||||
|
||||
private returnTypes_ ::= <<isReturnGroupAhead>> returnGroup | returnItem (',' returnItem)*
|
||||
returnGroup ::= '(' [returnItem (',' returnItem)*] ')'
|
||||
returnItem ::= [<<isParamNameAhead>> IDENT ':'] <<exprNoAssign>> ['=' initializer]
|
||||
returnItem ::= [<<isParamNameAhead>> IDENT ':'] <<exprNoAssign>>
|
||||
|
||||
// `#foreign lib`, `#modify { ... }`, `#c_call`, `#expand`, …
|
||||
procModifier ::= <<dirWithBlock>> block
|
||||
| <<dirWithOperand>> [',' IDENT] [expr]
|
||||
| <<dirPlain>> [',' IDENT]
|
||||
procModifier ::= <<dirWithBlock>> directiveFlag_* block
|
||||
| <<dirWithOperand>> directiveFlag_* [expr]
|
||||
| <<dirPlain>> directiveFlag_*
|
||||
|
||||
structExpr ::= 'struct' ['(' [paramList] ')'] structModifier_* block
|
||||
enumExpr ::= ('enum' | 'enum_flags') [!'{' expr] structModifier_* block
|
||||
@@ -365,7 +377,13 @@ private structModifier_ ::= procModifier
|
||||
|
||||
// `#ident` is one token, so which directives take operands is decided in
|
||||
// JaiParserUtil rather than here.
|
||||
directiveExpr ::= <<dir "#assert">> expr [expr]
|
||||
| <<dirWithBlock>> [',' IDENT] block
|
||||
| <<dirWithOperand>> [',' IDENT] [expr]
|
||||
| <<dirPlain>> [',' IDENT]
|
||||
directiveExpr ::= <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
|
||||
| <<dir "#assert">> expr [expr]
|
||||
| <<dir "#module_parameters">> '(' [paramList] ')' ['(' [paramList] ')'] [block]
|
||||
| <<dirWithBlock>> directiveFlag_* block
|
||||
| <<dirWithOperand>> directiveFlag_* [expr]
|
||||
| <<dirPlain>> directiveFlag_*
|
||||
|
||||
// `#import,file`, `#library,system,link_always`, `#run,stallable` — a directive can
|
||||
// carry any number of comma-separated flags.
|
||||
private directiveFlag_ ::= ',' IDENT
|
||||
|
||||
@@ -71,6 +71,7 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
"add_context",
|
||||
"module_parameters",
|
||||
"place",
|
||||
"overlay",
|
||||
"procedure_of_call",
|
||||
"body_text",
|
||||
"version",
|
||||
@@ -85,7 +86,6 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
"elsewhere",
|
||||
"expand",
|
||||
"specified",
|
||||
"discard",
|
||||
"location",
|
||||
"this",
|
||||
)
|
||||
@@ -286,9 +286,13 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
): Boolean = b.tokenType === T.LPAREN && !isProcHeaderAhead(b, level)
|
||||
|
||||
/**
|
||||
* `[#directive|using]* IDENT (',' IDENT)* (':' | '::' | ':=')` — a declaration.
|
||||
* Jai declarations have no introducer keyword, so this is what tells
|
||||
* `[#directive [(…)] | using | `]* IDENT (',' IDENT)* (':' | '::' | ':=')` — a
|
||||
* declaration. Jai declarations have no introducer keyword, so this is what tells
|
||||
* `foo :: () {}` apart from `foo();`.
|
||||
*
|
||||
* The prefix skip covers `#as using base: Document;`,
|
||||
* `#overlay (unknown.vtable) using vtable: *Vtable;` and the macro-exported
|
||||
* `` `it := entry.value; ``.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isDeclarationAhead(
|
||||
@@ -296,11 +300,24 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
level: Int,
|
||||
): Boolean {
|
||||
var i = 0
|
||||
while (true) {
|
||||
val t = b.lookAhead(i) ?: return false
|
||||
if (t === T.DIRECTIVE || t === T.KW_USING) i++ else break
|
||||
loop@ while (true) {
|
||||
when (b.lookAhead(i)) {
|
||||
T.DIRECTIVE, T.KW_USING -> {
|
||||
i++
|
||||
}
|
||||
|
||||
T.LPAREN -> {
|
||||
i = skipBalancedParens(b, i)
|
||||
if (i < 0) return false
|
||||
}
|
||||
|
||||
else -> {
|
||||
break@loop
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true) {
|
||||
if (b.lookAhead(i) === T.BACKTICK) i++
|
||||
if (b.lookAhead(i) !== T.IDENT) return false
|
||||
i++
|
||||
when (b.lookAhead(i)) {
|
||||
@@ -311,6 +328,61 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
}
|
||||
}
|
||||
|
||||
/** Index just past the `)` matching the `(` at [start], or -1 if unbalanced. */
|
||||
private fun skipBalancedParens(
|
||||
b: PsiBuilder,
|
||||
start: Int,
|
||||
): Int {
|
||||
var depth = 0
|
||||
var i = start
|
||||
while (i - start <= MAX_LOOKAHEAD) {
|
||||
when (b.lookAhead(i) ?: return -1) {
|
||||
T.LPAREN -> {
|
||||
depth++
|
||||
}
|
||||
|
||||
T.RPAREN -> {
|
||||
depth--
|
||||
if (depth == 0) return i + 1
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
i++
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes a `{ … }` block as opaque tokens.
|
||||
*
|
||||
* Used for `#asm`, whose body is x86-64 assembly (`movd source:, byte;`) and not
|
||||
* Jai at all. Giving it structure is a separate job; tiling it keeps the
|
||||
* surrounding file parseable.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun opaqueBlock(
|
||||
b: PsiBuilder,
|
||||
level: Int,
|
||||
): Boolean {
|
||||
if (b.tokenType !== T.LBRACE) return false
|
||||
var depth = 0
|
||||
while (!b.eof()) {
|
||||
val t = b.tokenType
|
||||
if (t === T.LBRACE) {
|
||||
depth++
|
||||
} else if (t === T.RBRACE) {
|
||||
depth--
|
||||
if (depth == 0) {
|
||||
b.advanceLexer()
|
||||
return true
|
||||
}
|
||||
}
|
||||
b.advanceLexer()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** `[$|$$] IDENT (',' [$|$$] IDENT)* (':' | '::' | ':=')` — a named parameter. */
|
||||
@JvmStatic
|
||||
fun isParamNameAhead(
|
||||
|
||||
104
src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt
Normal file
104
src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt
Normal file
@@ -0,0 +1,104 @@
|
||||
package dev.hgh.jai.parser
|
||||
|
||||
import com.intellij.psi.PsiErrorElement
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
import dev.hgh.jai.JaiLanguage
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Scratch harness for grammar work. Not a gate — the gate is [JaiCorpusParserTest].
|
||||
*
|
||||
* Set `-Djai.debug.file=<path>` to dump every error in one corpus file instead.
|
||||
*/
|
||||
class DebugParseTest : BasePlatformTestCase() {
|
||||
private val snippets =
|
||||
listOf(
|
||||
"tzname: **u8 #elsewhere libc;\n",
|
||||
"S :: struct {\n #as unknown: IUnknown;\n}\n",
|
||||
"x.magic = (.*) cast(*u32) DATA.data;\n",
|
||||
"M :: #library,system,link_always \"Metal\";\n",
|
||||
"f :: (s: *u8, \$strict := false) -> u32 { return 1; }\n",
|
||||
"#module_parameters (MAX := 4, VERBOSE := false);\n",
|
||||
"Allocator_Proc :: #type (mode: int, old: *void) -> *void;\n",
|
||||
"SimpleProcedure :: #type () -> ();\n",
|
||||
"n := tprint(\"%\", ifx options.output_path else \".\");\n",
|
||||
"v :: (info: *File_Visit_Info, modules : *[..] string) { }\n",
|
||||
"B :: struct (type: Type, by_pointer := false) { }\n",
|
||||
"e := ifx a then b;\n",
|
||||
)
|
||||
|
||||
/** Corpus files to dump the first error of; edit freely while working. */
|
||||
private val corpusFiles =
|
||||
listOf(
|
||||
"modules/Sound_Player/os/win32.jai",
|
||||
"examples/module_info.jai",
|
||||
"how_to/800_allocators.jai",
|
||||
"modules/POSIX/module.jai",
|
||||
"modules/Basic/module.jai",
|
||||
"modules/Compiler/module.jai",
|
||||
"modules/Window_Creation/module.jai",
|
||||
"modules/String/module.jai",
|
||||
"modules/Hash_Table.jai",
|
||||
"modules/Math/module.jai",
|
||||
)
|
||||
|
||||
fun testCorpusFiles() {
|
||||
val root = File(System.getProperty("user.home"), ".local/jai")
|
||||
if (!root.exists()) return
|
||||
for (relative in corpusFiles) {
|
||||
val file = File(root, relative)
|
||||
if (file.exists()) dumpFile(file) else println("missing: $relative")
|
||||
}
|
||||
}
|
||||
|
||||
fun testSnippets() {
|
||||
val debugFile = System.getProperty("jai.debug.file")
|
||||
if (debugFile != null) {
|
||||
dumpFile(File(debugFile))
|
||||
return
|
||||
}
|
||||
val factory = PsiFileFactory.getInstance(project)
|
||||
var failures = 0
|
||||
for (text in snippets) {
|
||||
val file = factory.createFileFromText("t.jai", JaiLanguage, text)
|
||||
val error = firstError(file)
|
||||
if (error == null) {
|
||||
println("ok ${text.replace("\n", "\\n")}")
|
||||
} else {
|
||||
failures++
|
||||
val at = text.substring(error.textOffset).take(28).replace("\n", "\\n")
|
||||
println("FAIL ${text.replace("\n", "\\n")}")
|
||||
println(" ${error.errorDescription} | at '$at'")
|
||||
}
|
||||
}
|
||||
println("$failures/${snippets.size} snippets failed")
|
||||
}
|
||||
|
||||
private fun dumpFile(file: File) {
|
||||
val text = file.readText()
|
||||
val psi = PsiFileFactory.getInstance(project).createFileFromText(file.name, JaiLanguage, text)
|
||||
val error = firstError(psi)
|
||||
if (error == null) {
|
||||
println("${file.name}: clean")
|
||||
return
|
||||
}
|
||||
val line = text.substring(0, error.textOffset).count { it == '\n' } + 1
|
||||
println("${file.name}:$line: ${error.errorDescription}")
|
||||
println(" at '${text.substring(error.textOffset).take(80).replace("\n", "\\n")}'")
|
||||
}
|
||||
|
||||
private fun firstError(file: com.intellij.psi.PsiFile): PsiErrorElement? {
|
||||
var first: PsiErrorElement? = null
|
||||
file.accept(
|
||||
object : PsiRecursiveElementWalkingVisitor() {
|
||||
override fun visitErrorElement(element: PsiErrorElement) {
|
||||
if (first == null) first = element
|
||||
super.visitErrorElement(element)
|
||||
}
|
||||
},
|
||||
)
|
||||
return first
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ Jai File(0,49)
|
||||
JaiStatementImpl(STATEMENT)(0,17)
|
||||
JaiDeclarationImpl(DECLARATION)(0,17)
|
||||
JaiDeclNamesImpl(DECL_NAMES)(0,1)
|
||||
JaiDeclNameImpl(DECL_NAME)(0,1)
|
||||
PsiElement(Jai:IDENT)('a')(0,1)
|
||||
PsiElement(Jai::)(':')(2,3)
|
||||
JaiRefExprImpl(REF_EXPR)(4,9)
|
||||
@@ -14,6 +15,7 @@ Jai File(0,49)
|
||||
JaiStatementImpl(STATEMENT)(18,26)
|
||||
JaiDeclarationImpl(DECLARATION)(18,26)
|
||||
JaiDeclNamesImpl(DECL_NAMES)(18,19)
|
||||
JaiDeclNameImpl(DECL_NAME)(18,19)
|
||||
PsiElement(Jai:IDENT)('b')(18,19)
|
||||
PsiElement(Jai::=)(':=')(20,22)
|
||||
JaiInitializerImpl(INITIALIZER)(23,25)
|
||||
@@ -23,6 +25,7 @@ Jai File(0,49)
|
||||
JaiStatementImpl(STATEMENT)(27,35)
|
||||
JaiDeclarationImpl(DECLARATION)(27,35)
|
||||
JaiDeclNamesImpl(DECL_NAMES)(27,28)
|
||||
JaiDeclNameImpl(DECL_NAME)(27,28)
|
||||
PsiElement(Jai:IDENT)('c')(27,28)
|
||||
PsiElement(Jai:::)('::')(29,31)
|
||||
JaiInitializerImpl(INITIALIZER)(32,34)
|
||||
|
||||
Reference in New Issue
Block a user