Module K <: KNOT__HERED_PROP_OTH_REL := Knot_HeredPropOthRel(KnotInput).
Definition prog := K.knot.
Definition world := (prog * (store * terminationMeasure))%type.
Definition instruction := instr assert.
Definition stack := list instruction.
Infix ";;" := instr_seq (at level 60, right associativity).
Definition prog_lookup (p:prog) (l:label) : option instruction :=
get _ (snd (unsquash p)) l.
(** Execution of machine code **)
Inductive step (t:terminationMeasure) : prog -> prog -> store -> stack -> store -> stack -> Prop :=
| step_assert : forall p r i stk (P:assert),
proj1_sig P (p,(r,t)) ->
(*----------------------------------------------------*)
step t p p r ((instr_assert P ;; i) :: stk) r (i :: stk)
| step_getlabel: forall p r l v i stk,
(*----------------------------------------------------*)
step t p p r ((instr_getlabel l v ;; i) :: stk) (r#v <- (value_label l)) (i :: stk)
| step_fetch_field_0: forall p r v1 v2 i a0 a1 stk,
r#v1 = Some (value_cons a0 a1) ->
(*----------------------------------------------------*)
step t p p r ((instr_fetch_field v1 0 v2 ;; i) :: stk) (r#v2 <- a0) (i :: stk)
| step_fetch_field_1: forall p r v1 v2 i a0 a1 stk,
r#v1 = Some (value_cons a0 a1) ->
(*----------------------------------------------------*)
step t p p r ((instr_fetch_field v1 1 v2 ;; i) :: stk) (r#v2 <- a1) (i :: stk)
| step_cons: forall p r v1 v2 v3 i a1 a2 stk,
r#v1 = Some a1 ->
r#v2 = Some a2 ->
(*----------------------------------------------------*)
step t p p r ((instr_cons v1 v2 v3 ;; i) :: stk) (r#v3 <- (value_cons a1 a2)) (i :: stk)
| step_seq: forall p r i1 i2 i3 stk,
(*----------------------------------------------------*)
step t p p r (((i1 ;; i2) ;; i3) :: stk) r ((i1 ;; i2 ;; i3) :: stk)
| step_if_nil1 : forall p r v i1 i2 i stk,
r#v = Some (value_label (L 0)) ->
(*----------------------------------------------------*)
step t p p r ((instr_if_nil v i1 i2 ;; i) :: stk) r ((i1 ;; i) :: stk)
| step_if_nil2 : forall p r v i1 i2 i a1 a2 stk,
r#v = Some (value_cons a1 a2) ->
(*----------------------------------------------------*)
step t p p r ((instr_if_nil v i1 i2 ;; i) :: stk) r ((i2 ;; i) :: stk)
| step_call : forall p p' r v l i i' stk,
r#v = Some (value_label l) ->
prog_lookup p l = Some i' ->
age p p' ->
(*----------------------------------------------------*)
step t p p' r ((instr_call v ;; i) :: stk) r ((i' ;; instr_nil _) :: i :: stk)
| step_call_apocalypse : forall p r v i stk,
level p = 0 ->
(*----------------------------------------------------*)
step t p p r ((instr_call v ;; i) :: stk) r ((instr_call v ;; i) :: stk)
| step_return : forall p r stk i,
(*----------------------------------------------------*)
step t p p r ((instr_return ;; i) :: stk) r stk.
(* Safety property *)
Inductive stepstar (t:terminationMeasure) : prog -> prog -> store -> stack -> store -> stack ->  Prop :=
| stepstar_O: forall s i p, stepstar t p p s i s i
| stepstar_S: forall p p' p'' s i s' i' s'' i'',
step t p p' s i s' i' -> stepstar t p' p'' s' i' s'' i'' -> stepstar t p p'' s i s'' i''.
Inductive step_or_halt (t:terminationMeasure) : prog -> store -> stack -> Prop :=
| step_or_halt_step: forall p p' r i r' i',
step t p p' r i r' i' -> step_or_halt t p r i
| step_or_halt_halt: forall p r,
step_or_halt t p r nil.
Definition safe (t:terminationMeasure) (p: prog) (s: store) (k: stack) :=
forall p' s' k', stepstar t p p' s k s' k' -> step_or_halt t p' s' k'.
Definition safe_prog (p: program assert) (l:label) :=
exists t, exists i,
p#l = Some i /\
forall n s, safe t (K.squash (n,p)) s (i::nil).
Definition eventually_halts (t:terminationMeasure) (p:prog) (r:store) (s:stack) : Prop :=
exists p', exists r', stepstar t p p' r s r' nil.
(*****)
(* Other Stuff *)
Inductive stepN : nat -> terminationMeasure -> prog -> prog -> store -> stack -> store -> stack ->  Prop :=
| stepN_O: forall t p s i, stepN O t p p s i s i
| stepN_S: forall n t s i p p' p'' s' i' s'' i'',
step t p p' s i s' i' -> stepN n t p' p'' s' i' s'' i'' -> stepN (S n) t p p'' s i s'' i''.

Lemma step_deterministic : forall t p p1 p2 s i s1 s2 i1 i2,
step t p p1 s i s1 i1 ->
step t p p2 s i s2 i2 ->
s1 = s2 /\ i1 = i2 /\ p1 = p2.