open import Padova2025.ProgrammingBasics.Naturals.Base
open import Padova2025.ProgrammingBasics.Naturals.Arithmetic
open import Padova2025.ProgrammingBasics.Lists
open import Padova2025.ProvingBasics.Equality.Base
open import Padova2025.ProvingBasics.Equality.Reasoning.Core
data Expr : Set where
lit : ℕ → Expr
add : Expr → Expr → Expr
eval : Expr → ℕ
eval (lit x) = x
eval (add x y) = eval x + eval y
example-expr : Expr
example-expr = add (lit two) (add (lit one) (lit one))
_ : eval example-expr ≡ four
_ = refl
data Op : Set where
PUSH : ℕ → Op
SUM : Op
POP : Op
Stack : Set
Stack = List ℕ
Code : Set
Code = List Op
run : Code → Stack → Stack
run [] st = st
run (PUSH x ∷ cs) st = run cs (x ∷ st)
run (SUM ∷ cs) [] = []
run (SUM ∷ cs) (x ∷ []) = []
run (SUM ∷ cs) (x ∷ y ∷ st) = run cs ((y + x) ∷ st)
run (POP ∷ cs) [] = run cs []
run (POP ∷ cs) (x ∷ st) = run cs st
compile : Expr → Code → Code
compile (lit x) cs = PUSH x ∷ cs
compile (add x y) cs = compile x (compile y (SUM ∷ cs))
compile₀ : Expr → Code
compile₀ x = compile x []
theorem : (e : Expr) (cs : Code) (st : Stack) → run (compile e cs) st ≡ run cs (eval e ∷ st)
theorem (lit x) cs st = refl
theorem (add x y) cs st = begin
run (compile (add x y) cs) st ≡⟨⟩
run (compile x (compile y (SUM ∷ cs))) st ≡⟨ theorem x (compile y (SUM ∷ cs)) st ⟩
run (compile y (SUM ∷ cs)) (eval x ∷ st) ≡⟨ theorem y (SUM ∷ cs) (eval x ∷ st) ⟩
run (SUM ∷ cs) (eval y ∷ eval x ∷ st) ≡⟨⟩
run cs ((eval x + eval y) ∷ st) ≡⟨⟩
run cs (eval (add x y) ∷ st) ∎
theorem₀ : (e : Expr) → run (compile₀ e) [] ≡ eval e ∷ []
theorem₀ e = theorem e [] []