Parser: corpus parse rate 69% -> 81%, and stop --tests from sticking

Grammar: 'using,except(x)' modifiers, '#ifx' with block branches, unions with
parameters, multi-value initializers, mixed 'name:, lvalue = call()' targets,
'push_context' with no explicit context, 'operator []=', '#foreign lib "symbol"',
keyword-named arguments such as 'remove={...}', and '#insert (options) body'.
Directive flags now require adjacency: without it, in
'(callback: (*GUID) #c_call, lpContext: *void)' the flag swallowed ', lpContext'.

procModifier is now just directiveExpr — one rule for directives in both
positions, so fixes apply everywhere.

jaitest: a '--tests' filter persisted through Gradle's configuration cache, so a
later unfiltered ./jaitest silently re-ran only that class and printed OK.
Unfiltered runs now disable the configuration cache.

MIN_CLEAN_FILES ratchets the corpus gate at 575/714.
This commit is contained in:
hgranthorner
2026-08-04 12:20:36 -04:00
parent 840a503e40
commit 086ae993c5
24 changed files with 728 additions and 271 deletions

12
jaitest
View File

@@ -9,14 +9,24 @@
# with `java.io.EOFException` or a missing in-progress-results bin. That is an
# infrastructure failure, not a test failure, so it is retried once.
#
# A `--tests` filter STICKS: Gradle reuses the configuration cache entry from the
# previous run, so a later unfiltered `./jaitest` silently re-runs just that one
# class and reports OK. Unfiltered runs therefore disable the configuration cache,
# which is the only reliable way to get the whole suite back.
#
# Usage: ./jaitest [gradle args...] e.g. ./jaitest --tests '*Lexer*'
set -uo pipefail
cd "$(dirname "$0")" || exit 1
extra=()
if [[ " $* " != *" --tests "* ]]; then
extra+=(--no-configuration-cache)
fi
run_gradle() {
rm -rf build/reports/tests/test
./jaigradle cleanTest test "$@" 2>&1 | grep -vE '^\[[0-9.]+s\]\[warning\]\[cds\]'
./jaigradle cleanTest test "${extra[@]}" "$@" 2>&1 | grep -vE '^\[[0-9.]+s\]\[warning\]\[cds\]'
return "${PIPESTATUS[0]}"
}

View File

