crosslang/golang-lean/GolangLean/Core/Eval.lean
Maximus Gorog fd3d42ae33 Add 'golang-lean/' from commit 'f5f17019224c6a6c319387214ceb8e29d09251c6'
git-subtree-dir: golang-lean
git-subtree-mainline: 6487c7046f
git-subtree-split: f5f1701922
2026-05-12 02:59:14 -06:00

190 lines
5.8 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import GolangLean.Core.Semantics
namespace GolangLean.Core
/-! # Executable evaluator and soundness.
A fuel-bounded recursive evaluator
`eval : Nat → Heap → Env → Term → Option (Value × Heap)`
together with the soundness theorem
`eval n h env e = some (v, h') → BigStep h env e v h'`.
Soundness is the bridge that makes the inductive specification *runnable*.
For any closed TGC term you can write a Lean theorem of the form
`BigStep h env e v h'`
and prove it by `decide`-style execution: run `eval`, then apply
`eval_sound` to the equation. -/
def eval : Nat → Heap → Env → Term → Option (Value × Heap)
| 0, _, _, _ => none
| _ + 1, h, _, .unitT => some (.vUnit, h)
| _ + 1, h, _, .intLit k => some (.vInt k, h)
| _ + 1, h, _, .boolLit b => some (.vBool b, h)
| _ + 1, h, env, .var x =>
match env.lookup x with
| some v => some (v, h)
| none => none
| _ + 1, h, env, .lam x body => some (.vClos x body env, h)
| n + 1, h, env, .app e1 e2 =>
match eval n h env e1 with
| some (.vClos x body env', h1) =>
match eval n h1 env e2 with
| some (v2, h2) => eval n h2 (env'.extend x v2) body
| none => none
| _ => none
| n + 1, h, env, .letIn x e1 e2 =>
match eval n h env e1 with
| some (v1, h1) => eval n h1 (env.extend x v1) e2
| none => none
| n + 1, h, env, .ifte ec e1 e2 =>
match eval n h env ec with
| some (.vBool true, h1) => eval n h1 env e1
| some (.vBool false, h1) => eval n h1 env e2
| _ => none
| n + 1, h, env, .binop op e1 e2 =>
match eval n h env e1 with
| some (v1, h1) =>
match eval n h1 env e2 with
| some (v2, h2) =>
match op.apply v1 v2 with
| some v => some (v, h2)
| none => none
| none => none
| none => none
| n + 1, h, env, .refMk e =>
match eval n h env e with
| some (v, h1) => some (.vLoc h1.size, h1.push v)
| none => none
| n + 1, h, env, .deref e =>
match eval n h env e with
| some (.vLoc loc, h1) =>
match h1[loc]? with
| some v => some (v, h1)
| none => none
| _ => none
| n + 1, h, env, .assign e1 e2 =>
match eval n h env e1 with
| some (.vLoc loc, h1) =>
match eval n h1 env e2 with
| some (v2, h2) =>
if loc < h2.size then some (.vUnit, h2.set! loc v2) else none
| none => none
| _ => none
| n + 1, h, env, .seq e1 e2 =>
match eval n h env e1 with
| some (_, h1) => eval n h1 env e2
| none => none
theorem eval_sound :
∀ (n : Nat) (h : Heap) (env : Env) (e : Term) (v : Value) (h' : Heap),
eval n h env e = some (v, h') → BigStep h env e v h' := by
intro n
induction n with
| zero =>
intro h env e v h' heq
simp [eval] at heq
| succ n ih =>
intro h env e v h' heq
cases e with
| unitT =>
simp [eval] at heq
obtain ⟨rfl, rfl⟩ := heq
exact .unitR
| intLit k =>
simp [eval] at heq
obtain ⟨rfl, rfl⟩ := heq
exact .intLitR k
| boolLit b =>
simp [eval] at heq
obtain ⟨rfl, rfl⟩ := heq
exact .boolLitR b
| var x =>
simp only [eval] at heq
split at heq
next vv hL =>
simp at heq
obtain ⟨rfl, rfl⟩ := heq
exact .varR hL
next => simp at heq
| lam x body =>
simp [eval] at heq
obtain ⟨rfl, rfl⟩ := heq
exact .lamR x body
| app e1 e2 =>
simp only [eval] at heq
split at heq
next x body env' h1 heq1 =>
split at heq
next v2 h2 heq2 =>
exact .appR (ih _ _ _ _ _ heq1) (ih _ _ _ _ _ heq2) (ih _ _ _ _ _ heq)
next => simp at heq
all_goals simp at heq
| letIn x e1 e2 =>
simp only [eval] at heq
split at heq
next v1 h1 heq1 =>
exact .letInR (ih _ _ _ _ _ heq1) (ih _ _ _ _ _ heq)
next => simp at heq
| ifte ec e1 e2 =>
simp only [eval] at heq
split at heq
next h1 heq1 =>
exact .ifTR (ih _ _ _ _ _ heq1) (ih _ _ _ _ _ heq)
next h1 heq1 =>
exact .ifFR (ih _ _ _ _ _ heq1) (ih _ _ _ _ _ heq)
all_goals simp at heq
| binop op e1 e2 =>
simp only [eval] at heq
split at heq
next v1 h1 heq1 =>
split at heq
next v2 h2 heq2 =>
split at heq
next vv heqop =>
simp at heq
obtain ⟨rfl, rfl⟩ := heq
exact .binopR (ih _ _ _ _ _ heq1) (ih _ _ _ _ _ heq2) heqop
next => simp at heq
next => simp at heq
next => simp at heq
| refMk e =>
simp only [eval] at heq
split at heq
next vv h1 heq1 =>
simp at heq
obtain ⟨rfl, rfl⟩ := heq
exact .refMkR (ih _ _ _ _ _ heq1)
next => simp at heq
| deref e =>
simp only [eval] at heq
split at heq
next loc h1 heq1 =>
split at heq
next vv hget =>
simp at heq
obtain ⟨rfl, rfl⟩ := heq
exact .derefR (ih _ _ _ _ _ heq1) hget
next => simp at heq
all_goals simp at heq
| assign e1 e2 =>
simp only [eval] at heq
split at heq
next loc h1 heq1 =>
split at heq
next v2 h2 heq2 =>
split at heq
next hb =>
simp at heq
obtain ⟨rfl, rfl⟩ := heq
exact .assignR (ih _ _ _ _ _ heq1) (ih _ _ _ _ _ heq2) hb
next => simp at heq
next => simp at heq
all_goals simp at heq
| seq e1 e2 =>
simp only [eval] at heq
split at heq
next _ h1 heq1 =>
exact .seqR (ih _ _ _ _ _ heq1) (ih _ _ _ _ _ heq)
next => simp at heq
end GolangLean.Core