git-subtree-dir: octive-lean git-subtree-mainline:fd3d42ae33git-subtree-split:4b6fcec565
173 lines
5.9 KiB
Text
173 lines
5.9 KiB
Text
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
|