@@ -101,12 +101,13 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// '---' | expr
// '---' | namedArgument | expr
public static boolean argument(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "argument")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, ARGUMENT, "<argument>");
result_ = consumeToken(builder_, TRIPLE_MINUS);
if (!result_) result_ = namedArgument(builder_, level_ + 1);
if (!result_) result_ = expr(builder_, level_ + 1, -1);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
@@ -157,6 +158,40 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
/* ********************************************************** */
// <<exprNoAssign>> (',' <<exprNoAssign>>)*
static boolean assignTargets_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "assignTargets_")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = exprNoAssign(builder_, level_ + 1);
result_ = result_ && assignTargets__1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// (',' <<exprNoAssign>>)*
private static boolean assignTargets__1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "assignTargets__1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!assignTargets__1_0(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "assignTargets__1", pos_)) break;
}
return true;
}
// ',' <<exprNoAssign>>
private static boolean assignTargets__1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "assignTargets__1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COMMA);
result_ = result_ && exprNoAssign(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// '`' (IDENT | 'defer' | 'return' | 'push_context' | 'operator')
public static boolean backtickExpr(PsiBuilder builder_, int level_) {
@@ -326,12 +361,12 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// procModifier | 'using'
// procModifier | usingModifier_
static boolean declModifier_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declModifier_")) return false;
boolean result_;
result_ = procModifier(builder_, level_ + 1);
if (!result_) result_ = consumeToken(builder_, KW_USING);
if (!result_) result_ = usingModifier_(builder_, level_ + 1);
return result_;
}
@@ -391,9 +426,9 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// ':' [<<exprNoAssign>>] procModifier* [('=' | ':') initializer]
// | ':=' initializer
// | '::' initializer
// ':' [<<exprNoAssign>>] procModifier* [',' assignTargets_] [('=' | ':') initializerList_]
// | ':=' initializerList_
// | '::' initializerList_
static boolean declTail_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail_")) return false;
boolean result_;
@@ -405,7 +440,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
// ':' [<<exprNoAssign>>] procModifier* [('=' | ':') initializer]
// ':' [<<exprNoAssign>>] procModifier* [',' assignTargets_] [('=' | ':') initializerList_]
private static boolean declTail__0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail__0")) return false;
boolean result_;
@@ -414,6 +449,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
result_ = result_ && declTail__0_1(builder_, level_ + 1);
result_ = result_ && declTail__0_2(builder_, level_ + 1);
result_ = result_ && declTail__0_3(builder_, level_ + 1);
result_ = result_ && declTail__0_4(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
@@ -436,51 +472,69 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// [('=' | ':') initializer]
// [',' assignTargets_]
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
// ',' assignTargets_
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_3_0_0(builder_, level_ + 1);
result_ = result_ && initializer(builder_, level_ + 1);
result_ = consumeToken(builder_, COMMA);
result_ = result_ && assignTargets_(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [('=' | ':') initializerList_]
private static boolean declTail__0_4(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail__0_4")) return false;
declTail__0_4_0(builder_, level_ + 1);
return true;
}
// ('=' | ':') initializerList_
private static boolean declTail__0_4_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail__0_4_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = declTail__0_4_0_0(builder_, level_ + 1);
result_ = result_ && initializerList_(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// '=' | ':'
private static boolean declTail__0_3_0_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail__0_3_0_0")) return false;
private static boolean declTail__0_4_0_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail__0_4_0_0")) return false;
boolean result_;
result_ = consumeToken(builder_, EQ);
if (!result_) result_ = consumeToken(builder_, COLON);
return result_;
}
// ':=' initializer
// ':=' initializerList_
private static boolean declTail__1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail__1")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COLON_EQ);
result_ = result_ && initializer(builder_, level_ + 1);
result_ = result_ && initializerList_(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// '::' initializer
// '::' initializerList_
private static boolean declTail__2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "declTail__2")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COLON_COLON);
result_ = result_ && initializer(builder_, level_ + 1);
result_ = result_ && initializerList_(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
@@ -534,6 +588,9 @@ public class JaiParser implements PsiParser, LightPsiParser {
/* ********************************************************** */
// <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
// | <<dir "#foreign">> directiveFlag_* [<<exprNoAssign>>] [STRING]
// | <<dir "#elsewhere">> directiveFlag_* [<<exprNoAssign>>] [STRING]
// | <<dir "#insert">> directiveFlag_* ['(' [argList] ')'] [block | expr]
// | <<dir "#assert">> expr [expr]
// | <<dir "#module_parameters">> '(' [paramList] ')' ['(' [paramList] ')'] [block]
// | <<dirWithBlock>> directiveFlag_* block
@@ -549,6 +606,9 @@ public class JaiParser implements PsiParser, LightPsiParser {
if (!result_) result_ = directiveExpr_3(builder_, level_ + 1);
if (!result_) result_ = directiveExpr_4(builder_, level_ + 1);
if (!result_) result_ = directiveExpr_5(builder_, level_ + 1);
if (!result_) result_ = directiveExpr_6(builder_, level_ + 1);
if (!result_) result_ = directiveExpr_7(builder_, level_ + 1);
if (!result_) result_ = directiveExpr_8(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
}
@@ -576,88 +636,91 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// <<dir "#assert">> expr [expr]
// <<dir "#foreign">> directiveFlag_* [<<exprNoAssign>>] [STRING]
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_ = dir(builder_, level_ + 1, "#foreign");
result_ = result_ && directiveExpr_1_1(builder_, level_ + 1);
result_ = result_ && directiveExpr_1_2(builder_, level_ + 1);
result_ = result_ && directiveExpr_1_3(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [expr]
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);
// directiveFlag_*
private static boolean directiveExpr_1_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_1_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "directiveExpr_1_1", pos_)) break;
}
return true;
}
// <<dir "#module_parameters">> '(' [paramList] ')' ['(' [paramList] ')'] [block]
// [<<exprNoAssign>>]
private static boolean directiveExpr_1_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_1_2")) return false;
exprNoAssign(builder_, level_ + 1);
return true;
}
// [STRING]
private static boolean directiveExpr_1_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_1_3")) return false;
consumeToken(builder_, STRING);
return true;
}
// <<dir "#elsewhere">> directiveFlag_* [<<exprNoAssign>>] [STRING]
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_ = dir(builder_, level_ + 1, "#elsewhere");
result_ = result_ && directiveExpr_2_1(builder_, level_ + 1);
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);
result_ = result_ && directiveExpr_2_3(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [paramList]
// directiveFlag_*
private static boolean directiveExpr_2_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_2_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "directiveExpr_2_1", pos_)) break;
}
return true;
}
// [<<exprNoAssign>>]
private static boolean directiveExpr_2_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_2_2")) return false;
paramList(builder_, level_ + 1);
exprNoAssign(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);
// [STRING]
private static boolean directiveExpr_2_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_2_3")) return false;
consumeToken(builder_, STRING);
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
// <<dir "#insert">> directiveFlag_* ['(' [argList] ')'] [block | expr]
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_ = dir(builder_, level_ + 1, "#insert");
result_ = result_ && directiveExpr_3_1(builder_, level_ + 1);
result_ = result_ && block(builder_, level_ + 1);
result_ = result_ && directiveExpr_3_2(builder_, level_ + 1);
result_ = result_ && directiveExpr_3_3(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
@@ -673,29 +736,60 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// <<dirWithOperand>> directiveFlag_* [expr]
private static boolean directiveExpr_4(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_4")) return false;
// ['(' [argList] ')']
private static boolean directiveExpr_3_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_3_2")) return false;
directiveExpr_3_2_0(builder_, level_ + 1);
return true;
}
// '(' [argList] ')'
private static boolean directiveExpr_3_2_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_3_2_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = dirWithOperand(builder_, level_ + 1);
result_ = result_ && directiveExpr_4_1(builder_, level_ + 1);
result_ = result_ && directiveExpr_4_2(builder_, level_ + 1);
result_ = consumeToken(builder_, LPAREN);
result_ = result_ && directiveExpr_3_2_0_1(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, RPAREN);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// 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;
}
// [argList]
private static boolean directiveExpr_3_2_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_3_2_0_1")) return false;
argList(builder_, level_ + 1);
return true;
}
// [block | expr]
private static boolean directiveExpr_3_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_3_3")) return false;
directiveExpr_3_3_0(builder_, level_ + 1);
return true;
}
// block | expr
private static boolean directiveExpr_3_3_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_3_3_0")) return false;
boolean result_;
result_ = block(builder_, level_ + 1);
if (!result_) result_ = expr(builder_, level_ + 1, -1);
return result_;
}
// <<dir "#assert">> expr [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_ = dir(builder_, level_ + 1, "#assert");
result_ = result_ && expr(builder_, level_ + 1, -1);
result_ = result_ && directiveExpr_4_2(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [expr]
private static boolean directiveExpr_4_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_4_2")) return false;
@@ -703,38 +797,140 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// <<dirPlain>> directiveFlag_*
// <<dir "#module_parameters">> '(' [paramList] ')' ['(' [paramList] ')'] [block]
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_5_1(builder_, level_ + 1);
result_ = dir(builder_, level_ + 1, "#module_parameters");
result_ = result_ && consumeToken(builder_, LPAREN);
result_ = result_ && directiveExpr_5_2(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, RPAREN);
result_ = result_ && directiveExpr_5_4(builder_, level_ + 1);
result_ = result_ && directiveExpr_5_5(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [paramList]
private static boolean directiveExpr_5_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_5_2")) return false;
paramList(builder_, level_ + 1);
return true;
}
// ['(' [paramList] ')']
private static boolean directiveExpr_5_4(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_5_4")) return false;
directiveExpr_5_4_0(builder_, level_ + 1);
return true;
}
// '(' [paramList] ')'
private static boolean directiveExpr_5_4_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_5_4_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, LPAREN);
result_ = result_ && directiveExpr_5_4_0_1(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, RPAREN);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [paramList]
private static boolean directiveExpr_5_4_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_5_4_0_1")) return false;
paramList(builder_, level_ + 1);
return true;
}
// [block]
private static boolean directiveExpr_5_5(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_5_5")) return false;
block(builder_, level_ + 1);
return true;
}
// <<dirWithBlock>> directiveFlag_* block
private static boolean directiveExpr_6(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_6")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = dirWithBlock(builder_, level_ + 1);
result_ = result_ && directiveExpr_6_1(builder_, level_ + 1);
result_ = result_ && block(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// directiveFlag_*
private static boolean directiveExpr_5_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_5_1")) return false;
private static boolean directiveExpr_6_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_6_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;
if (!empty_element_parsed_guard_(builder_, "directiveExpr_6_1", pos_)) break;
}
return true;
}
// <<dirWithOperand>> directiveFlag_* [expr]
private static boolean directiveExpr_7(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_7")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = dirWithOperand(builder_, level_ + 1);
result_ = result_ && directiveExpr_7_1(builder_, level_ + 1);
result_ = result_ && directiveExpr_7_2(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// directiveFlag_*
private static boolean directiveExpr_7_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_7_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "directiveExpr_7_1", pos_)) break;
}
return true;
}
// [expr]
private static boolean directiveExpr_7_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_7_2")) return false;
expr(builder_, level_ + 1, -1);
return true;
}
// <<dirPlain>> directiveFlag_*
private static boolean directiveExpr_8(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_8")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = dirPlain(builder_, level_ + 1);
result_ = result_ && directiveExpr_8_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// directiveFlag_*
private static boolean directiveExpr_8_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "directiveExpr_8_1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!directiveFlag_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "directiveExpr_8_1", pos_)) break;
}
return true;
}
/* ********************************************************** */
// ',' IDENT
// <<directiveFlag>>
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_;
return directiveFlag(builder_, level_ + 1);
}
/* ********************************************************** */
@@ -1059,6 +1255,28 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
/* ********************************************************** */
// block | expr
static boolean ifxBranch_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "ifxBranch_")) return false;
boolean result_;
result_ = block(builder_, level_ + 1);
if (!result_) result_ = expr(builder_, level_ + 1, -1);
return result_;
}
/* ********************************************************** */
// 'ifx' | <<dir "#ifx">>
static boolean ifxKeyword_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "ifxKeyword_")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, KW_IFX);
if (!result_) result_ = dir(builder_, level_ + 1, "#ifx");
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// '---' | expr
public static boolean initializer(PsiBuilder builder_, int level_) {
@@ -1071,6 +1289,40 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
/* ********************************************************** */
// initializer (',' initializer)*
static boolean initializerList_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "initializerList_")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = initializer(builder_, level_ + 1);
result_ = result_ && initializerList__1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// (',' initializer)*
private static boolean initializerList__1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "initializerList__1")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!initializerList__1_0(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "initializerList__1", pos_)) break;
}
return true;
}
// ',' initializer
private static boolean initializerList__1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "initializerList__1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, COMMA);
result_ = result_ && initializer(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
/* ********************************************************** */
// 'interface' [expr]
public static boolean interfaceExpr(PsiBuilder builder_, int level_) {
@@ -1168,6 +1420,29 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
/* ********************************************************** */
// <<isNamedArgumentAhead>> memberName '=' (block | expr)
public static boolean namedArgument(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "namedArgument")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, NAMED_ARGUMENT, "<named argument>");
result_ = isNamedArgumentAhead(builder_, level_ + 1);
result_ = result_ && memberName(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, EQ);
result_ = result_ && namedArgument_3(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
}
// block | expr
private static boolean namedArgument_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "namedArgument_3")) return false;
boolean result_;
result_ = block(builder_, level_ + 1);
if (!result_) result_ = expr(builder_, level_ + 1, -1);
return result_;
}
/* ********************************************************** */
// NOTE+
public static boolean noteStatement(PsiBuilder builder_, int level_) {
@@ -1204,7 +1479,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
/* ********************************************************** */
// '+' | '-' | '*' | '/' | '%' | '==' | '!=' | '<' | '>' | '<=' | '>='
// | '&' | '|' | '^' | '~' | '<<' | '>>' | '<<<' | '>>>'
// | '[' ']' | '[' ']' '='
// | '[' ']' '=' | '[' ']'
public static boolean operatorSymbol(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "operatorSymbol")) return false;
boolean result_;
@@ -1228,8 +1503,8 @@ 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_ = parseTokens(builder_, 0, LBRACKET, RBRACKET);
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);
return result_;
}
@@ -1648,97 +1923,18 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// <<dirWithBlock>> directiveFlag_* block
// | <<dirWithOperand>> directiveFlag_* [expr]
// | <<dirPlain>> directiveFlag_*
// directiveExpr
public static boolean procModifier(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "procModifier")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_, level_, _NONE_, PROC_MODIFIER, "<proc modifier>");
result_ = procModifier_0(builder_, level_ + 1);
if (!result_) result_ = procModifier_1(builder_, level_ + 1);
if (!result_) result_ = procModifier_2(builder_, level_ + 1);
result_ = directiveExpr(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
}
// <<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_;
}
// 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_;
Marker marker_ = enter_section_(builder_);
result_ = dirWithOperand(builder_, level_ + 1);
result_ = result_ && procModifier_1_1(builder_, level_ + 1);
result_ = result_ && procModifier_1_2(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// directiveFlag_*
private static boolean procModifier_1_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "procModifier_1_1")) return false;
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;
}
// [expr]
private static boolean procModifier_1_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "procModifier_1_2")) return false;
expr(builder_, level_ + 1, -1);
return true;
}
// <<dirPlain>> directiveFlag_*
private static boolean procModifier_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "procModifier_2")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = dirPlain(builder_, level_ + 1);
result_ = result_ && procModifier_2_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// directiveFlag_*
private static boolean procModifier_2_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "procModifier_2_1")) return false;
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;
}
/* ********************************************************** */
// ['`'] 'push_context' expr block
// ['`'] 'push_context' [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;
@@ -1746,7 +1942,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
Marker marker_ = enter_section_(builder_, level_, _NONE_, PUSH_CONTEXT_STATEMENT, "<push context statement>");
result_ = pushContextStatement_0(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, KW_PUSH_CONTEXT);
result_ = result_ && expr(builder_, level_ + 1, -1);
result_ = result_ && pushContextStatement_2(builder_, level_ + 1);
result_ = result_ && block(builder_, level_ + 1);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
@@ -1759,6 +1955,13 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// [expr]
private static boolean pushContextStatement_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "pushContextStatement_2")) return false;
expr(builder_, level_ + 1, -1);
return true;
}
/* ********************************************************** */
// IDENT
public static boolean refExpr(PsiBuilder builder_, int level_) {
@@ -2228,7 +2431,7 @@ public class JaiParser implements PsiParser, LightPsiParser {
}
/* ********************************************************** */
// 'union' structModifier_* block
// 'union' ['(' [paramList] ')'] structModifier_* block
public static boolean unionExpr(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "unionExpr")) return false;
if (!nextTokenIs(builder_, KW_UNION)) return false;
@@ -2236,22 +2439,106 @@ public class JaiParser implements PsiParser, LightPsiParser {
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, KW_UNION);
result_ = result_ && unionExpr_1(builder_, level_ + 1);
result_ = result_ && unionExpr_2(builder_, level_ + 1);
result_ = result_ && block(builder_, level_ + 1);
exit_section_(builder_, marker_, UNION_EXPR, result_);
return result_;
}
// structModifier_*
// ['(' [paramList] ')']
private static boolean unionExpr_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "unionExpr_1")) return false;
unionExpr_1_0(builder_, level_ + 1);
return true;
}
// '(' [paramList] ')'
private static boolean unionExpr_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "unionExpr_1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, LPAREN);
result_ = result_ && unionExpr_1_0_1(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, RPAREN);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [paramList]
private static boolean unionExpr_1_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "unionExpr_1_0_1")) return false;
paramList(builder_, level_ + 1);
return true;
}
// structModifier_*
private static boolean unionExpr_2(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "unionExpr_2")) return false;
while (true) {
int pos_ = current_position_(builder_);
if (!structModifier_(builder_, level_ + 1)) break;
if (!empty_element_parsed_guard_(builder_, "unionExpr_1", pos_)) break;
if (!empty_element_parsed_guard_(builder_, "unionExpr_2", pos_)) break;
}
return true;
}
/* ********************************************************** */
// 'using' [directiveFlag_ ['(' [argList] ')']]
static boolean usingModifier_(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "usingModifier_")) return false;
if (!nextTokenIs(builder_, KW_USING)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, KW_USING);
result_ = result_ && usingModifier__1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [directiveFlag_ ['(' [argList] ')']]
private static boolean usingModifier__1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "usingModifier__1")) return false;
usingModifier__1_0(builder_, level_ + 1);
return true;
}
// directiveFlag_ ['(' [argList] ')']
private static boolean usingModifier__1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "usingModifier__1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = directiveFlag_(builder_, level_ + 1);
result_ = result_ && usingModifier__1_0_1(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// ['(' [argList] ')']
private static boolean usingModifier__1_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "usingModifier__1_0_1")) return false;
usingModifier__1_0_1_0(builder_, level_ + 1);
return true;
}
// '(' [argList] ')'
private static boolean usingModifier__1_0_1_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "usingModifier__1_0_1_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeToken(builder_, LPAREN);
result_ = result_ && usingModifier__1_0_1_0_1(builder_, level_ + 1);
result_ = result_ && consumeToken(builder_, RPAREN);
exit_section_(builder_, marker_, null, result_);
return result_;
}
// [argList]
private static boolean usingModifier__1_0_1_0_1(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "usingModifier__1_0_1_0_1")) return false;
argList(builder_, level_ + 1);
return true;
}
/* ********************************************************** */
// 'using' [',' expr] expr semi
public static boolean usingStatement(PsiBuilder builder_, int level_) {
@@ -2643,18 +2930,17 @@ public class JaiParser implements PsiParser, LightPsiParser {
return result_;
}
// 'ifx' expr ['then'] [expr] ['else' expr]
// ifxKeyword_ expr ['then'] [ifxBranch_] ['else' ifxBranch_]
public static boolean ifxExpr(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "ifxExpr")) return false;
if (!nextTokenIsSmart(builder_, KW_IFX)) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeTokenSmart(builder_, KW_IFX);
Marker marker_ = enter_section_(builder_, level_, _COLLAPSE_, IFX_EXPR, "<ifx expr>");
result_ = ifxKeyword_(builder_, level_ + 1);
result_ = result_ && expr(builder_, level_ + 1, -1);
result_ = result_ && ifxExpr_2(builder_, level_ + 1);
result_ = result_ && ifxExpr_3(builder_, level_ + 1);
result_ = result_ && ifxExpr_4(builder_, level_ + 1);
exit_section_(builder_, marker_, IFX_EXPR, result_);
exit_section_(builder_, level_, marker_, result_, false, null);
return result_;
}
@@ -2665,27 +2951,27 @@ public class JaiParser implements PsiParser, LightPsiParser {
return true;
}
// [expr]
// [ifxBranch_]
private static boolean ifxExpr_3(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "ifxExpr_3")) return false;
expr(builder_, level_ + 1, -1);
ifxBranch_(builder_, level_ + 1);
return true;
}
// ['else' expr]
// ['else' ifxBranch_]
private static boolean ifxExpr_4(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "ifxExpr_4")) return false;
ifxExpr_4_0(builder_, level_ + 1);
return true;
}
// 'else' expr
// 'else' ifxBranch_
private static boolean ifxExpr_4_0(PsiBuilder builder_, int level_) {
if (!recursion_guard_(builder_, level_, "ifxExpr_4_0")) return false;
boolean result_;
Marker marker_ = enter_section_(builder_);
result_ = consumeTokenSmart(builder_, KW_ELSE);
result_ = result_ && expr(builder_, level_ + 1, -1);
result_ = result_ && ifxBranch_(builder_, level_ + 1);
exit_section_(builder_, marker_, null, result_);
return result_;
}

