perf(gengo): fold DO WHILE .T. / .F. at compile time

DO WHILE .T. now emits a bare for-loop with no PushBool/PopLogical
per iteration — saves a stack roundtrip on every trip through the
idiomatic infinite-loop pattern (9 .prg files use it). DO WHILE .F.
emits nothing. Loop exits still work via EXIT / RETURN.

FiveSql2 43/43, Harbour compat 56/56.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 08:45:58 +09:00
parent c3a9eb33a4
commit 67a9855319

View File

@@ -1391,6 +1391,11 @@ emit:
}
func (g *Generator) emitDoWhile(s *ast.DoWhileStmt, locals localMap) {
// DO WHILE .F. — body is unreachable; emit nothing.
if v, ok := boolLiteralValue(s.Cond); ok && !v {
return
}
// Detect RDD commands in body for WA hoisting
hasRDD := hasRDDCommands(s.Body)
safeToHoist := hasRDD && !hasWorkareaChange(s.Body)
@@ -1405,8 +1410,12 @@ func (g *Generator) emitDoWhile(s *ast.DoWhileStmt, locals localMap) {
g.writeln("for {")
g.indent++
g.emitExpr(s.Cond)
g.writeln("if !t.PopLogical() { break }")
// DO WHILE .T. — the idiomatic infinite loop. Skip the per-iteration
// PushBool/PopLogical; exit only through EXIT / LOOP / RETURN.
if v, ok := boolLiteralValue(s.Cond); !ok || !v {
g.emitExpr(s.Cond)
g.writeln("if !t.PopLogical() { break }")
}
for _, stmt := range s.Body {
g.emitStmt(stmt, locals)
}