Lvc.IL.Annotation

Require Import List.
Require Import Util Relations Get Drop Var Val Exp Env Map CSet AutoIndTac MoreList IL DecSolve.
Require Import Libs.PartialOrder.

Set Implicit Arguments.

Inductive ann (A:Type) : Type :=
| ann0 (a:A) : ann A
| ann1 (a:A) (sa:ann A) : ann A
| ann2 (a:A) (sa:ann A) (ta:ann A) : ann A.

Definition getAnn {A} (a:ann A) : A :=
  match a with
    | ann0 aa
    | ann1 a _a
    | ann2 a _ _a
  end.

Fixpoint setAnn A (s:stmt) (a:A) : ann A :=
  match s with
   | stmtLet x e ann1 a (setAnn a)
   | stmtIf x s1 s2ann2 a (setAnn s1 a) (setAnn s2 a)
   | stmtApp l Yann0 a
   | stmtReturn xann0 a
   | stmtExtern x f Y sann1 a (setAnn s a)
   | stmtFun Z s1 s2ann2 a (setAnn s1 a) (setAnn s2 a)
   end.

Fixpoint setTopAnn A (s:ann A) (a:A) : ann A :=
  match s with
   | ann0 _ann0 a
   | ann1 _ ann1 a
   | ann2 _ s1 s2ann2 a s1 s2
   end.

Lemma getAnn_setTopAnn A (an:ann A) a
 : getAnn (setTopAnn an a) = a.
Proof.
  destruct an; eauto.
Qed.

Fixpoint mapAnn X Y (f:XY) (a:ann X) : ann Y :=
  match a with
    | ann1 a anann1 (f a) (mapAnn f an)
    | ann2 a an1 an2ann2 (f a) (mapAnn f an1) (mapAnn f an2)
    | ann0 aann0 (f a)
  end.

Lemma getAnn_mapAnn A (a:ann A) (f:A)
  : getAnn (mapAnn f a) = f (getAnn a).
Proof.
  general induction a; simpl; eauto.
Qed.

Inductive annotation {A:Type} : stmtann AProp :=
| antExp x e s a sa
  : annotation s sa
    → annotation (stmtLet x e s) (ann1 a sa)
| antIf x s t a sa ta
  : annotation s sa
    → annotation t ta
    → annotation (stmtIf x s t) (ann2 a sa ta)
| antGoto l Y a
  : annotation (stmtApp l Y) (ann0 a)
| antReturn x a
  : annotation (stmtReturn x) (ann0 a)
| antExtern x f Y s a sa
  : annotation s sa
    → annotation (stmtExtern x f Y s) (ann1 a sa)
| antLet Z s t a sa ta
  : annotation s sa
    → annotation t ta
    → annotation (stmtFun Z s t) (ann2 a sa ta).

Instance annotation_dec_inst {A} {s} {a} : Computable (@annotation A s a).
Proof.
  revert a. induction s; destruct a; try destruct IHs;
  try (now left; econstructor; eauto);
  try (now right; inversion 1; eauto).
  destruct (IHs a0);
    try (now left; econstructor; eauto);
    try (now right; inversion 1; eauto).
  destruct (IHs1 a2), (IHs2 a3);
    try (now left; econstructor; eauto);
    try (now right; inversion 1; eauto).
  destruct (IHs a0);
    try (now left; econstructor; eauto);
    try (now right; inversion 1; eauto).
  destruct (IHs1 a2), (IHs2 a3);
    try (now left; econstructor; eauto);
    try (now right; inversion 1; eauto).
Defined.

Inductive ann_R {A B} (R:ABProp) : ann Aann BProp :=
  | annLt1 a b an bn
    : R a b
      → ann_R R an bn
      → ann_R R (ann1 a an) (ann1 b bn)
  | annLt2 a ans ant b bns bnt
    : R a b
      → ann_R R ans bns
      → ann_R R ant bnt
      → ann_R R (ann2 a ans ant) (ann2 b bns bnt)
  | annLt0 a b
      : R a b
      → ann_R R (ann0 a) (ann0 b).

Lemma ann_R_get A B (R: ABProp) a b
: ann_R R a b
  → R (getAnn a) (getAnn b).
Proof.
  intros. inv H; eauto.
Qed.

Instance ann_R_refl {A} {R} `{Reflexive A R} : Reflexive (ann_R R).
Proof.
  hnf in H.
  hnf; intros. general induction x; eauto using ann_R.
  - econstructor; eauto.
  - econstructor; eauto.
  - econstructor; eauto.
Qed.

Instance ann_R_sym {A} {R} `{Symmetric A R} : Symmetric (ann_R R).
Proof.
  hnf in H.
  hnf; intros. general induction H0; eauto using ann_R.
  - econstructor; eauto.
  - econstructor; eauto.
  - econstructor; eauto.
Qed.

Instance ann_R_trans A R `{Transitive A R} : Transitive (ann_R R).
Proof.
  hnf; intros ? ? ? B C.
  general induction B; inv C; econstructor; eauto.
Qed.

Instance ann_R_ann1_pe_morphism X `{OrderedType X}
: Proper (@pe X _ ==> ann_R (@pe X _) ==> ann_R (@pe X _)) (@ann1 _).
Proof.
  unfold Proper, respectful; intros.
  econstructor; eauto.
Qed.

Instance ordered_type_lt_dec A `{OrderedType A} (a b: A)
: Computable (_lt a b).
pose proof (_compare_spec a b).
destruct (_cmp a b).
right; inv H0. hnf; intros. eapply (lt_not_eq H2 H1).
left. inv H0; eauto.
right; inv H0. intro. eapply (lt_not_gt H1 H2).
Defined.

Instance ann_R_dec A B (R:ABProp)
         `{ a b, Computable (R a b)} (a:ann A) (b:ann B) :
  Computable (ann_R R a b).
Proof.
  revert a b.
  fix 1.
  destruct a; destruct b; try dec_solve.
  + decide (R a a0); dec_solve.
  + decide (R a a1); try dec_solve;
    edestruct ann_R_dec with (a:=a0) (b:=b); hnf in *;
    try eassumption; try dec_solve.
  + decide (R a1 a); try dec_solve.
    destruct (ann_R_dec a2 b1); try dec_solve.
    destruct (ann_R_dec a3 b2); try dec_solve.
Defined.

Instance PartialOrder_ann Dom `{PartialOrder Dom}
: PartialOrder (ann Dom) := {
  poLe := ann_R poLe;
  poLe_dec := @ann_R_dec _ _ poLe poLe_dec;
  poEq := ann_R poEq;
  poEq_dec := @ann_R_dec _ _ poEq poEq_dec
}.

Instance getAnn_ann_R_morphism A (R:AAProp)
: Proper (ann_R R ==> R) (getAnn).
Proof.
  unfold Proper, respectful; intros.
  inv H; simpl; eauto.
Qed.

Hint Extern 20 (ann_R _ ?a ?) ⇒ (is_evar a ; fail 1)
                                    || (has_evar a ; fail 1)
                                    || (is_evar ; fail 1)
                                    || (has_evar ; fail 1)
                                    || reflexivity.