View File

@@ -10,4 +10,7 @@ public interface JaiArgument extends PsiElement {
@Nullable
JaiExpr getExpr();
@Nullable
JaiNamedArgument getNamedArgument();
}

View File

@@ -7,11 +7,14 @@ import com.intellij.psi.PsiElement;
public interface JaiDeclaration extends PsiElement {
@NotNull
List<JaiArgument> getArgumentList();
@NotNull
JaiDeclNames getDeclNames();
@Nullable
JaiInitializer getInitializer();
@NotNull
List<JaiInitializer> getInitializerList();
@NotNull
List<JaiProcModifier> getProcModifierList();

View File

@@ -7,11 +7,14 @@ import com.intellij.psi.PsiElement;
public interface JaiDirectiveExpr extends JaiExpr {
@NotNull
List<JaiArgument> getArgumentList();
@Nullable
JaiBlock getBlock();
@NotNull
List<JaiExpr> getExprList();
@Nullable
JaiExpr getExpr();
@NotNull
List<JaiParameter> getParameterList();

View File

@@ -7,6 +7,9 @@ import com.intellij.psi.PsiElement;
public interface JaiIfxExpr extends JaiExpr {
@NotNull
List<JaiBlock> getBlockList();
@NotNull
List<JaiExpr> getExprList();

View File

@@ -0,0 +1,19 @@
// 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 JaiNamedArgument extends PsiElement {
@Nullable
JaiBlock getBlock();
@Nullable
JaiExpr getExpr();
@NotNull
JaiMemberName getMemberName();
}

View File

@@ -7,10 +7,7 @@ import com.intellij.psi.PsiElement;
public interface JaiProcModifier extends PsiElement {
@Nullable
JaiBlock getBlock();
@Nullable
JaiExpr getExpr();
@NotNull
JaiDirectiveExpr getDirectiveExpr();
}

View File

@@ -10,7 +10,7 @@ public interface JaiPushContextStatement extends PsiElement {
@NotNull
JaiBlock getBlock();
@NotNull
@Nullable
JaiExpr getExpr();
}

View File

@@ -53,6 +53,7 @@ public interface JaiTypes {
IElementType MEMBER_EXPR = new JaiElementType("MEMBER_EXPR");
IElementType MEMBER_NAME = new JaiElementType("MEMBER_NAME");
IElementType MUL_EXPR = new JaiElementType("MUL_EXPR");
IElementType NAMED_ARGUMENT = new JaiElementType("NAMED_ARGUMENT");
IElementType NOTE_STATEMENT = new JaiElementType("NOTE_STATEMENT");
IElementType OPERATOR_DECLARATION = new JaiElementType("OPERATOR_DECLARATION");
IElementType OPERATOR_SYMBOL = new JaiElementType("OPERATOR_SYMBOL");
@@ -327,6 +328,9 @@ public interface JaiTypes {
else if (type == MUL_EXPR) {
return new JaiMulExprImpl(node);
}
else if (type == NAMED_ARGUMENT) {
return new JaiNamedArgumentImpl(node);
}
else if (type == NOTE_STATEMENT) {
return new JaiNoteStatementImpl(node);
}

View File

@@ -10,6 +10,9 @@ public interface JaiUnionExpr extends JaiExpr {
@NotNull
JaiBlock getBlock();
@NotNull
List<JaiParameter> getParameterList();
@NotNull
List<JaiProcModifier> getProcModifierList();

View File

@@ -183,6 +183,10 @@ public class JaiVisitor extends PsiElementVisitor {
visitExpr(o);
}
public void visitNamedArgument(@NotNull JaiNamedArgument o) {
visitPsiElement(o);
}
public void visitNoteStatement(@NotNull JaiNoteStatement o) {
visitPsiElement(o);
}

View File

@@ -33,4 +33,10 @@ public class JaiArgumentImpl extends ASTWrapperPsiElement implements JaiArgument
return findChildByClass(JaiExpr.class);
}
@Override
@Nullable
public JaiNamedArgument getNamedArgument() {
return findChildByClass(JaiNamedArgument.class);
}
}

View File

@@ -27,6 +27,12 @@ public class JaiDeclarationImpl extends ASTWrapperPsiElement implements JaiDecla
else super.accept(visitor);
}
@Override
@NotNull
public List<JaiArgument> getArgumentList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiArgument.class);
}
@Override
@NotNull
public JaiDeclNames getDeclNames() {
@@ -34,9 +40,9 @@ public class JaiDeclarationImpl extends ASTWrapperPsiElement implements JaiDecla
}
@Override
@Nullable
public JaiInitializer getInitializer() {
return findChildByClass(JaiInitializer.class);
@NotNull
public List<JaiInitializer> getInitializerList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiInitializer.class);
}
@Override

