Parser: corpus parse rate 81% -> 90%

A bare procedure *type* parameter such as 'proc: (info: *Info, data: T)' has no
arrow, directive or body after the parentheses, so isProcHeaderAhead now accepts
any parenthesised group that contains a ':' or '$' at depth 1.

Also: compound-assignment operator overloads, 'for <=REVERSE *=BY_POINTER',
backticked loop variables and returns, 'cast(T, value)', postfix 'x.(T)' casts,
'{}' as the zero value, '#asm AVX, AVX2 { … }', 'push_context,defer_pop', and
'#string,\%' here-strings (used in how_to/018_print_functions.jai, which the
shipped Jai_Lexer module itself rejects).

A directive prefixing a declaration no longer takes a bare operand: '#add_context
deep_copy_depth: int;' had the directive eating the declared name.

Ratchet raised to 640/714.
This commit is contained in:
hgranthorner
2026-08-04 12:24:02 -04:00
parent 086ae993c5
commit b8e55fcd50
19 changed files with 550 additions and 78 deletions

View File

@@ -43,10 +43,11 @@ public class JaiParser implements PsiParser, LightPsiParser {
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),
PAREN_EXPR, POSTFIX_CAST_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,
ZERO_LITERAL_EXPR),
};
/* ********************************************************** */
@@ -361,12 +362,79 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// procModifier | usingModifier_
// <<dirWithBlock>> directiveFlag_* block
// | <<dirPlain>> directiveFlag_* [parenExpr | STRING]
// | usingModifier_
static boolean declModifier_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier_")) return false;
boolean result_;
result_ = procModifier(builder_, level_ + 1);
Marker marker_ = enter_section_(builder_);
result_ = declModifier__0(builder_, level_ + 1);
if (!result_) result_ = declModifier__1(builder_, level_ + 1);
if (!result_) result_ = usingModifier_(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// <<dirWithBlock>> directiveFlag_* block
private static boolean declModifier__0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier__0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = dirWithBlock(builder_, level_ + 1);
result_ = result_ && declModifier__0_1(builder_, level_ + 1);
result_ = result_ && block(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// directiveFlag_*
private static boolean declModifier__0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier__0_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "declModifier__0_1", pos_)) break;
}
return true;
}
// <<dirPlain>> directiveFlag_* [parenExpr | STRING]
private static boolean declModifier__1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier__1")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = dirPlain(builder_, level_ + 1);
result_ = result_ && declModifier__1_1(builder_, level_ + 1);
result_ = result_ && declModifier__1_2(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// directiveFlag_*
private static boolean declModifier__1_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier__1_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "declModifier__1_1", pos_)) break;
}
return true;
}
// [parenExpr | STRING]
private static boolean declModifier__1_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier__1_2")) return false;
declModifier__1_2_0(builder_, level_ + 1);
return true;
}
// parenExpr | STRING
private static boolean declModifier__1_2_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier__1_2_0")) return false;
boolean result_;
result_ = parenExpr(builder_, level_ + 1);
if (!result_) result_ = consumeToken(builder_, STRING);
return result_;
}
@@ -587,7 +655,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
// <<dir "#asm">> directiveFlag_* [expr (',' expr)*] <<opaqueBlock>>
// | <<dir "#foreign">> directiveFlag_* [<<exprNoAssign>>] [STRING]
// | <<dir "#elsewhere">> directiveFlag_* [<<exprNoAssign>>] [STRING]
// | <<dir "#insert">> directiveFlag_* ['(' [argList] ')'] [block | expr]
@@ -613,13 +681,14 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
// <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
// <<dir "#asm">> directiveFlag_* [expr (',' expr)*] <<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_ && directiveExpr_0_2(builder_, level_ + 1);
result_ = result_ && opaqueBlock(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
@@ -636,6 +705,46 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// [expr (',' expr)*]
private static boolean directiveExpr_0_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_0_2")) return false;
directiveExpr_0_2_0(builder_, level_ + 1);
return true;
}
// expr (',' expr)*
private static boolean directiveExpr_0_2_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_0_2_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = expr(builder_, level_ + 1, -1);
result_ = result_ && directiveExpr_0_2_0_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// (',' expr)*
private static boolean directiveExpr_0_2_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_0_2_0_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveExpr_0_2_0_1_0(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "directiveExpr_0_2_0_1", pos_)) break;
}
return true;
}
// ',' expr
private static boolean directiveExpr_0_2_0_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_0_2_0_1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COMMA);
result_ = result_ && expr(builder_, level_ + 1, -1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// <<dir "#foreign">> directiveFlag_* [<<exprNoAssign>>] [STRING]
private static boolean directiveExpr_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_1")) return false;
@@ -1076,30 +1185,75 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// '<' | '*'
// '<=' expr | '*=' expr | '<' | '*'
static boolean forModifier_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forModifier_")) return false;
if (!nextTokenIs(builder_, "", LT, STAR)) return false;
boolean result_;
result_ = consumeToken(builder_, LT);
Marker marker_ = enter_section_(builder_);
result_ = forModifier__0(builder_, level_ + 1);
if (!result_) result_ = forModifier__1(builder_, level_ + 1);
if (!result_) result_ = consumeToken(builder_, LT);
if (!result_) result_ = consumeToken(builder_, STAR);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// '<=' expr
private static boolean forModifier__0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forModifier__0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, LT_EQ);
result_ = result_ && expr(builder_, level_ + 1, -1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// '*=' expr
private static boolean forModifier__1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forModifier__1")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, STAR_EQ);
result_ = result_ && expr(builder_, level_ + 1, -1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// IDENT (',' IDENT)*
public static boolean forNames(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forNames")) return false;
if (!nextTokenIs(builder_, IDENT)) return false;
// ['`'] IDENT
public static boolean forName(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forName")) return false;
if (!nextTokenIs(builder_, "<for name>", BACKTICK, IDENT)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, IDENT);
result_ = result_ && forNames_1(builder_, level_ + 1);
exit_section_(builder_, marker_, FOR_NAMES, result_);
Marker marker_ = enter_section_(builder_, level_, _NONE_, FOR_NAME, "<for name>");
result_ = forName_0(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, IDENT);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
}
// (',' IDENT)*
// ['`']
private static boolean forName_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forName_0")) return false;
consumeToken(builder_, BACKTICK);
return true;
}
/* ********************************************************** */
// forName (',' forName)*
public static boolean forNames(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forNames")) return false;
if (!nextTokenIs(builder_, "<for names>", BACKTICK, IDENT)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, FOR_NAMES, "<for names>");
result_ = forName(builder_, level_ + 1);
result_ = result_ && forNames_1(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
}
// (',' forName)*
private static boolean forNames_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forNames_1")) return false;
while (true) {
@@ -1110,12 +1264,13 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// ',' IDENT
// ',' forName
private static boolean forNames_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "forNames_1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeTokens(builder_, 0, COMMA, IDENT);
result_ = consumeToken(builder_, COMMA);
result_ = result_ && forName(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
@@ -1479,6 +1634,8 @@ public class JaiParser implements PsiParser, LightPsiParser {
/* ********************************************************** */
// '+' | '-' | '*' | '/' | '%' | '==' | '!=' | '<' | '>' | '<=' | '>='
// | '&' | '|' | '^' | '~' | '<<' | '>>' | '<<<' | '>>>'
// | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^='
// | '<<=' | '>>=' | '<<<=' | '>>>='
// | '[' ']' '=' | '[' ']'
public static boolean operatorSymbol(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "operatorSymbol")) return false;
@@ -1503,6 +1660,18 @@ public class JaiParser implements PsiParser, LightPsiParser {
if (!result_) result_ = consumeToken(builder_, SHR);
if (!result_) result_ = consumeToken(builder_, ROL);
if (!result_) result_ = consumeToken(builder_, ROR);
if (!result_) result_ = consumeToken(builder_, PLUS_EQ);
if (!result_) result_ = consumeToken(builder_, MINUS_EQ);
if (!result_) result_ = consumeToken(builder_, STAR_EQ);
if (!result_) result_ = consumeToken(builder_, SLASH_EQ);
if (!result_) result_ = consumeToken(builder_, PERCENT_EQ);
if (!result_) result_ = consumeToken(builder_, AND_EQ);
if (!result_) result_ = consumeToken(builder_, OR_EQ);
if (!result_) result_ = consumeToken(builder_, XOR_EQ);
if (!result_) result_ = consumeToken(builder_, SHL_EQ);
if (!result_) result_ = consumeToken(builder_, SHR_EQ);
if (!result_) result_ = consumeToken(builder_, ROL_EQ);
if (!result_) result_ = consumeToken(builder_, ROR_EQ);
if (!result_) result_ = parseTokens(builder_, 0, LBRACKET, RBRACKET, EQ);
if (!result_) result_ = parseTokens(builder_, 0, LBRACKET, RBRACKET);
exit_section_(builder_, level_, marker_, result_, false, null);
@@ -1934,7 +2103,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// ['`'] 'push_context' [expr] block
// ['`'] 'push_context' directiveFlag_* [expr] block
public static boolean pushContextStatement(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "pushContextStatement")) return false;
if (!nextTokenIs(builder_, "<push context statement>", BACKTICK, KW_PUSH_CONTEXT)) return false;
@@ -1943,6 +2112,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
result_ = pushContextStatement_0(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, KW_PUSH_CONTEXT);
result_ = result_ && pushContextStatement_2(builder_, level_ + 1);
result_ = result_ && pushContextStatement_3(builder_, level_ + 1);
result_ = result_ && block(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
@@ -1955,9 +2125,20 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// [expr]
// directiveFlag_*
private static boolean pushContextStatement_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "pushContextStatement_2")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "pushContextStatement_2", pos_)) break;
}
return true;
}
// [expr]
private static boolean pushContextStatement_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "pushContextStatement_3")) return false;
expr(builder_, level_ + 1, -1);
return true;
}
@@ -2080,51 +2261,59 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// 'return' [expr (',' expr)*] semiWithNotes_
// ['`'] '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;
if (!nextTokenIs(builder_, "<return statement>", BACKTICK, KW_RETURN)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, KW_RETURN);
result_ = result_ && returnStatement_1(builder_, level_ + 1);
Marker marker_ = enter_section_(builder_, level_, _NONE_, RETURN_STATEMENT, "<return statement>");
result_ = returnStatement_0(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, KW_RETURN);
result_ = result_ && returnStatement_2(builder_, level_ + 1);
result_ = result_ && semiWithNotes_(builder_, level_ + 1);
exit_section_(builder_, marker_, RETURN_STATEMENT, result_);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
}
// ['`']
private static boolean returnStatement_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_0")) return false;
consumeToken(builder_, BACKTICK);
return true;
}
// [expr (',' expr)*]
private static boolean returnStatement_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_1")) return false;
returnStatement_1_0(builder_, level_ + 1);
private static boolean returnStatement_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_2")) return false;
returnStatement_2_0(builder_, level_ + 1);
return true;
}
// expr (',' expr)*
private static boolean returnStatement_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_1_0")) return false;
private static boolean returnStatement_2_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_2_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = expr(builder_, level_ + 1, -1);
result_ = result_ && returnStatement_1_0_1(builder_, level_ + 1);
result_ = result_ && returnStatement_2_0_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// (',' expr)*
private static boolean returnStatement_1_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_1_0_1")) return false;
private static boolean returnStatement_2_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_2_0_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!returnStatement_1_0_1_0(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "returnStatement_1_0_1", pos_)) break;
if (!returnStatement_2_0_1_0(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "returnStatement_2_0_1", pos_)) break;
}
return true;
}
// ',' expr
private static boolean returnStatement_1_0_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_1_0_1_0")) return false;
private static boolean returnStatement_2_0_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "returnStatement_2_0_1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COMMA);
@@ -2605,6 +2794,18 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
/* ********************************************************** */
// '{' '}'
public static boolean zeroLiteralExpr(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "zeroLiteralExpr")) return false;
if (!nextTokenIs(builder_, LBRACE)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeTokens(builder_, 0, LBRACE, RBRACE);
exit_section_(builder_, marker_, ZERO_LITERAL_EXPR, result_);
return result_;
}
/* ********************************************************** */
// Expression root: expr
// Operator priority table:
@@ -2629,12 +2830,13 @@ public class JaiParser implements PsiParser, LightPsiParser {
// 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)
// 21: POSTFIX(postfixCastExpr)
// 22: POSTFIX(indexExpr)
// 23: POSTFIX(memberExpr)
// 24: POSTFIX(derefExpr)
// 25: POSTFIX(typedStructLiteralExpr)
// 26: POSTFIX(typedArrayLiteralExpr)
// 27: ATOM(primaryExpr)
public static boolean expr(PsiBuilder builder_, int level_, int priority_) {
if (!recursion_guard_(builder_, level_, "expr")) return false;
addVariant(builder_, "<expr>");
@@ -2715,23 +2917,27 @@ public class JaiParser implements PsiParser, LightPsiParser {
result_ = true;
exit_section_(builder_, level_, marker_, CALL_EXPR, result_, true, null);
}
else if (priority_ < 21 && indexExpr_0(builder_, level_ + 1)) {
else if (priority_ < 21 && postfixCastExpr_0(builder_, level_ + 1)) {
result_ = true;
exit_section_(builder_, level_, marker_, POSTFIX_CAST_EXPR, result_, true, null);
}
else if (priority_ < 22 && indexExpr_0(builder_, level_ + 1)) {
result_ = true;
exit_section_(builder_, level_, marker_, INDEX_EXPR, result_, true, null);
}
else if (priority_ < 22 && memberExpr_0(builder_, level_ + 1)) {
else if (priority_ < 23 && memberExpr_0(builder_, level_ + 1)) {
result_ = true;
exit_section_(builder_, level_, marker_, MEMBER_EXPR, result_, true, null);
}
else if (priority_ < 23 && consumeTokenSmart(builder_, POSTFIX_DEREFERENCE)) {
else if (priority_ < 24 && consumeTokenSmart(builder_, POSTFIX_DEREFERENCE)) {
result_ = true;
exit_section_(builder_, level_, marker_, DEREF_EXPR, result_, true, null);
}
else if (priority_ < 24 && typedStructLiteralExpr_0(builder_, level_ + 1)) {
else if (priority_ < 25 && typedStructLiteralExpr_0(builder_, level_ + 1)) {
result_ = true;
exit_section_(builder_, level_, marker_, TYPED_STRUCT_LITERAL_EXPR, result_, true, null);
}
else if (priority_ < 25 && typedArrayLiteralExpr_0(builder_, level_ + 1)) {
else if (priority_ < 26 && typedArrayLiteralExpr_0(builder_, level_ + 1)) {
result_ = true;
exit_section_(builder_, level_, marker_, TYPED_ARRAY_LITERAL_EXPR, result_, true, null);
}
@@ -2849,7 +3055,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
// 'cast' [',' IDENT] '(' [expr] ')' expr
// 'cast' directiveFlag_* '(' [expr (',' expr)*] ')' [expr]
public static boolean castExpr(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr")) return false;
if (!nextTokenIsSmart(builder_, KW_CAST)) return false;
@@ -2860,21 +3066,65 @@ public class JaiParser implements PsiParser, LightPsiParser {
result_ = result_ && consumeToken(builder_, LPAREN);
result_ = result_ && castExpr_3(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, RPAREN);
result_ = result_ && expr(builder_, level_ + 1, -1);
result_ = result_ && castExpr_5(builder_, level_ + 1);
exit_section_(builder_, marker_, CAST_EXPR, result_);
return result_;
}
// [',' IDENT]
// directiveFlag_*
private static boolean castExpr_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_1")) return false;
parseTokensSmart(builder_, 0, COMMA, IDENT);
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "castExpr_1", pos_)) break;
}
return true;
}
// [expr]
// [expr (',' expr)*]
private static boolean castExpr_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_3")) return false;
castExpr_3_0(builder_, level_ + 1);
return true;
}
// expr (',' expr)*
private static boolean castExpr_3_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_3_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = expr(builder_, level_ + 1, -1);
result_ = result_ && castExpr_3_0_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// (',' expr)*
private static boolean castExpr_3_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_3_0_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!castExpr_3_0_1_0(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "castExpr_3_0_1", pos_)) break;
}
return true;
}
// ',' expr
private static boolean castExpr_3_0_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_3_0_1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeTokenSmart(builder_, COMMA);
result_ = result_ && expr(builder_, level_ + 1, -1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [expr]
private static boolean castExpr_5(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "castExpr_5")) return false;
expr(builder_, level_ + 1, -1);
return true;
}
@@ -2995,6 +3245,25 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// '.' '(' [expr] ')'
private static boolean postfixCastExpr_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "postfixCastExpr_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeTokensSmart(builder_, 0, DOT, LPAREN);
result_ = result_ && postfixCastExpr_0_2(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, RPAREN);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [expr]
private static boolean postfixCastExpr_0_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "postfixCastExpr_0_2")) return false;
expr(builder_, level_ + 1, -1);
return true;
}
// '[' [expr] ']'
private static boolean indexExpr_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "indexExpr_0")) return false;
@@ -3076,6 +3345,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
// | builtinCallExpr
// | interfaceExpr
// | literalExpr
// | zeroLiteralExpr
// | refExpr
// | uninitializedExpr
public static boolean primaryExpr(PsiBuilder builder_, int level_) {
@@ -3095,6 +3365,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
if (!result_) result_ = builtinCallExpr(builder_, level_ + 1);
if (!result_) result_ = interfaceExpr(builder_, level_ + 1);
if (!result_) result_ = literalExpr(builder_, level_ + 1);
if (!result_) result_ = zeroLiteralExpr(builder_, level_ + 1);
if (!result_) result_ = refExpr(builder_, level_ + 1);
if (!result_) result_ = uninitializedExpr(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, result_, false, null);

View File

@@ -10,12 +10,18 @@ public interface JaiDeclaration extends PsiElement {
@NotNull
List<JaiArgument> getArgumentList();
@NotNull
List<JaiBlock> getBlockList();
@NotNull
JaiDeclNames getDeclNames();
@NotNull
List<JaiInitializer> getInitializerList();
@NotNull
List<JaiParenExpr> getParenExprList();
@NotNull
List<JaiProcModifier> getProcModifierList();

View File

@@ -13,8 +13,8 @@ public interface JaiDirectiveExpr extends JaiExpr {
@Nullable
JaiBlock getBlock();
@Nullable
JaiExpr getExpr();
@NotNull
List<JaiExpr> getExprList();
@NotNull
List<JaiParameter> getParameterList();

View 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 JaiForName extends PsiElement {
}

View File

@@ -7,4 +7,7 @@ import com.intellij.psi.PsiElement;
public interface JaiForNames extends PsiElement {
@NotNull
List<JaiForName> getForNameList();
}

View 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 JaiPostfixCastExpr extends JaiExpr {
@NotNull
List<JaiExpr> getExprList();
}

View File

@@ -40,6 +40,7 @@ public interface JaiTypes {
IElementType EQUALITY_EXPR = new JaiElementType("EQUALITY_EXPR");
IElementType EXPR = new JaiElementType("EXPR");
IElementType EXPRESSION_STATEMENT = new JaiElementType("EXPRESSION_STATEMENT");
IElementType FOR_NAME = new JaiElementType("FOR_NAME");
IElementType FOR_NAMES = new JaiElementType("FOR_NAMES");
IElementType FOR_STATEMENT = new JaiElementType("FOR_STATEMENT");
IElementType IFX_EXPR = new JaiElementType("IFX_EXPR");
@@ -62,6 +63,7 @@ public interface JaiTypes {
IElementType PARAM_NAME = new JaiElementType("PARAM_NAME");
IElementType PARAM_NAMES = new JaiElementType("PARAM_NAMES");
IElementType PAREN_EXPR = new JaiElementType("PAREN_EXPR");
IElementType POSTFIX_CAST_EXPR = new JaiElementType("POSTFIX_CAST_EXPR");
IElementType PREFIX_EXPR = new JaiElementType("PREFIX_EXPR");
IElementType PRIMARY_EXPR = new JaiElementType("PRIMARY_EXPR");
IElementType PROC_LITERAL_EXPR = new JaiElementType("PROC_LITERAL_EXPR");
@@ -86,6 +88,7 @@ public interface JaiTypes {
IElementType UNION_EXPR = new JaiElementType("UNION_EXPR");
IElementType USING_STATEMENT = new JaiElementType("USING_STATEMENT");
IElementType WHILE_STATEMENT = new JaiElementType("WHILE_STATEMENT");
IElementType ZERO_LITERAL_EXPR = new JaiElementType("ZERO_LITERAL_EXPR");
IElementType AND = JaiTokenTypes.byName("&");
IElementType AND_AND = JaiTokenTypes.byName("&&");
@@ -289,6 +292,9 @@ public interface JaiTypes {
else if (type == EXPRESSION_STATEMENT) {
return new JaiExpressionStatementImpl(node);
}
else if (type == FOR_NAME) {
return new JaiForNameImpl(node);
}
else if (type == FOR_NAMES) {
return new JaiForNamesImpl(node);
}
@@ -355,6 +361,9 @@ public interface JaiTypes {
else if (type == PAREN_EXPR) {
return new JaiParenExprImpl(node);
}
else if (type == POSTFIX_CAST_EXPR) {
return new JaiPostfixCastExprImpl(node);
}
else if (type == PREFIX_EXPR) {
return new JaiPrefixExprImpl(node);
}
@@ -424,6 +433,9 @@ public interface JaiTypes {
else if (type == WHILE_STATEMENT) {
return new JaiWhileStatementImpl(node);
}
else if (type == ZERO_LITERAL_EXPR) {
return new JaiZeroLiteralExprImpl(node);
}
throw new AssertionError("Unknown element type: " + type);
}
}

View File

@@ -131,6 +131,10 @@ public class JaiVisitor extends PsiElementVisitor {
visitPsiElement(o);
}
public void visitForName(@NotNull JaiForName o) {
visitPsiElement(o);
}
public void visitForNames(@NotNull JaiForNames o) {
visitPsiElement(o);
}
@@ -219,6 +223,10 @@ public class JaiVisitor extends PsiElementVisitor {
visitExpr(o);
}
public void visitPostfixCastExpr(@NotNull JaiPostfixCastExpr o) {
visitExpr(o);
}
public void visitPrefixExpr(@NotNull JaiPrefixExpr o) {
visitExpr(o);
}
@@ -315,6 +323,10 @@ public class JaiVisitor extends PsiElementVisitor {
visitPsiElement(o);
}
public void visitZeroLiteralExpr(@NotNull JaiZeroLiteralExpr o) {
visitExpr(o);
}
public void visitPsiElement(@NotNull PsiElement o) {
visitElement(o);
}

View 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 JaiZeroLiteralExpr extends JaiExpr {
}

View File

@@ -33,6 +33,12 @@ public class JaiDeclarationImpl extends ASTWrapperPsiElement implements JaiDecla
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiArgument.class);
}
@Override
@NotNull
public List<JaiBlock> getBlockList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiBlock.class);
}
@Override
@NotNull
public JaiDeclNames getDeclNames() {
@@ -45,6 +51,12 @@ public class JaiDeclarationImpl extends ASTWrapperPsiElement implements JaiDecla
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiInitializer.class);
}
@Override
@NotNull
public List<JaiParenExpr> getParenExprList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiParenExpr.class);
}
@Override
@NotNull
public List<JaiProcModifier> getProcModifierList() {

View File

@@ -40,9 +40,9 @@ public class JaiDirectiveExprImpl extends JaiExprImpl implements JaiDirectiveExp
}
@Override
@Nullable
public JaiExpr getExpr() {
return findChildByClass(JaiExpr.class);
@NotNull
public List<JaiExpr> getExprList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiExpr.class);
}
@Override

