Skip to content

Commit d7c6646

Browse files
committed
autotranslate/scratch: phase-1 inline .tex compile gate (#951)
Extends the mirror gate with the inline-code compile check BR scoped in #951. For each Code/CodeSmall/lstlisting body in the .tex corpus that renderCodeIds actually rewrites and that is NOT inside an \ifswedish clamp (Latex.ifswedishRanges — the mirror leaves clamped code alone), compile the Swedish body AND the rendered English body. REGRESSION = Swedish compiles but English does not; skip if BOTH fail (many inline bodies aren't standalone-compilable: neighbour context / signature-only / script style — self-skipping beats false alarms). Strips a leading lstlisting optional-arg line before compiling. Uses the mirror's per-file overrides (renderCodeIds(body, extraId)) so per-file clusters (e.g. ANIMAL) are gated too. REPL transcripts are DEFERRED to phase 2 (they need splitting on `scala>` prompts); Trace/Output aren't compilable Scala. Both counts are logged so nothing silently reads as "covered". Also guards os.walk against a missing examples/ dir. Tested: 23 self-contained inline bodies compile clean (non-vacuous); an injected Tomat->Tomato duplicate-class rename is caught (exit 1) while a \ifswedish-clamped copy of the same break is correctly skipped.
1 parent a77f959 commit d7c6646

1 file changed

Lines changed: 46 additions & 3 deletions

File tree

autotranslate/scratch/verify-mirror-examples.scala

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//> using jvm 21
33
//> using dep com.lihaoyi::os-lib:0.11.8
44
//> using file ../CodeGlossary.scala
5+
//> using file ../Latex.scala
56

67
// COMPILE GATE for the mirror's example-code translation (#947/#948 + the personExample s-interp fix).
78
// "Only compilable code should pass": every example .scala/.java that CodeGlossary.renderCodeIds rewrites
@@ -19,14 +20,19 @@
1920
// key surviving in a rendered Scala-code env / inline \code fails the gate — so a ratified sound can't regress
2021
// to Swedish, and a NEW sound added to a .tex but not to codeStr is caught.
2122
//
23+
// Plus a PHASE-1 INLINE .tex COMPILE GATE (#951): the same regression rule applied to the display Scala-code
24+
// envs (Code/CodeSmall/lstlisting) the mirror rewrites in .tex — skipping \ifswedish-clamped code and deferring
25+
// REPL transcripts to phase 2. See that section below.
26+
//
2227
// scala-cli run autotranslate/scratch/verify-mirror-examples.scala -- <introprog-root>
2328
// (exit 0 = clean, exit 1 = at least one regression or an untranslated ratified code-string)
2429

2530
@main def verifyMirrorExamples(rootStr: String): Unit =
2631
val root = os.Path(rootStr, os.pwd)
2732
val dir = root / "compendium" / "examples" // workspace/ is served by the hand-maintained workspace-en
28-
val files = os.walk(dir).filter(f => os.isFile(f) && (f.ext == "scala" || f.ext == "java"))
29-
.sortBy(_.toString)
33+
val files =
34+
if !os.exists(dir) then Seq.empty[os.Path]
35+
else os.walk(dir).filter(f => os.isFile(f) && (f.ext == "scala" || f.ext == "java")).sortBy(_.toString)
3036
def compiles(code: String, name: String): Boolean =
3137
val tmp = os.temp.dir(prefix = "mirror-gate") // keep the original filename (Java needs it)
3238
os.write.over(tmp / name, code)
@@ -70,4 +76,41 @@
7076
if leaks.nonEmpty then leaks.foreach(l => println(" LEAK: " + l))
7177
else println("PASS — every ratified code-string is translated in inline .tex code regions.")
7278

73-
if regressions.nonEmpty || leaks.nonEmpty then sys.exit(1)
79+
// ---- PHASE-1 INLINE .tex COMPILE GATE (#951) ----
80+
// Gate the display Scala-code envs the mirror actually rewrites. For each Code/CodeSmall/lstlisting body that
81+
// is NOT inside an \ifswedish clamp (the mirror leaves clamped code alone, via Latex.ifswedishRanges) and that
82+
// renderCodeIds changes, compile the Swedish body AND the rendered English body. REGRESSION = Swedish compiles
83+
// but English does NOT. Skip if BOTH fail — many inline bodies aren't standalone-compilable (neighbour context
84+
// / signature-only / script style), and self-skipping those beats false alarms. REPL* transcripts are DEFERRED
85+
// to phase 2 (they need splitting on `scala>` prompts); Trace/Output aren't Scala. Uses the SAME per-file
86+
// overrides as the mirror (renderCodeIds(body, extraId)) so per-file-scoped clusters (e.g. ANIMAL) are gated.
87+
val phase1Envs = Set("Code", "CodeSmall", "lstlisting")
88+
def stripLstOpt(body: String): String = // \begin{lstlisting}[opts]: the [opts] can trail on line 1
89+
body.replaceFirst("(?s)\\A[ \\t]*\\[[^\\]]*\\]", "")
90+
var inChecked = 0; var inSkipped = 0; var replDeferred = 0; var nonCode = 0
91+
val inRegressions = collection.mutable.ArrayBuffer[String]()
92+
for f <- texFiles do
93+
val tex = os.read(f)
94+
val rel = f.relativeTo(root).toString
95+
val extraId = CodeGlossary.overridesFor(rel)
96+
if !CodeGlossary.isOptedOut(rel) then
97+
val clampRanges = Latex.ifswedishRanges(tex)
98+
def clamped(pos: Int): Boolean = clampRanges.exists((a, b) => pos >= a && pos < b)
99+
for m <- envRe.findAllMatchIn(tex) if !clamped(m.start) do
100+
val env = m.group(1)
101+
val body = if env == "lstlisting" then stripLstOpt(m.group(2)) else m.group(2)
102+
val en = CodeGlossary.renderCodeIds(body, extraId)
103+
if en != body then // only REWRITTEN bodies are gate-relevant
104+
if env.startsWith("REPL") then replDeferred += 1 // rewritten transcripts -> phase 2
105+
else if !phase1Envs(env) then nonCode += 1 // Trace/Output — not compilable Scala
106+
else if compiles(en, "Inline.scala") then inChecked += 1
107+
else if compiles(body, "Inline.scala") then
108+
inRegressions += s"$rel ($env)"
109+
println(s" INLINE REGRESSION: $rel ($env) — compiles in Swedish but NOT after rename")
110+
else inSkipped += 1
111+
println(s"\n=== inline .tex compile gate (phase 1): $inChecked ok, $inSkipped skipped (not standalone), " +
112+
s"$replDeferred REPL deferred to phase 2, $nonCode Trace/Output not gated, ${inRegressions.size} REGRESSIONS ===")
113+
if inRegressions.nonEmpty then println("FAIL — inline translation broke compilation in: " + inRegressions.mkString(", "))
114+
else println("PASS — every rewritten, self-contained inline Scala-code env still compiles.")
115+
116+
if regressions.nonEmpty || leaks.nonEmpty || inRegressions.nonEmpty then sys.exit(1)

0 commit comments

Comments
 (0)