Module K <: KNOT__HERED_PROP_OTH := Knot_HeredPropOth(KnotInput).
Definition prog := K.knot.
Definition world := (prog * store)%type.
Definition assert := pred world.
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 : prog -> prog -> store -> stack -> store -> stack -> Prop :=
| step_assert : forall p r i stk (P:assert),
P (p,r) ->
(*----------------------------------------------------*)
step p p r ((instr_assert P ;; i) :: stk) r (i :: stk)
| step_getlabel: forall p r l v i stk,
(*----------------------------------------------------*)
step 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 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 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 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 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 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 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 p p' r ((instr_call v ;; i) :: stk) r ((i' ;; instr_assert FF) :: i :: stk)
| step_return : forall p r stk i,
(*----------------------------------------------------*)
step p p r ((instr_return ;; i) :: stk) r stk.
(* Safety property *)
Inductive stepstar : prog -> prog -> store -> stack -> store -> stack ->  Prop :=
| stepstar_O: forall s i p, stepstar p p s i s i
| stepstar_S: forall p p' p'' s i s' i' s'' i'',
step p p' s i s' i' -> stepstar p' p'' s' i' s'' i'' -> stepstar p p'' s i s'' i''.
Inductive step_or_halt : prog -> store -> stack -> Prop :=
| step_or_halt_step: forall p p' r i r' i',
step p p' r i r' i' -> step_or_halt p r i
| step_or_halt_halt: forall p r,
step_or_halt p r nil.
Definition safe (p: prog) (s: store) (k: stack) :=
forall p' s' k', stepstar p p' s k s' k' -> step_or_halt p' s' k'.
Definition safe_prog (p: program assert) (l:label) :=
exists i, p#l = Some i /\
forall n s, safe (K.squash (n,p)) s (i::nil).
Definition eventually_halts (p:prog) (r:store) (s:stack) : Prop :=
exists p', exists r', stepstar p p' r s r' nil.
Definition eventually_halts_n (n : nat) (p:prog) (r:store) (s:stack) : Prop :=
exists p', exists r', (level p - level p' <= n) /\ stepstar p p' r s r' nil.
(*****)
(* Other Stuff *)
Inductive stepN : nat -> prog -> prog -> store -> stack -> store -> stack ->  Prop :=
| stepN_O: forall p s i, stepN O p p s i s i
| stepN_S: forall n s i p p' p'' s' i' s'' i'',
step p p' s i s' i' -> stepN n p' p'' s' i' s'' i'' -> stepN (S n) p p'' s i s'' i''.

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