View 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 JaiForNameImpl extends ASTWrapperPsiElement implements JaiForName {
public JaiForNameImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull JaiVisitor visitor) {
visitor.visitForName(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JaiVisitor) accept((JaiVisitor)visitor);
else super.accept(visitor);
}
}

View File

@@ -27,4 +27,10 @@ public class JaiForNamesImpl extends ASTWrapperPsiElement implements JaiForNames
else super.accept(visitor);
}
@Override
@NotNull
public List<JaiForName> getForNameList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiForName.class);
}
}

View 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 JaiPostfixCastExprImpl extends JaiExprImpl implements JaiPostfixCastExpr {
public JaiPostfixCastExprImpl(@NotNull ASTNode node) {
super(node);
}
@Override
public void accept(@NotNull JaiVisitor visitor) {
visitor.visitPostfixCastExpr(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JaiVisitor) accept((JaiVisitor)visitor);
else super.accept(visitor);
}
@Override
@NotNull
public List<JaiExpr> getExprList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiExpr.class);
}
}

View 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 dev.hgh.jai.psi.*;
public class JaiZeroLiteralExprImpl extends JaiExprImpl implements JaiZeroLiteralExpr {
public JaiZeroLiteralExprImpl(@NotNull ASTNode node) {
super(node);
}
@Override
public void accept(@NotNull JaiVisitor visitor) {
visitor.visitZeroLiteralExpr(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JaiVisitor) accept((JaiVisitor)visitor);
else super.accept(visitor);
}
}