View File

@@ -27,6 +27,12 @@ public class JaiDirectiveExprImpl extends JaiExprImpl implements JaiDirectiveExp
else super.accept(visitor);
}
@Override
@NotNull
public List<JaiArgument> getArgumentList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiArgument.class);
}
@Override
@Nullable
public JaiBlock getBlock() {
@@ -34,9 +40,9 @@ public class JaiDirectiveExprImpl extends JaiExprImpl implements JaiDirectiveExp
}
@Override
@NotNull
public List<JaiExpr> getExprList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiExpr.class);
@Nullable
public JaiExpr getExpr() {
return findChildByClass(JaiExpr.class);
}
@Override

View File

@@ -27,6 +27,12 @@ public class JaiIfxExprImpl extends JaiExprImpl implements JaiIfxExpr {
else super.accept(visitor);
}
@Override
@NotNull
public List<JaiBlock> getBlockList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiBlock.class);
}
@Override
@NotNull
public List<JaiExpr> getExprList() {

View File

@@ -0,0 +1,48 @@
// 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 JaiNamedArgumentImpl extends ASTWrapperPsiElement implements JaiNamedArgument {
public JaiNamedArgumentImpl(@NotNull ASTNode node) {
super(node);
}
public void accept(@NotNull JaiVisitor visitor) {
visitor.visitNamedArgument(this);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JaiVisitor) accept((JaiVisitor)visitor);
else super.accept(visitor);
}
@Override
@Nullable
public JaiBlock getBlock() {
return findChildByClass(JaiBlock.class);
}
@Override
@Nullable
public JaiExpr getExpr() {
return findChildByClass(JaiExpr.class);
}
@Override
@NotNull
public JaiMemberName getMemberName() {
return findNotNullChildByClass(JaiMemberName.class);
}
}

