Library MetaCoq.Template.utils.MCUtils

From Coq Require Import Nat ZArith Bool.

Require Export MCPrelude
        MCReflect
        All_Forall
        MCArith
        MCCompare
        MCEquality
        MCList
        MCOption
        MCProd
        MCSquash
        MCRelations
        MCString
        ReflectEq
        bytestring
.

Tactic Notation "destruct" "?" :=
  let E := fresh "E" in
  match goal with
    [ |- context[match ?X with __ end]] ⇒ destruct X eqn:E
  | [ H : context[match ?X with __ end] |- _] ⇒ destruct X eqn:E
  end.

Tactic Notation "destruct" "?" "in" hyp(H) :=
  let e := fresh "E" in
  match type of H with context [match ?x with __ end] ⇒ destruct x eqn:e
  end.

Ltac cbnr := cbn; try reflexivity.

Ltac rdestruct H :=
  match type of H with
  | _ _destruct H as [H|H]; [rdestruct H|rdestruct H]
  | _ _let H' := fresh H in
            destruct H as [H|H']; [rdestruct H|rdestruct H']
  | prod _ _let H' := fresh H in
            destruct H as [H H']; rdestruct H; rdestruct H'
  | sigT _let H' := fresh H in
             destruct H as [H H']; rdestruct H; rdestruct H'
  | _idtac
  end.

Ltac rdest :=
  repeat match goal with
  | H : _ _ |- _destruct H
  | H : prod _ _ |- _destruct H
  | H : sigT _ |- _destruct H
  | |- _ _split
  | |- prod _ _split
  | |- sigT _eexists
  end.

Tactic Notation "toProp" ident(H) :=
  match type of H with
  | is_true (_ <? _)%natapply PeanoNat.Nat.ltb_lt in H
  | is_true (_ <=? _)%natapply PeanoNat.Nat.leb_le in H
  | is_true (_ =? _)%natapply PeanoNat.Nat.eqb_eq in H
  | (_ <? _)%nat = trueapply PeanoNat.Nat.ltb_lt in H
  | (_ <=? _)%nat = trueapply PeanoNat.Nat.leb_le in H
  | (_ =? _)%nat = trueapply PeanoNat.Nat.eqb_eq in H
  | (_ <? _)%nat = falseapply PeanoNat.Nat.ltb_ge in H
  | (_ <=? _)%nat = falseapply PeanoNat.Nat.leb_gt in H
  | (_ =? _)%nat = falseapply PeanoNat.Nat.eqb_neq in H

  | is_true (_ <? _)%Zapply Z.ltb_lt in H
  | is_true (_ <=? _)%Zapply Z.leb_le in H
  | is_true (_ =? _)%Zapply Z.eqb_eq in H
  | (_ <? _)%Z = trueapply Z.ltb_lt in H
  | (_ <=? _)%Z = trueapply Z.leb_le in H
  | (_ =? _)%Z = trueapply Z.eqb_eq in H
  | (_ <? _)%Z = falseapply Z.ltb_ge in H
  | (_ <=? _)%Z = falseapply Z.leb_gt in H
  | (_ =? _)%Z = falseapply Z.eqb_neq in H
     
  | is_true (_ && _) ⇒ apply andb_true_iff in H
  | (_ && _) = trueapply andb_true_iff in H
  | (_ && _) = falseapply andb_false_iff in H
     
  | is_true (_ || _) ⇒ apply orb_true_iff in H
  | (_ || _) = trueapply orb_true_iff in H
  | (_ || _) = falseapply orb_false_iff in H
  end.

Tactic Notation "toProp" :=
  match goal with
  | |- is_true (_ <? _)%natapply PeanoNat.Nat.ltb_lt
  | |- is_true (_ <=? _)%natapply PeanoNat.Nat.leb_le
  | |- is_true (_ =? _)%natapply PeanoNat.Nat.eqb_eq
  | |- (_ <? _)%nat = trueapply PeanoNat.Nat.ltb_lt
  | |- (_ <=? _)%nat = trueapply PeanoNat.Nat.leb_le
  | |- (_ =? _)%nat = trueapply PeanoNat.Nat.eqb_eq
  | |- ( _ <? _)%nat = falseapply PeanoNat.Nat.ltb_ge
  | |- (_ <=? _)%nat = falseapply PeanoNat.Nat.leb_gt
  | |- (_ =? _)%nat = falseapply PeanoNat.Nat.eqb_neq

  | |- is_true (_ <? _)%Zapply Z.ltb_lt
  | |- is_true (_ <=? _)%Zapply Z.leb_le
  | |- is_true (_ =? _)%Zapply Z.eqb_eq
  | |- (_ <? _)%Z = trueapply Z.ltb_lt
  | |- (_ <=? _)%Z = trueapply Z.leb_le
  | |- (_ =? _)%Z = trueapply Z.eqb_eq
  | |- (_ <? _)%Z = falseapply Z.ltb_ge
  | |- (_ <=? _)%Z = falseapply Z.leb_gt
  | |- (_ =? _)%Z = falseapply Z.eqb_neq

  | |- is_true (_ && _) ⇒ apply andb_true_iff; split
  | |- (_ && _) = trueapply andb_true_iff; split

  | |- is_true (_ || _) ⇒ apply orb_true_iff
  | |- (_ || _) = trueapply orb_true_iff

  | H : _ |- _toProp H
  end.

Tactic Notation "toProp" ident(H) "as" simple_intropattern(X) :=
   match type of H with
   | is_true (_ && _) ⇒ apply andb_true_iff in H; destruct H as X
   | (_ && _) = trueapply andb_true_iff in H; destruct H as X
   | (_ && _) = falseapply andb_false_iff in H; destruct H as X
      
   | is_true (_ || _) ⇒ apply orb_true_iff in H; destruct H as X
   | (_ || _) = trueapply orb_true_iff in H; destruct H as X
   | (_ || _) = falseapply orb_false_iff in H; destruct H as X
   end.

Tactic Notation "toProp" "as" simple_intropattern(X) :=
  match goal with
  | H : _ |- _toProp H as X
  end.

Ltac rtoProp :=
  repeat match goal with
  | H : is_true (_ && _) |- _apply andb_and in H; destruct H
  | |- context [is_true (_ && _)] ⇒ rewrite andb_and
  end.

Class Fuel := fuel : nat.

Such a useful tactic it should be part of the stdlib.
Ltac forward_gen H tac :=
  match type of H with
  | ?X _let H' := fresh in assert (H':X) ; [tac|specialize (H H'); clear H']
  end.

Ltac inv H := inversion_clear H.

Tactic Notation "forward" constr(H) := forward_gen H ltac:(idtac).
Tactic Notation "forward" constr(H) "by" tactic(tac) := forward_gen H tac.

#[global]
Hint Resolve Peano_dec.eq_nat_dec : eq_dec.

Ltac invs H := inversion H; subst; clear H.

Ltac generalize_eq x t :=
  set (x := t) in *; cut (x = t); [|reflexivity]; clearbody x.

Lemma iff_forall {A} B C (H : x : A, B x C x)
  : ( x, B x) ( x, C x).
  firstorder.
Defined.

Lemma iff_ex {A} B C (H : x : A, B x C x)
  : (ex B) (ex C).
  firstorder.
Defined.

Lemma if_true_false (b : bool) : (if b then true else false) = b.
  destruct b; reflexivity.
Qed.

Lemma iff_is_true_eq_bool (b b' : bool) :
  (b b') b = b'.
Proof.
  destruct b, b'; cbnr; intros [H1 H2];
    try specialize (H1 eq_refl); try specialize (H2 eq_refl);
      discriminate.
Qed.

Lemma uip_bool (b1 b2 : bool) (p q : b1 = b2) : p = q.
Proof.
  destruct q. apply Eqdep_dec.UIP_refl_bool.
Qed.

Axiom todo : string {A}, A.
Ltac todo s := exact (todo s).

From Coq Require Import Extraction.
Extract Constant todo ⇒ "fun s -> failwith (Caml_bytestring.caml_string_of_bytestring s)".