View File

@@ -195,15 +195,16 @@ whileStatement ::= 'while' [<<isLabelAhead>> IDENT ':'] expr statement
// `for < * name, index : iterable` — `<` reverses, `*` iterates by pointer, and
// `for :expansion` selects a named for_expansion.
forStatement ::= 'for' [':' expr] forModifier_* [<<isForNamesAhead>> forNames ':'] expr statement
private forModifier_ ::= '<' | '*'
forNames ::= IDENT (',' IDENT)*
private forModifier_ ::= '<=' expr | '*=' expr | '<' | '*'
forNames ::= forName (',' forName)*
forName ::= ['`'] IDENT
returnStatement ::= 'return' [expr (',' expr)*] semiWithNotes_
returnStatement ::= ['`'] 'return' [expr (',' expr)*] semiWithNotes_
breakStatement ::= 'break' [IDENT] semi
continueStatement ::= 'continue' [IDENT] semi
removeStatement ::= 'remove' [expr] semi
deferStatement ::= ['`'] 'defer' statement
pushContextStatement ::= ['`'] 'push_context' [expr] block
pushContextStatement ::= ['`'] 'push_context' directiveFlag_* [expr] block
usingStatement ::= 'using' [',' expr] expr semi
expressionStatement ::= expr (',' expr)* semiWithNotes_
@@ -216,7 +217,9 @@ expressionStatement ::= expr (',' expr)* semiWithNotes_
declaration ::= <<isDeclarationAhead>> declModifier_* declNames declTail_ semiWithNotes_
// `#as using base: Document;`, `#overlay (unknown.vtable) using vtable: *Vtable;`,
// `#as using,except(vtable) iunknown: IUnknown;`
private declModifier_ ::= procModifier | usingModifier_
private declModifier_ ::= <<dirWithBlock>> directiveFlag_* block
| <<dirPlain>> directiveFlag_* [parenExpr | STRING]
| usingModifier_
private usingModifier_ ::= 'using' [directiveFlag_ ['(' [argList] ')']]
declNames ::= declName (',' declName)*
declName ::= ['`'] IDENT
@@ -234,6 +237,8 @@ initializer ::= '---' | expr
operatorDeclaration ::= 'operator' operatorSymbol '::' expr semiWithNotes_
operatorSymbol ::= '+' | '-' | '*' | '/' | '%' | '==' | '!=' | '<' | '>' | '<=' | '>='
| '&' | '|' | '^' | '~' | '<<' | '>>' | '<<<' | '>>>'
| '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^='
| '<<=' | '>>=' | '<<<=' | '>>>='
| '[' ']' '=' | '[' ']'
// -------------------------------------------------------------------- expressions
@@ -259,6 +264,7 @@ expr ::= assignExpr
| inlineExpr
| ifxExpr
| callExpr
| postfixCastExpr
| indexExpr
| memberExpr
| derefExpr
@@ -297,7 +303,7 @@ arrayTypeExpr ::= '[' ['..' | expr] ']' expr
// (modules/Shared_Memory_Channel/module.jai:113).
derefCastExpr ::= '(' '.*' ')' expr
castExpr ::= 'cast' [',' IDENT] '(' [expr] ')' expr
castExpr ::= 'cast' directiveFlag_* '(' [expr (',' expr)*] ')' [expr]
autoCastExpr ::= 'xx' [',' IDENT] expr
inlineExpr ::= ('inline' | 'no_inline') expr
ifxExpr ::= ifxKeyword_ expr ['then'] [ifxBranch_] ['else' ifxBranch_]
@@ -305,6 +311,7 @@ private ifxKeyword_ ::= 'ifx' | <<dir "#ifx">>
private ifxBranch_ ::= block | expr
callExpr ::= expr '(' [argList] ')'
postfixCastExpr ::= expr '.' '(' [expr] ')'
indexExpr ::= expr '[' [expr] ']'
memberExpr ::= expr '.' memberName
derefExpr ::= expr '.*'
@@ -337,12 +344,16 @@ primaryExpr ::= procLiteralExpr
| builtinCallExpr
| interfaceExpr
| literalExpr
| zeroLiteralExpr
| refExpr
| uninitializedExpr
refExpr ::= IDENT
literalExpr ::= NUMBER | STRING | HERE_STRING | 'true' | 'false' | 'null' | 'context'
uninitializedExpr ::= '---' | '--'
// `table.* = {};` zero-initialises. Only the empty form is an expression; a
// non-empty `{ … }` in expression position would collide with a block statement.
zeroLiteralExpr ::= '{' '}'
backtickExpr ::= '`' (IDENT | 'defer' | 'return' | 'push_context' | 'operator')
unaryDotExpr ::= '.' memberName
structLiteralExpr ::= '.{' [argList] '}'
@@ -388,7 +399,7 @@ private structModifier_ ::= procModifier
// `#ident` is one token, so which directives take operands is decided in
// JaiParserUtil rather than here.
// `#foreign libc "inotify_init1"` names the library and then the C symbol.
directiveExpr ::= <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
directiveExpr ::= <<dir "#asm">> directiveFlag_* [expr (',' expr)*] <<opaqueBlock>>
| <<dir "#foreign">> directiveFlag_* [<<exprNoAssign>>] [STRING]
| <<dir "#elsewhere">> directiveFlag_* [<<exprNoAssign>>] [STRING]
| <<dir "#insert">> directiveFlag_* ['(' [argList] ')'] [block | expr]

