Build: regenerate the parser on every build, and always from scratch

Two staleness traps cost real debugging time, and both made grammar edits look
like they had no effect:

- compileJava/compileKotlin read src/main/gen with no task dependency, so an
  edit to Jai.bnf could be compiled against the previous generated parser. The
  compiled JaiParser.class was three minutes older than its source while the
  tests reported green. They now depend on generateParser.
- purgeOldFiles is not enough. Grammar-Kit rewrites only the files whose rule
  changed, so JaiDeclaration kept a getArgumentList() its regenerated Impl no
  longer had and the build failed inside generated code. generateParser now
  deletes src/main/gen first.

Grammar: named return defaults use a private rule rather than 'initializer'.
Giving the default its own PSI element made the enclosing procLiteralExpr end
early, so '-> a: int = 1 { }' silently lost its body.

Corpus parse 90.9% (649/714), ratchet at 645.
This commit is contained in:
hgranthorner
2026-08-04 12:37:46 -04:00
parent b8e55fcd50
commit dc53033898
8 changed files with 245 additions and 80 deletions

View File

@@ -15,12 +15,11 @@ import java.io.File
class DebugParseTest : BasePlatformTestCase() {
private val snippets =
listOf(
"#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",
"f :: () -> a: int = 1;\n",
"f :: () -> a: int = 1 { }\n",
"f :: () -> a: int = xx { }\n",
"f :: () -> a: int = 1 #foreign lib;\n",
"g :: () { x := 1; }\n",
)
/** Corpus files to dump the first error of. */
@@ -53,11 +52,17 @@ class DebugParseTest : BasePlatformTestCase() {
val error = firstError(file)
if (error == null) {
println("ok ${text.replace("\n", "\\n")}")
if (System.getProperty("jai.debug.tree") != null) {
println(com.intellij.psi.impl.DebugUtil.psiToString(file, true, false))
}
} else {
failures++
val at = text.substring(error.textOffset).take(28).replace("\n", "\\n")
println("FAIL ${text.replace("\n", "\\n")}")
println(" ${error.errorDescription} | at '$at'")
if (System.getProperty("jai.debug.tree") != null) {
println(com.intellij.psi.impl.DebugUtil.psiToString(file, true, false))
}
}
}
println("$failures/${snippets.size} snippets failed")

View File

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