import tools.mini_crush /- This corresponds to Chapter 2 of CPDT, Some Quick Examples -/ open list inductive binop : Type | Plus | Times open binop inductive exp : Type | Const : nat → exp | Binop : binop → exp → exp → exp open exp def binop_denote : binop → nat → nat → nat | Plus := add | Times := mul def exp_denote : exp → nat | (Const n) := n | (Binop b e1 e2) := (binop_denote b) (exp_denote e1) (exp_denote e2) inductive instr : Type | iConst : ℕ → instr | iBinop : binop → instr open instr @[reducible] def prog := list instr def stack := list nat def instr_denote (i : instr) (s : stack) : option stack := match i with | (iConst n) := some (n :: s) | (iBinop b) := match s with | (arg1 :: arg2 :: s') := some ((binop_denote b) arg1 arg2 :: s') | _ := none end end def prog_denote : prog → stack → option stack | nil s := some s | (i :: p') s := match instr_denote i s with | none := none | (some s') := prog_denote p' s' end def compile : exp → prog | (Const n) := iConst n :: nil | (Binop b e1 e2) := compile e2 ++ compile e1 ++ iBinop b :: nil /- This example needs a few facts from the list library. -/ @[simp] lemma compile_correct' : ∀ e p s, prog_denote (compile e ++ p) s = prog_denote p (exp_denote e :: s) := by mini_crush @[simp] lemma compile_correct : ∀ e, prog_denote (compile e) nil = some (exp_denote e :: nil) := by mini_crush inductive type : Type | Nat | Bool open type inductive tbinop : type → type → type → Type | TPlus : tbinop Nat Nat Nat | TTimes : tbinop Nat Nat Nat | TEq : ∀ t, tbinop t t Bool | TLt : tbinop Nat Nat Bool open tbinop inductive texp : type → Type | TNConst : nat → texp Nat | TBConst : bool → texp Bool | TBinop : ∀ {t1 t2 t}, tbinop t1 t2 t → texp t1 → texp t2 → texp t open texp def type_denote : type → Type | Nat := nat | Bool := bool /- To simulate CPDT we need the next three operations. -/ def beq_nat (m n : ℕ) : bool := if m = n then tt else ff def eqb (b₁ b₂ : bool) : bool := if b₁ = b₂ then tt else ff def leb (m n : ℕ) : bool := if m < n then tt else ff def tbinop_denote : Π {arg1 arg2 res : type}, tbinop arg1 arg2 res → type_denote arg1 → type_denote arg2 → type_denote res | ._ ._ ._ TPlus := (add : ℕ → ℕ → ℕ) | ._ ._ ._ TTimes := (mul : ℕ → ℕ → ℕ) | ._ ._ ._ (TEq Nat) := beq_nat | ._ ._ ._ (TEq Bool) := eqb | ._ ._ ._ TLt := leb def texp_denote : Π {t : type}, texp t → type_denote t | ._ (TNConst n) := n | ._ (TBConst b) := b | ._ (@TBinop _ _ _ b e1 e2) := (tbinop_denote b) (texp_denote e1) (texp_denote e2) @[reducible] def tstack := list type inductive tinstr : tstack → tstack → Type | TiNConst : Π s, nat → tinstr s (Nat :: s) | TiBConst : Π s, bool → tinstr s (Bool :: s) | TiBinop : Π {arg1 arg2 res s}, tbinop arg1 arg2 res → tinstr (arg1 :: arg2 :: s) (res :: s) open tinstr inductive tprog : tstack → tstack → Type | TNil : Π {s}, tprog s s | TCons : Π {s1 s2 s3}, tinstr s1 s2 → tprog s2 s3 → tprog s1 s3 open tprog def vstack : tstack → Type | nil := unit | (t :: ts') := type_denote t × vstack ts' def tinstr_denote : Π {ts ts' : tstack}, tinstr ts ts' → vstack ts → vstack ts' | ._ ._ (TiNConst ts n) := λ s, (n, s) | ._ ._ (TiBConst ts b) := λ s, (b, s) | ._ ._ (@TiBinop arg1 arg2 res s b) := λ ⟨arg1, ⟨arg2, s'⟩⟩, ((tbinop_denote b) arg1 arg2, s') def tprog_denote : Π {ts ts' : tstack}, tprog ts ts' → vstack ts → vstack ts' | ._ ._ (@TNil _) := λ s, s | ._ ._ (@TCons _ _ _ i p') := λ s, tprog_denote p' (tinstr_denote i s) def tconcat : Π {ts ts' ts'' : tstack}, tprog ts ts' → tprog ts' ts'' → tprog ts ts'' | ._ ._ ts'' (@TNil _) p' := p' | ._ ._ ts'' (@TCons _ _ _ i p1) p' := TCons i (tconcat p1 p') def tcompile : Π {t : type}, texp t → Π ts : tstack, tprog ts (t :: ts) | ._ (TNConst n) ts := TCons (TiNConst _ n) TNil | ._ (TBConst b) ts := TCons (TiBConst _ b) TNil | ._ (@TBinop _ _ _ b e1 e2) ts := tconcat (tcompile e2 _) (tconcat (tcompile e1 _) (TCons (TiBinop b) TNil)) @[simp] lemma tconcat_correct : ∀ ts ts' ts'' (p : tprog ts ts') (p' : tprog ts' ts'') (s : vstack ts), tprog_denote (tconcat p p') s = tprog_denote p' (tprog_denote p s) := by mini_crush @[simp] lemma tcompile_correct' : ∀ t (e : texp t) ts (s : vstack ts), tprog_denote (tcompile e ts) s = (texp_denote e, s) := by mini_crush lemma tcompile_correct : ∀ t (e : texp t), tprog_denote (tcompile e nil) () = (texp_denote e, ()) := by mini_crush