(* Syntax *)
Definition var := nat.
Definition val := nat.
Inductive expr :=
| Evar: var->expr
| Econst: val ->expr
| Eop: (val->val->val) -> expr -> expr -> expr.
Inductive command :=
| Cskip: command
| Cassign: var -> expr -> command
| Cload: var -> expr -> command
| Cstore: expr -> expr -> command
| Cseq : command -> command -> command
| Cif: expr -> command  -> command -> command
| Cwhile: expr  -> command -> command.
(* Semantics -- stacks, memories, and states *)
Definition stack := var -> option val.
Definition mem := val -> option val.
Definition rho0 : stack := fun _ => None.
Definition m0 : mem := fun _ => None.
Class EqDec (A : Type) : Type := eq_dec : forall a a' : A, {a = a'} + {a <> a'}.
Instance EqDec_nat: EqDec nat.
Instance EqDec_var: EqDec var := _.
Instance EqDec_val: EqDec val := _.
Definition upd{A B}{EA: EqDec A} (f: A -> option B) x y z :=
if eq_dec x z then y else f z.
Inductive state := State: forall (rho: stack) (m: mem) (c: command), state.
Definition stack_of (s: state) := match s with State rho _ _ => rho end.
Definition mem_of (s: state) := match s with State _ m _ => m end.
Definition cmd_of (s: state) := match s with State _ _ c => c end.
(* Operational semantics *)
Inductive eval: expr -> val -> stack -> Prop :=
| Eval_var: forall rho e v, rho e = Some v -> eval (Evar e) v rho
| Eval_const: forall rho v, eval (Econst v) v rho
| Eval_op: forall rho f e1 e2 v1 v2, eval e1 v1 rho -> eval e2 v2 rho ->
eval (Eop f e1 e2) (f v1 v2) rho.
Inductive step: relation state :=
| Step_skip: forall rho m c, step (State rho m (Cseq Cskip c)) (State rho m c)
| Step_assign: forall rho m x e c v, eval e v rho ->
step (State rho m (Cseq (Cassign x e) c)) (State (upd rho x (Some v)) m c)
| Step_load:  forall rho m x e c v v', eval e v rho -> m v = Some v' ->
step (State rho m (Cseq (Cload x e) c)) (State (upd rho x (Some v')) m c)
| Step_store: forall rho m e1 e2 c v1 v2,
eval e1 v1 rho -> eval e2 v2 rho ->
step (State rho m (Cseq (Cstore e1 e2) c)) (State rho (upd m v1 (Some v2)) c)
| Step_seq: forall rho m c1 c2 c,
step (State rho m (Cseq (Cseq c1 c2) c)) (State rho m (Cseq c1 (Cseq c2 c)))
| Step_iftrue: forall rho m e c1 c2 c v, eval e v  rho-> v<>0 ->
step (State rho m (Cseq (Cif e c1 c2) c)) (State rho m (Cseq c1 c))
| Step_iffalse: forall rho m e c1 c2 c, eval e 0 rho ->
step (State rho m (Cseq (Cif e c1 c2) c)) (State rho m (Cseq c2 c))
| Step_whiletrue: forall rho m e c1 c v, eval e v rho -> v<>0 ->
step (State rho m (Cseq (Cwhile e c1) c)) (State rho m (Cseq c1 (Cseq (Cwhile e c1) c)))
| Step_whilefalse: forall rho m e c1 c, eval e 0 rho ->
step (State rho m (Cseq (Cwhile e c1) c)) (State rho m c).
Definition stepstar := clos_refl_trans_1n _ step.
Definition a : var := 0.
Definition run (c: command) (v: val) : Prop :=
exists rho, exists m,
stepstar (State rho0 m0 (Cseq c Cskip)) (State rho m Cskip) /\ rho a = Some v.
(* Hoare Logic *)
Definition h_assert := stack -> Prop.
Inductive immed_safe: state -> Prop :=
| IS_stop: forall rho m, immed_safe (State rho m Cskip)
| IS_step: forall s s', step s s' -> immed_safe s.
Definition safe (s: state) : Prop :=
forall s', stepstar s s' -> immed_safe s'.
Definition guard (P: h_assert) (c: command) :=
forall rho,   P rho -> safe (State rho m0 c).
Definition Hoare (P: h_assert) (c: command) (Q: h_assert) : Prop :=
forall k, guard Q k -> guard P (Cseq c k).
Definition subst (x:var) (v: option val) (P: h_assert) : h_assert :=
fun rho => P (upd rho x v).

Lemma upd_same: forall A B {EA: EqDec A} rho (x: A) (v: option B), upd rho x v x = v.