From 086ae993c5cca1923c594233143c4eba85487fe2 Mon Sep 17 00:00:00 2001 From: hgranthorner <37941012+hgranthorner@users.noreply.github.com> Date: Tue, 4 Aug 2026 12:20:36 -0400 Subject: [PATCH] Parser: corpus parse rate 69% -> 81%, and stop --tests from sticking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- jaitest | 12 +- .../gen/dev/hgh/jai/parser/JaiParser.java | 668 +++++++++++++----- src/main/gen/dev/hgh/jai/psi/JaiArgument.java | 3 + .../gen/dev/hgh/jai/psi/JaiDeclaration.java | 7 +- .../gen/dev/hgh/jai/psi/JaiDirectiveExpr.java | 7 +- src/main/gen/dev/hgh/jai/psi/JaiIfxExpr.java | 3 + .../gen/dev/hgh/jai/psi/JaiNamedArgument.java | 19 + .../gen/dev/hgh/jai/psi/JaiProcModifier.java | 7 +- .../hgh/jai/psi/JaiPushContextStatement.java | 2 +- src/main/gen/dev/hgh/jai/psi/JaiTypes.java | 4 + .../gen/dev/hgh/jai/psi/JaiUnionExpr.java | 3 + src/main/gen/dev/hgh/jai/psi/JaiVisitor.java | 4 + .../dev/hgh/jai/psi/impl/JaiArgumentImpl.java | 6 + .../hgh/jai/psi/impl/JaiDeclarationImpl.java | 12 +- .../jai/psi/impl/JaiDirectiveExprImpl.java | 12 +- .../dev/hgh/jai/psi/impl/JaiIfxExprImpl.java | 6 + .../jai/psi/impl/JaiNamedArgumentImpl.java | 48 ++ .../hgh/jai/psi/impl/JaiProcModifierImpl.java | 12 +- .../psi/impl/JaiPushContextStatementImpl.java | 4 +- .../hgh/jai/psi/impl/JaiUnionExprImpl.java | 6 + src/main/grammar/Jai.bnf | 45 +- .../dev/hgh/jai/parser/JaiParserUtil.kt | 47 +- .../dev/hgh/jai/parser/DebugParseTest.kt | 49 +- .../dev/hgh/jai/parser/JaiCorpusParserTest.kt | 13 +- 24 files changed, 728 insertions(+), 271 deletions(-) create mode 100644 src/main/gen/dev/hgh/jai/psi/JaiNamedArgument.java create mode 100644 src/main/gen/dev/hgh/jai/psi/impl/JaiNamedArgumentImpl.java diff --git a/jaitest b/jaitest index 0ad6147..73e7e86 100755 --- a/jaitest +++ b/jaitest @@ -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]}" } diff --git a/src/main/gen/dev/hgh/jai/parser/JaiParser.java b/src/main/gen/dev/hgh/jai/parser/JaiParser.java index eb99227..af7befa 100644 --- a/src/main/gen/dev/hgh/jai/parser/JaiParser.java +++ b/src/main/gen/dev/hgh/jai/parser/JaiParser.java @@ -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, ""); 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_; } + /* ********************************************************** */ + // <> (',' <>)* + 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_; + } + + // (',' <>)* + 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; + } + + // ',' <> + 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 { } /* ********************************************************** */ - // ':' [<>] procModifier* [('=' | ':') initializer] - // | ':=' initializer - // | '::' initializer + // ':' [<>] 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_; } - // ':' [<>] procModifier* [('=' | ':') initializer] + // ':' [<>] 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 { /* ********************************************************** */ // <> directiveFlag_* <> + // | <> directiveFlag_* [<>] [STRING] + // | <> directiveFlag_* [<>] [STRING] + // | <> directiveFlag_* ['(' [argList] ')'] [block | expr] // | <> expr [expr] // | <> '(' [paramList] ')' ['(' [paramList] ')'] [block] // | <> 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; } - // <> expr [expr] + // <> directiveFlag_* [<>] [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; } - // <> '(' [paramList] ')' ['(' [paramList] ')'] [block] + // [<>] + 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; + } + + // <> directiveFlag_* [<>] [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; + } + + // [<>] 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; - } - - // <> directiveFlag_* block + // <> 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; } - // <> 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_; + } + + // <> 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; } - // <> directiveFlag_* + // <> '(' [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; + } + + // <> 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; + } + + // <> 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; + } + + // <> 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 + // <> 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' | <> + 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_; } + /* ********************************************************** */ + // <> 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, ""); + 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 { } /* ********************************************************** */ - // <> directiveFlag_* block - // | <> directiveFlag_* [expr] - // | <> 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, ""); - 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_; } - // <> 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; - } - - // <> 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; - } - - // <> 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_, "", 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, ""); 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, ""); + 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_; } diff --git a/src/main/gen/dev/hgh/jai/psi/JaiArgument.java b/src/main/gen/dev/hgh/jai/psi/JaiArgument.java index 346b9b2..167cfe2 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiArgument.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiArgument.java @@ -10,4 +10,7 @@ public interface JaiArgument extends PsiElement { @Nullable JaiExpr getExpr(); + @Nullable + JaiNamedArgument getNamedArgument(); + } diff --git a/src/main/gen/dev/hgh/jai/psi/JaiDeclaration.java b/src/main/gen/dev/hgh/jai/psi/JaiDeclaration.java index e1b3377..2ce8e9a 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiDeclaration.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiDeclaration.java @@ -7,11 +7,14 @@ import com.intellij.psi.PsiElement; public interface JaiDeclaration extends PsiElement { + @NotNull + List getArgumentList(); + @NotNull JaiDeclNames getDeclNames(); - @Nullable - JaiInitializer getInitializer(); + @NotNull + List getInitializerList(); @NotNull List getProcModifierList(); diff --git a/src/main/gen/dev/hgh/jai/psi/JaiDirectiveExpr.java b/src/main/gen/dev/hgh/jai/psi/JaiDirectiveExpr.java index ed650f0..8c5bd30 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiDirectiveExpr.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiDirectiveExpr.java @@ -7,11 +7,14 @@ import com.intellij.psi.PsiElement; public interface JaiDirectiveExpr extends JaiExpr { + @NotNull + List getArgumentList(); + @Nullable JaiBlock getBlock(); - @NotNull - List getExprList(); + @Nullable + JaiExpr getExpr(); @NotNull List getParameterList(); diff --git a/src/main/gen/dev/hgh/jai/psi/JaiIfxExpr.java b/src/main/gen/dev/hgh/jai/psi/JaiIfxExpr.java index 4a3f558..5203ee8 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiIfxExpr.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiIfxExpr.java @@ -7,6 +7,9 @@ import com.intellij.psi.PsiElement; public interface JaiIfxExpr extends JaiExpr { + @NotNull + List getBlockList(); + @NotNull List getExprList(); diff --git a/src/main/gen/dev/hgh/jai/psi/JaiNamedArgument.java b/src/main/gen/dev/hgh/jai/psi/JaiNamedArgument.java new file mode 100644 index 0000000..99cf75a --- /dev/null +++ b/src/main/gen/dev/hgh/jai/psi/JaiNamedArgument.java @@ -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(); + +} diff --git a/src/main/gen/dev/hgh/jai/psi/JaiProcModifier.java b/src/main/gen/dev/hgh/jai/psi/JaiProcModifier.java index c7bc44b..37bc3c5 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiProcModifier.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiProcModifier.java @@ -7,10 +7,7 @@ import com.intellij.psi.PsiElement; public interface JaiProcModifier extends PsiElement { - @Nullable - JaiBlock getBlock(); - - @Nullable - JaiExpr getExpr(); + @NotNull + JaiDirectiveExpr getDirectiveExpr(); } diff --git a/src/main/gen/dev/hgh/jai/psi/JaiPushContextStatement.java b/src/main/gen/dev/hgh/jai/psi/JaiPushContextStatement.java index 5232622..fec6614 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiPushContextStatement.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiPushContextStatement.java @@ -10,7 +10,7 @@ public interface JaiPushContextStatement extends PsiElement { @NotNull JaiBlock getBlock(); - @NotNull + @Nullable JaiExpr getExpr(); } diff --git a/src/main/gen/dev/hgh/jai/psi/JaiTypes.java b/src/main/gen/dev/hgh/jai/psi/JaiTypes.java index 1bfdb23..d06825d 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiTypes.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiTypes.java @@ -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); } diff --git a/src/main/gen/dev/hgh/jai/psi/JaiUnionExpr.java b/src/main/gen/dev/hgh/jai/psi/JaiUnionExpr.java index 42ebb2c..6da178a 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiUnionExpr.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiUnionExpr.java @@ -10,6 +10,9 @@ public interface JaiUnionExpr extends JaiExpr { @NotNull JaiBlock getBlock(); + @NotNull + List getParameterList(); + @NotNull List getProcModifierList(); diff --git a/src/main/gen/dev/hgh/jai/psi/JaiVisitor.java b/src/main/gen/dev/hgh/jai/psi/JaiVisitor.java index a5f3682..9c8fb30 100644 --- a/src/main/gen/dev/hgh/jai/psi/JaiVisitor.java +++ b/src/main/gen/dev/hgh/jai/psi/JaiVisitor.java @@ -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); } diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiArgumentImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiArgumentImpl.java index 34e7a4c..a3f85b7 100644 --- a/src/main/gen/dev/hgh/jai/psi/impl/JaiArgumentImpl.java +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiArgumentImpl.java @@ -33,4 +33,10 @@ public class JaiArgumentImpl extends ASTWrapperPsiElement implements JaiArgument return findChildByClass(JaiExpr.class); } + @Override + @Nullable + public JaiNamedArgument getNamedArgument() { + return findChildByClass(JaiNamedArgument.class); + } + } diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiDeclarationImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiDeclarationImpl.java index 6e38ac9..7b45ebe 100644 --- a/src/main/gen/dev/hgh/jai/psi/impl/JaiDeclarationImpl.java +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiDeclarationImpl.java @@ -27,6 +27,12 @@ public class JaiDeclarationImpl extends ASTWrapperPsiElement implements JaiDecla else super.accept(visitor); } + @Override + @NotNull + public List 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 getInitializerList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiInitializer.class); } @Override diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiDirectiveExprImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiDirectiveExprImpl.java index 7ebe7ab..9fe298b 100644 --- a/src/main/gen/dev/hgh/jai/psi/impl/JaiDirectiveExprImpl.java +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiDirectiveExprImpl.java @@ -27,6 +27,12 @@ public class JaiDirectiveExprImpl extends JaiExprImpl implements JaiDirectiveExp else super.accept(visitor); } + @Override + @NotNull + public List 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 getExprList() { - return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiExpr.class); + @Nullable + public JaiExpr getExpr() { + return findChildByClass(JaiExpr.class); } @Override diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiIfxExprImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiIfxExprImpl.java index ac84059..74f107c 100644 --- a/src/main/gen/dev/hgh/jai/psi/impl/JaiIfxExprImpl.java +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiIfxExprImpl.java @@ -27,6 +27,12 @@ public class JaiIfxExprImpl extends JaiExprImpl implements JaiIfxExpr { else super.accept(visitor); } + @Override + @NotNull + public List getBlockList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiBlock.class); + } + @Override @NotNull public List getExprList() { diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiNamedArgumentImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiNamedArgumentImpl.java new file mode 100644 index 0000000..cffddcb --- /dev/null +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiNamedArgumentImpl.java @@ -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); + } + +} diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiProcModifierImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiProcModifierImpl.java index f4fde3e..b9be03c 100644 --- a/src/main/gen/dev/hgh/jai/psi/impl/JaiProcModifierImpl.java +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiProcModifierImpl.java @@ -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); } } diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiPushContextStatementImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiPushContextStatementImpl.java index c1bf6f1..975d587 100644 --- a/src/main/gen/dev/hgh/jai/psi/impl/JaiPushContextStatementImpl.java +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiPushContextStatementImpl.java @@ -34,9 +34,9 @@ public class JaiPushContextStatementImpl extends ASTWrapperPsiElement implements } @Override - @NotNull + @Nullable public JaiExpr getExpr() { - return findNotNullChildByClass(JaiExpr.class); + return findChildByClass(JaiExpr.class); } } diff --git a/src/main/gen/dev/hgh/jai/psi/impl/JaiUnionExprImpl.java b/src/main/gen/dev/hgh/jai/psi/impl/JaiUnionExprImpl.java index cd8c4de..e01f82c 100644 --- a/src/main/gen/dev/hgh/jai/psi/impl/JaiUnionExprImpl.java +++ b/src/main/gen/dev/hgh/jai/psi/impl/JaiUnionExprImpl.java @@ -33,6 +33,12 @@ public class JaiUnionExprImpl extends JaiExprImpl implements JaiUnionExpr { return findNotNullChildByClass(JaiBlock.class); } + @Override + @NotNull + public List getParameterList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, JaiParameter.class); + } + @Override @NotNull public List getProcModifierList() { diff --git a/src/main/grammar/Jai.bnf b/src/main/grammar/Jai.bnf index ac0bcf5..8060531 100644 --- a/src/main/grammar/Jai.bnf +++ b/src/main/grammar/Jai.bnf @@ -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 ::= <> 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_ ::= ':' [<>] procModifier* [('=' | ':') initializer] - | ':=' initializer - | '::' initializer +private declTail_ ::= ':' [<>] 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_ ::= <> (',' <>)* 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' | <> +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 ::= <> memberName '=' (block | expr) primaryExpr ::= procLiteralExpr | structExpr @@ -364,20 +374,24 @@ returnGroup ::= '(' [returnItem (',' returnItem)*] ')' returnItem ::= [<> IDENT ':'] <> // `#foreign lib`, `#modify { ... }`, `#c_call`, `#expand`, … -procModifier ::= <> directiveFlag_* block - | <> directiveFlag_* [expr] - | <> 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 ::= <> directiveFlag_* <> + | <> directiveFlag_* [<>] [STRING] + | <> directiveFlag_* [<>] [STRING] + | <> directiveFlag_* ['(' [argList] ')'] [block | expr] | <> expr [expr] | <> '(' [paramList] ')' ['(' [paramList] ')'] [block] | <> directiveFlag_* block @@ -385,5 +399,6 @@ directiveExpr ::= <> directiveFlag_* <> | <> 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_ ::= <> diff --git a/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt b/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt index 5e675b4..dda9c8a 100644 --- a/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt +++ b/src/main/kotlin/dev/hgh/jai/parser/JaiParserUtil.kt @@ -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 } diff --git a/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt b/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt index 0d0f6bf..c336e4b 100644 --- a/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt +++ b/src/test/kotlin/dev/hgh/jai/parser/DebugParseTest.kt @@ -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=` 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() { diff --git a/src/test/kotlin/dev/hgh/jai/parser/JaiCorpusParserTest.kt b/src/test/kotlin/dev/hgh/jai/parser/JaiCorpusParserTest.kt index ca5269a..0560518 100644 --- a/src/test/kotlin/dev/hgh/jai/parser/JaiCorpusParserTest.kt +++ b/src/test/kotlin/dev/hgh/jai/parser/JaiCorpusParserTest.kt @@ -36,6 +36,7 @@ class JaiCorpusParserTest : BasePlatformTestCase() { var totalErrors = 0 val filesWithErrors = mutableListOf() val firstErrors = mutableListOf() + val allErrors = mutableListOf() val histogram = mutableMapOf() 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