View File

@@ -579,11 +579,16 @@ open class JaiLexer : LexerBase() {
private fun scanHereString(from: Int): Int {
var p = scanWhile(from) { isSpace(it) }
// Optional `,cr` modifier.
// Optional modifier: `#string,cr ID` in the compiler's lexer
// (module.jai:487), and `#string,\% ID` in how_to/018_print_functions.jai,
// which the shipped Jai_Lexer module does not accept. Any non-space run is
// taken as the modifier; a here-string still has to produce a terminator
// identifier and a newline after it, so this cannot misfire.
if (ch(p) == ','.code) {
p = scanWhile(p + 1) { isSpace(it) }
if (!startsIdentifier(ch(p))) return -1
p = scanIdentifier(p)
val modifierStart = p
p = scanWhile(p) { !isSpace(it) && it != -1 }
if (p == modifierStart) return -1
p = scanWhile(p) { isSpace(it) }
}

View File

@@ -282,11 +282,15 @@ object JaiParserUtil : GeneratedParserUtilBase() {
T.RPAREN -> {
depth--
if (depth == 0) {
// A `name:` or `$T` inside the parentheses can only be a
// parameter list, so the header stands on its own: a bare
// proc *type* like `proc: (info: *Info, data: T)` has no
// arrow, directive or body after it.
if (sawParamMarker) return true
val next = b.lookAhead(i + 1)
return when {
next === T.RIGHT_ARROW -> true
next === T.DIRECTIVE -> true
next === T.LBRACE -> empty || sawParamMarker
return when (next) {
T.RIGHT_ARROW, T.DIRECTIVE -> true
T.LBRACE -> empty
else -> false
}
}
@@ -459,6 +463,7 @@ object JaiParserUtil : GeneratedParserUtilBase() {
): Boolean {
var i = 0
while (true) {
if (b.lookAhead(i) === T.BACKTICK) i++
if (b.lookAhead(i) !== T.IDENT) return false
i++
when (b.lookAhead(i)) {

View File

@@ -106,7 +106,7 @@ class JaiCorpusParserTest : BasePlatformTestCase() {
private companion object {
/** Ratchet. Raise it as the grammar improves; never lower it. */
const val MIN_CLEAN_FILES = 575
const val MIN_CLEAN_FILES = 640
const val REPORTED_ERRORS = 25
const val REPORTED_KINDS = 20
const val GOT_WIDTH = 14