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