perf(gengo): fold .NOT. <literal> at compile time
`.NOT. .T.` / `.NOT. .F.` emit PushBool directly instead of pushing the source bool and calling Not(). boolLiteralValue also sees through an outer NOT, so `IF !.F.` now triggers the full dead-branch pass (no PopLogical wrapper either). FiveSql2 43/43, Harbour compat 56/56. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1265,9 +1265,17 @@ func (g *Generator) emitCallAsStmt(call *ast.CallExpr, locals localMap) {
|
||||
g.writeln(fmt.Sprintf("t.Do(%d)", len(call.Args)))
|
||||
}
|
||||
|
||||
// boolLiteralValue returns (value, true) if e is a bare .T./.F. literal.
|
||||
// Used by emitIf to skip dead branches.
|
||||
// boolLiteralValue returns (value, true) if e reduces to a .T./.F.
|
||||
// literal at compile time. Sees through an outer `.NOT.` so expressions
|
||||
// like `!.F.` also collapse. Used by emitIf to skip dead branches and
|
||||
// by the AND/OR short-circuit emitter.
|
||||
func boolLiteralValue(e ast.Expr) (bool, bool) {
|
||||
if u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.NOT {
|
||||
if v, ok := boolLiteralValue(u.X); ok {
|
||||
return !v, true
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
lit, ok := e.(*ast.LiteralExpr)
|
||||
if !ok {
|
||||
return false, false
|
||||
@@ -1988,6 +1996,17 @@ func (g *Generator) emitExpr(expr ast.Expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fold `.NOT. .T.` → .F. and `.NOT. .F.` → .T. at compile time.
|
||||
if e.Op == token.NOT {
|
||||
if v, ok := boolLiteralValue(e.X); ok {
|
||||
if v {
|
||||
g.writeln("t.PushBool(false)")
|
||||
} else {
|
||||
g.writeln("t.PushBool(true)")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
g.emitExpr(e.X)
|
||||
g.emitUnaryOp(e.Op)
|
||||
case *ast.AssignExpr:
|
||||
|
||||
Reference in New Issue
Block a user