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