crosslang/octive-lean/OctiveLean/Core/Eval.lean
Maximus Gorog 6592cd058d Add 'octive-lean/' from commit '4b6fcec565a170d7029d4ccba21be2ecd0512d13'
git-subtree-dir: octive-lean
git-subtree-mainline: fd3d42ae33
git-subtree-split: 4b6fcec565
2026-05-12 02:59:14 -06:00

173 lines
5.9 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 OctiveLean.Core.Semantics
namespace OctiveLean.Core
/-! # Executable evaluator and soundness for TOC.
Fuel-bounded recursive evaluator
`eval : Nat → Env → Term → Option (Value × Env)`
together with
`eval_sound : eval n env e = some (v, env') → BigStep env e v env'`.
Function-call semantics: the body's post-env is *discarded* — only the
arg-evaluation env propagates outward. This matches Octave/MATLAB scoping
where mutations inside a function do not leak.
`whileT` recursion uses one fuel step per iteration. A run that uses `n`
fuel covers up to `n` iterations of the loop. -/
def eval : Nat → Env → Term → Option (Value × Env)
| 0, _, _ => none
| _ + 1, env, .unitT => some (.vUnit, env)
| _ + 1, env, .intLit k => some (.vInt k, env)
| _ + 1, env, .boolLit b => some (.vBool b, env)
| _ + 1, env, .var x =>
match env.lookup x with
| some v => some (v, env)
| none => none
| _ + 1, env, .lam x body => some (.vClos x body env, env)
| n + 1, env, .app e1 e2 =>
match eval n env e1 with
| some (.vClos x body env_clos, env1) =>
match eval n env1 e2 with
| some (v_arg, env2) =>
match eval n (env_clos.extend x v_arg) body with
| some (v, _) => some (v, env2)
| none => none
| none => none
| _ => none
| n + 1, env, .letIn x e1 e2 =>
match eval n env e1 with
| some (v1, env1) =>
match eval n (env1.extend x v1) e2 with
| some (v2, _) => some (v2, env1) -- scope-restore: discard body's post-env
| none => none
| none => none
| n + 1, env, .ifte ec e1 e2 =>
match eval n env ec with
| some (.vBool true, env1) => eval n env1 e1
| some (.vBool false, env1) => eval n env1 e2
| _ => none
| n + 1, env, .binop op e1 e2 =>
match eval n env e1 with
| some (v1, env1) =>
match eval n env1 e2 with
| some (v2, env2) =>
match op.apply v1 v2 with
| some v => some (v, env2)
| none => none
| none => none
| none => none
| n + 1, env, .seq e1 e2 =>
match eval n env e1 with
| some (_, env1) => eval n env1 e2
| none => none
| n + 1, env, .assign x e =>
match eval n env e with
| some (v, env1) => some (.vUnit, env1.extend x v)
| none => none
| n + 1, env, .whileT c b =>
match eval n env c with
| some (.vBool true, env1) =>
match eval n env1 b with
| some (_, env2) => eval n env2 (.whileT c b)
| none => none
| some (.vBool false, env1) => some (.vUnit, env1)
| _ => none
theorem eval_sound :
∀ (n : Nat) (env : Env) (e : Term) (v : Value) (env' : Env),
eval n env e = some (v, env') → BigStep env e v env' := by
intro n
induction n with
| zero => intro env e v env' heq; simp [eval] at heq
| succ n ih =>
intro env e v env' 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_clos env1 heq1 =>
split at heq
next v_arg env2 heq2 =>
split at heq
next v_body _ heqb =>
simp at heq; obtain ⟨rfl, rfl⟩ := heq
exact .appR (ih _ _ _ _ heq1) (ih _ _ _ _ heq2) (ih _ _ _ _ heqb)
next => simp at heq
next => simp at heq
all_goals simp at heq
| letIn x e1 e2 =>
simp only [eval] at heq
split at heq
next v1 env1 heq1 =>
split at heq
next v2 _ heq2 =>
simp at heq; obtain ⟨rfl, rfl⟩ := heq
exact .letInR (ih _ _ _ _ heq1) (ih _ _ _ _ heq2)
next => simp at heq
next => simp at heq
| ifte ec e1 e2 =>
simp only [eval] at heq
split at heq
next env1 heq1 => exact .ifTR (ih _ _ _ _ heq1) (ih _ _ _ _ heq)
next env1 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 env1 heq1 =>
split at heq
next v2 env2 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
| seq e1 e2 =>
simp only [eval] at heq
split at heq
next _ env1 heq1 =>
exact .seqR (ih _ _ _ _ heq1) (ih _ _ _ _ heq)
next => simp at heq
| assign x e =>
simp only [eval] at heq
split at heq
next vv env1 heq1 =>
simp at heq; obtain ⟨rfl, rfl⟩ := heq
exact .assignR (ih _ _ _ _ heq1)
next => simp at heq
| whileT c b =>
simp only [eval] at heq
split at heq
next env1 heq1 =>
split at heq
next _ env2 heq2 =>
have hbs_rec := ih _ _ _ _ heq
have hv_unit : v = .vUnit := by cases hbs_rec <;> rfl
subst hv_unit
exact .whileTR (ih _ _ _ _ heq1) (ih _ _ _ _ heq2) hbs_rec
next => simp at heq
next env1 heq1 =>
simp at heq; obtain ⟨rfl, rfl⟩ := heq
exact .whileFR (ih _ _ _ _ heq1)
all_goals simp at heq
end OctiveLean.Core