(*** Machine specification ***)

(** Abstract syntax of machine code **)

Definition var: Set := positive.Definition var_eq: forall (v1 v2: var), {v1=v2} + {v1<>v2} := positive_eq_dec.Definition V (n: nat) : var := P_of_succ_nat n.Definition label: Set := positive.Definition label_eq: forall (l1 l2: label), {l1=l2} + {l1<>l2} := positive_eq_dec.Definition L (n: nat) : label := P_of_succ_nat n.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Inductive instr : Type :=
  | instr_assert : X -> instr

  | instr_getlabel: label -> var -> instr
  | instr_fetch_field: var -> nat -> var -> instr
  | instr_cons: var -> var -> var -> instr

  | instr_seq: instr -> instr -> instr
  | instr_if_nil : var -> instr -> instr -> instr
  | instr_call: var -> instr
  | instr_return: instr

  | instr_nil : instr.Fixpoint fmap_instr {A B} (f:A->B) (x:instr A) : instr B :=
  match x with
  | instr_assert a => instr_assert (f a)
  | instr_getlabel l v => instr_getlabel l v
  | instr_fetch_field v1 n v2 => instr_fetch_field v1 n v2
  | instr_cons v1 v2 v3 => instr_cons v1 v2 v3
  | instr_seq i1 i2 => instr_seq (fmap_instr f i1) (fmap_instr f i2)
  | instr_if_nil v i1 i2 => instr_if_nil v (fmap_instr f i1) (fmap_instr f i2)
  | instr_call v => instr_call v
  | instr_return => instr_return
  | instr_nil => instr_nil _
  end.(** Run-time values and environments **)

Inductive value: Set :=
  | value_label: label -> value
  | value_cons: value -> value -> value.(** Run-time values and environments **)

Inductive value: Set :=
  | value_label: label -> value
  | value_cons: value -> value -> value.(** Run-time values and environments **)

Inductive value: Set :=
  | value_label: label -> value
  | value_cons: value -> value -> value.Definition store := map value.Definition store_empty : store := empty value.Definition program X := map (instr X).Definition terminationMeasure : Type :=
  label -> store -> option nat.Definition termMeasure_incr (s1 s2:terminationMeasure) :=
  forall l r, s1 l r = None \/ s1 l r = s2 l r.Definition F := program.Definition fmap A B (f:A->B) := map_fmap _ _ (fmap_instr f).

Lemma fmap_comp : forall A B C (f:B -> C) (g:A -> B), fmap f oo fmap g = fmap (f oo g).