Lean migration: Phase 7 (Sign + Constant analyses, executable)

- Spa.Showable: port of Showable.agda (quoted strings, map format) for
  output parity
- Spa.Analysis.Utils: eval_combine₂
- Spa.Lattice.AboveBelow.le_cases: order of the flat lattice by cases
- Spa.Analysis.Sign / Spa.Analysis.Constant: the four monotonicity
  POSTULATES from the Agda files are now proved theorems (via le_cases);
  interpretations, evaluator validity, analyze_correct per analysis
- Main + lake exe spa: runs both analyses on the Agda test program;
  constant analysis folds unknown=0, sign analysis gives unknown=⊤

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 20:52:08 -07:00
parent 739fbb503c
commit a82d54666a
9 changed files with 854 additions and 1 deletions

40
lean/Main.lean Normal file
View File

@@ -0,0 +1,40 @@
/-
Port of `Main.agda`. Prints the constant- and sign-analysis results for the
test program (Agda: `putStrLn (output-Const ++ "\n" ++ output-Sign)`).
-/
import Spa.Analysis.Sign
import Spa.Analysis.Constant
namespace Spa
/-- Agda: `testCode`. -/
def testCode : Stmt :=
.andThen (.basic (.assign "zero" (.num 0)))
(.andThen (.basic (.assign "pos" (.add (.var "zero") (.num 1))))
(.andThen (.basic (.assign "neg" (.sub (.var "zero") (.num 1))))
(.basic (.assign "unknown" (.add (.var "pos") (.var "neg"))))))
/-- Agda: `testCodeCond₁`. -/
def testCodeCond₁ : Stmt :=
.andThen (.basic (.assign "var" (.num 1)))
(.ifElse (.var "var")
(.basic (.assign "var" (.add (.var "var") (.num 1))))
(.andThen (.basic (.assign "var" (.sub (.var "var") (.num 1))))
(.basic (.assign "var" (.num 1)))))
/-- Agda: `testCodeCond₂`. -/
def testCodeCond₂ : Stmt :=
.andThen (.basic (.assign "var" (.num 1)))
(.ifElse (.var "var")
(.basic (.assign "x" (.num 1)))
(.basic .noop))
/-- Agda: `testProgram`. -/
def testProgram : Program := testCode
end Spa
/-- Agda: `main`. -/
def main : IO Unit :=
IO.println (Spa.ConstAnalysis.output Spa.testProgram ++ "\n" ++
Spa.SignAnalysis.output Spa.testProgram)