Tier 2 golden trees, and #scope_file is a statement not a modifier
isDeclarationAhead used to skip *any* directive, so '#scope_file' was absorbed as
a modifier of the declaration after it. That misreports scope, since a scope
directive governs everything that follows it. Only #as, #overlay, #add_context
and #no_reset actually prefix a declaration in the corpus; the rest are
statements now, which the regenerated Directives.txt shows.
Golden fixtures cover the reference doc's gotcha list: declaration forms,
procedures (named/multiple/variadic/polymorphic/foreign returns), structs, enums,
unions, array and pointer types, the 'if x == { case }' switch form, for
modifiers, ifx, and directives including a here-string.
DebugParseTest is now inert by default and documented as the scratch loop.
generateParser wipes its output through a Delete task rather than a doFirst,
because a lambda added from a Kotlin build script captures the script object and
breaks the configuration cache ('./jaigradle check' failed to store it).
check and verifyPlugin (IU-253/261/262) both green.
This commit is contained in:
@@ -91,6 +91,17 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
"this",
|
||||
)
|
||||
|
||||
/**
|
||||
* Directives that modify the declaration that follows them, rather than standing
|
||||
* alone as a statement.
|
||||
*
|
||||
* The distinction matters for the tree shape: `#scope_file` changes visibility for
|
||||
* everything *after* it, so attaching it to the next declaration would misreport
|
||||
* that declaration's scope. Taken from the corpus, where only these four appear
|
||||
* directly in front of a `name :` / `name ::` / `name :=`.
|
||||
*/
|
||||
private val DIRECTIVES_ON_DECLARATIONS = setOf("as", "overlay", "add_context", "no_reset")
|
||||
|
||||
// ---------------------------------------------------------------- directives
|
||||
|
||||
/**
|
||||
@@ -343,7 +354,13 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
var inPrefix = false
|
||||
loop@ while (true) {
|
||||
when (b.lookAhead(i)) {
|
||||
T.DIRECTIVE, T.KW_USING -> {
|
||||
T.DIRECTIVE -> {
|
||||
if (!isDeclarationDirective(b, i)) break@loop
|
||||
i++
|
||||
inPrefix = true
|
||||
}
|
||||
|
||||
T.KW_USING -> {
|
||||
i++
|
||||
inPrefix = true
|
||||
}
|
||||
@@ -378,6 +395,20 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the DIRECTIVE at lookahead [index] modifies the declaration that
|
||||
* follows. Only the first token can be read as text through the builder, which is
|
||||
* enough: a declaration-modifying directive is always the first thing we look at.
|
||||
*/
|
||||
private fun isDeclarationDirective(
|
||||
b: PsiBuilder,
|
||||
index: Int,
|
||||
): Boolean {
|
||||
if (index != 0) return true
|
||||
val text = b.tokenText ?: return false
|
||||
return text.removePrefix("#") in DIRECTIVES_ON_DECLARATIONS
|
||||
}
|
||||
|
||||
/**
|
||||
* Index just past the closer matching the bracket at [start], or -1 if unbalanced.
|
||||
* Covers `(…)`, `[…]`, `.[…]` and `.{…}`, which all appear in declaration
|
||||
@@ -479,6 +510,22 @@ object JaiParserUtil : GeneratedParserUtilBase() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the next token cannot start a polymorph capture.
|
||||
*
|
||||
* An unparenthesised return list is comma-separated, and so is the parameter list
|
||||
* that may enclose it. A `$T` after the comma can only be a parameter, so the
|
||||
* return list has to stop there.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun notPolyParamAhead(
|
||||
b: PsiBuilder,
|
||||
level: Int,
|
||||
): Boolean {
|
||||
val t = b.tokenType
|
||||
return t !== T.DOLLAR && t !== T.DOUBLE_DOLLAR
|
||||
}
|
||||
|
||||
/** `IDENT ':'` — a loop label. */
|
||||
@JvmStatic
|
||||
fun isLabelAhead(
|
||||
|
||||
Reference in New Issue
Block a user