View File

@@ -28,15 +28,9 @@ public class JaiProcModifierImpl extends ASTWrapperPsiElement implements JaiProc
}
@Override
@Nullable
public JaiBlock getBlock() {
return findChildByClass(JaiBlock.class);
}
@Override
@Nullable
public JaiExpr getExpr() {
return findChildByClass(JaiExpr.class);
@NotNull
public JaiDirectiveExpr getDirectiveExpr() {
return findNotNullChildByClass(JaiDirectiveExpr.class);
}
}

View File

@@ -34,9 +34,9 @@ public class JaiPushContextStatementImpl extends ASTWrapperPsiElement implements
}
@Override
@NotNull
@Nullable
public JaiExpr getExpr() {
return findNotNullChildByClass(JaiExpr.class);
return findChildByClass(JaiExpr.class);
}
}

View File

@@ -33,6 +33,12 @@ public class JaiUnionExprImpl extends JaiExprImpl implements JaiUnionExpr {
return findNotNullChildByClass(JaiBlock.class);
}
@Override
@NotNull
public List<JaiParameter> getParameterList() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiParameter.class);
}
@Override
@NotNull
public List<JaiProcModifier> getProcModifierList() {

View File

@@ -203,7 +203,7 @@ breakStatement ::= 'break' [IDENT] semi
continueStatement ::= 'continue' [IDENT] semi
removeStatement ::= 'remove' [expr] semi
deferStatement ::= ['`'] 'defer' statement
pushContextStatement ::= ['`'] 'push_context' expr block
pushContextStatement ::= ['`'] 'push_context' [expr] block
usingStatement ::= 'using' [',' expr] expr semi
expressionStatement ::= expr (',' expr)* semiWithNotes_
@@ -214,20 +214,27 @@ expressionStatement ::= expr (',' expr)* semiWithNotes_
// 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_ semiWithNotes_
// `#as using base: Document;`, `#overlay (unknown.vtable) using vtable: *Vtable;`
private declModifier_ ::= procModifier | 'using'
// `#as using base: Document;`, `#overlay (unknown.vtable) using vtable: *Vtable;`,
// `#as using,except(vtable) iunknown: IUnknown;`
private declModifier_ ::= procModifier | usingModifier_
private usingModifier_ ::= 'using' [directiveFlag_ ['(' [argList] ')']]
declNames ::= declName (',' declName)*
declName ::= ['`'] IDENT
private declTail_ ::= ':' [<<exprNoAssign>>] procModifier* [('=' | ':') initializer]
| ':=' initializer
| '::' initializer
private declTail_ ::= ':' [<<exprNoAssign>>] procModifier* [',' assignTargets_] [('=' | ':') initializerList_]
| ':=' initializerList_
| '::' initializerList_
// `x, y := mouse_x, mouse_y;` — one initializer per name.
private initializerList_ ::= initializer (',' initializer)*
// `success:, apk.zip_dir = load_zip_directory(path);` declares the first name and
// assigns to the remaining lvalues.
private assignTargets_ ::= <<exprNoAssign>> (',' <<exprNoAssign>>)*
initializer ::= '---' | expr
// `operator + :: (a: T, b: T) -> T { }`
operatorDeclaration ::= 'operator' operatorSymbol '::' expr semiWithNotes_
operatorSymbol ::= '+' | '-' | '*' | '/' | '%' | '==' | '!=' | '<' | '>' | '<=' | '>='
| '&' | '|' | '^' | '~' | '<<' | '>>' | '<<<' | '>>>'
| '[' ']' | '[' ']' '='
| '[' ']' '=' | '[' ']'
// -------------------------------------------------------------------- expressions
@@ -293,7 +300,9 @@ derefCastExpr ::= '(' '.*' ')' expr
castExpr ::= 'cast' [',' IDENT] '(' [expr] ')' expr
autoCastExpr ::= 'xx' [',' IDENT] expr
inlineExpr ::= ('inline' | 'no_inline') expr
ifxExpr ::= 'ifx' expr ['then'] [expr] ['else' expr]
ifxExpr ::= ifxKeyword_ expr ['then'] [ifxBranch_] ['else' ifxBranch_]
private ifxKeyword_ ::= 'ifx' | <<dir "#ifx">>
private ifxBranch_ ::= block | expr
callExpr ::= expr '(' [argList] ')'
indexExpr ::= expr '[' [expr] ']'
@@ -312,7 +321,8 @@ private keywordAsName_ ::= 'if' | 'for' | 'case' | 'enum' | 'cast' | 'union' | '
// `,,` introduces an inline context change: `join(parts,, allocator = temp)`.
private argList ::= argument ((',' | ',,') argument)* [',']
argument ::= '---' | expr
argument ::= '---' | namedArgument | expr
namedArgument ::= <<isNamedArgumentAhead>> memberName '=' (block | expr)
primaryExpr ::= procLiteralExpr
| structExpr
@@ -364,20 +374,24 @@ returnGroup ::= '(' [returnItem (',' returnItem)*] ')'
returnItem ::= [<<isParamNameAhead>> IDENT ':'] <<exprNoAssign>>
// `#foreign lib`, `#modify { ... }`, `#c_call`, `#expand`, …
procModifier ::= <<dirWithBlock>> directiveFlag_* block
| <<dirWithOperand>> directiveFlag_* [expr]
| <<dirPlain>> directiveFlag_*
// `#foreign lib "symbol"`, `#modify { ... }`, `#c_call`, `#expand`, `#align 8` — the
// same shape as any other directive, so there is one rule for both positions.
procModifier ::= directiveExpr
structExpr ::= 'struct' ['(' [paramList] ')'] structModifier_* block
enumExpr ::= ('enum' | 'enum_flags') [!'{' expr] structModifier_* block
unionExpr ::= 'union' structModifier_* block
unionExpr ::= 'union' ['(' [paramList] ')'] structModifier_* block
private structModifier_ ::= procModifier
// -------------------------------------------------------------------- directives
// `#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>>
| <<dir "#foreign">> directiveFlag_* [<<exprNoAssign>>] [STRING]
| <<dir "#elsewhere">> directiveFlag_* [<<exprNoAssign>>] [STRING]
| <<dir "#insert">> directiveFlag_* ['(' [argList] ')'] [block | expr]
| <<dir "#assert">> expr [expr]
| <<dir "#module_parameters">> '(' [paramList] ')' ['(' [paramList] ')'] [block]
| <<dirWithBlock>> directiveFlag_* block
@@ -385,5 +399,6 @@ directiveExpr ::= <<dir "#asm">> directiveFlag_* <<opaqueBlock>>
| <<dirPlain>> directiveFlag_*
// `#import,file`, `#library,system,link_always`, `#run,stallable` — a directive can
// carry any number of comma-separated flags.
private directiveFlag_ ::= ',' IDENT
// carry any number of comma-separated flags. Adjacency is enforced in the util; see
// JaiParserUtil.directiveFlag.
private directiveFlag_ ::= <<directiveFlag>>

View File

@@ -4,6 +4,7 @@ import com.intellij.lang.PsiBuilder
import com.intellij.lang.parser.GeneratedParserUtilBase
import com.intellij.psi.TokenType
import com.intellij.psi.tree.IElementType
import dev.hgh.jai.lexer.JaiTokenTypes
import dev.hgh.jai.lexer.JaiTokenTypes as T
/**
@@ -170,6 +171,39 @@ object JaiParserUtil : GeneratedParserUtilBase() {
return true
}
/**
* A `,flag` suffix on a directive: `#import,file`, `#library,system,link_always`,
* `#run,stallable`.
*
* Adjacency is required. Without it, in
* `(callback: (*GUID) #c_call, lpContext: *void)` the flag would swallow
* `, lpContext` and the parameter list would fall apart. Every flag in the corpus
* is written tight against the directive; a separator comma always has a space.
*/
@JvmStatic
fun directiveFlag(
b: PsiBuilder,
level: Int,
): Boolean {
if (b.tokenType !== T.COMMA) return false
if (b.rawLookup(-1) === TokenType.WHITE_SPACE) return false
if (b.rawLookup(1) !== T.IDENT) return false
b.advanceLexer()
b.advanceLexer()
return true
}
/** `name =` inside an argument list, where `name` may be a keyword (`remove=`). */
@JvmStatic
fun isNamedArgumentAhead(
b: PsiBuilder,
level: Int,
): Boolean {
val t = b.tokenType ?: return false
if (t !== T.IDENT && t !in JaiTokenTypes.KEYWORDS) return false
return b.lookAhead(1) === T.EQ
}
// ------------------------------------------------------------------ operators
/**
@@ -291,7 +325,8 @@ object JaiParserUtil : GeneratedParserUtilBase() {
* `foo :: () {}` apart from `foo();`.
*
* The prefix skip covers `#as using base: Document;`,
* `#overlay (unknown.vtable) using vtable: *Vtable;` and the macro-exported
* `#overlay (unknown.vtable) using vtable: *Vtable;`,
* `#as using,except(vtable) iunknown: IUnknown;` and the macro-exported
* `` `it := entry.value; ``.
*/
@JvmStatic
@@ -300,10 +335,12 @@ object JaiParserUtil : GeneratedParserUtilBase() {
level: Int,
): Boolean {
var i = 0
var inPrefix = false
loop@ while (true) {
when (b.lookAhead(i)) {
T.DIRECTIVE, T.KW_USING -> {
i++
inPrefix = true
}
T.LPAREN -> {
@@ -311,6 +348,14 @@ object JaiParserUtil : GeneratedParserUtilBase() {
if (i < 0) return false
}
// Only a `,flag` belonging to the prefix, as in `using,except(x)`.
// A comma between declared names is handled by the loop below.
T.COMMA -> {
if (!inPrefix || b.lookAhead(i + 1) !== T.IDENT) break@loop
i += 2
inPrefix = false
}
else -> {
break@loop
}

View File

@@ -1,6 +1,7 @@
package dev.hgh.jai.parser
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import com.intellij.testFramework.fixtures.BasePlatformTestCase
@@ -9,39 +10,30 @@ 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.
* Edit [snippets] and [corpusFiles] freely while iterating on `Jai.bnf`.
*/
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",
"#scope_file\n\n\nbig_endian :: () -> bool {\n return true;\n}\n",
"S :: struct {\n #as using,except(vtable) iunknown: IUnknown;\n}\n",
"using,except(FT_Init) new_module :: #import \"freetype\";\n",
"operator []= :: inline (a: *B, i: int, v: bool) { }\n",
"inotify_init :: (flags: s32 = 0) -> s32 #foreign libc \"inotify_init1\";\n",
"F :: (a: *L) -> E #foreign ft #deprecated \"msg\";\n",
)
/** Corpus files to dump the first error of; edit freely while working. */
/** Corpus files to dump the first error of. */
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",
"modules/Basic/Array.jai",
"modules/Debug/windows.jai",
"modules/Simp/backend/gl.jai",
"modules/GetRect/system/occlusion.jai",
"modules/POSIX/compare_bindings.jai",
"modules/Android/Toolchain/apk.jai",
"modules/Curl/examples/ftp.jai",
"modules/Objective_C/LightweightRenderingView/module.jai",
)
fun testCorpusFiles() {
@@ -54,11 +46,6 @@ class DebugParseTest : BasePlatformTestCase() {
}
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) {
@@ -89,7 +76,7 @@ class DebugParseTest : BasePlatformTestCase() {
println(" at '${text.substring(error.textOffset).take(80).replace("\n", "\\n")}'")
}
private fun firstError(file: com.intellij.psi.PsiFile): PsiErrorElement? {
private fun firstError(file: PsiFile): PsiErrorElement? {
var first: PsiErrorElement? = null
file.accept(
object : PsiRecursiveElementWalkingVisitor() {

View File

@@ -36,6 +36,7 @@ class JaiCorpusParserTest : BasePlatformTestCase() {
var totalErrors = 0
val filesWithErrors = mutableListOf<String>()
val firstErrors = mutableListOf<String>()
val allErrors = mutableListOf<String>()
val histogram = mutableMapOf<String, Int>()
for (file in jaiFiles) {
@@ -62,10 +63,8 @@ class JaiCorpusParserTest : BasePlatformTestCase() {
val offset = error.textOffset
val got = snippet(text, offset).take(GOT_WIDTH)
histogram.merge(got, 1, Int::plus)
if (firstErrors.size < REPORTED_ERRORS) {
val line = text.substring(0, offset).count { it == '\n' } + 1
firstErrors.add("$relative:$line: ${error.errorDescription} [at '$got']")
}
val line = text.substring(0, offset).count { it == '\n' } + 1
allErrors.add("$relative:$line: ${error.errorDescription} [at '$got']")
}
}
@@ -82,6 +81,10 @@ class JaiCorpusParserTest : BasePlatformTestCase() {
.take(REPORTED_KINDS)
.forEach { (token, count) -> println(" %5d %s".format(count, token)) }
}
// A spread across the corpus, not the first N alphabetically: the failures
// cluster by directory, so an alphabetical head hides whole categories.
val stride = maxOf(1, allErrors.size / REPORTED_ERRORS)
allErrors.filterIndexed { index, _ -> index % stride == 0 }.take(REPORTED_ERRORS).forEach { println(" $it") }
firstErrors.forEach { println(" $it") }
assertTrue(
@@ -103,7 +106,7 @@ class JaiCorpusParserTest : BasePlatformTestCase() {
private companion object {
/** Ratchet. Raise it as the grammar improves; never lower it. */
const val MIN_CLEAN_FILES = 4
const val MIN_CLEAN_FILES = 575
const val REPORTED_ERRORS = 25
const val REPORTED_KINDS = 20
const val GOT_WIDTH = 14