Library Imp_LangTrick.ProofCompiler.ProofCompAuto


From Coq Require Import List Arith Psatz String.

From Imp_LangTrick Require Import Base StackLangTheorems LogicTranslationBase StackLanguage Imp_LangTrickLanguage LogicProp Imp_LangLogProp ImpVarMapTheorems ProofCompilerPostHelpers ReflectionMachinery.
Require Imp_LangTrick.Tactics.FunctionWellFormedReflection.

Local Open Scope list_scope.
Local Open Scope string_scope.
Local Open Scope nat_scope.

Fixpoint not_In {A: Type} (a: A) (l: list A) :=
  match l with
  | nil => True
  | b :: m => ((b <> a) /\ (not_In a m))
  end.

Inductive not_In_ind {A: Type} (a: A) : (list A) -> Prop :=
| not_In_nil : not_In_ind a nil
| not_In_cons :
  forall b m,
    b <> a ->
    not_In_ind a m ->
    not_In_ind a (b :: m).

Lemma not_In_implies_In_implies_False :
  forall (A: Type) (a: A) (l: list A),
    not_In a l ->
    ~ (In a l).
Proof.
  induction l; intros.
  - simpl in H. unfold not. intros. simpl in H0. assumption.
  - unfold not. intros. simpl in H0. simpl in H. destruct H. destruct H0.
     + contradiction.
     + eapply IHl in H1. contradiction.
Qed.

Lemma not_In_ind_implies_not_In :
  forall (A: Type) (a: A) (l: list A),
    not_In_ind a l ->
    not_In a l.
Proof.
  induction l; intros.
  - simpl. eapply I.
  - simpl. invs H. split.
    + eassumption.
    + eapply IHl in H3. eassumption.
Qed.


Fixpoint construct_not_In {A: Type} {Aeq_dec: forall x y: A, {x = y} + {x <> y}} (a: A) (l: list A) : option (not_In a l) :=
  match l as l' return (option (not_In a l')) with
  | nil => Some (I)
  | b :: m =>
      match (Aeq_dec b a) with
      | left P => None
      | right P =>
          match (@construct_not_In A Aeq_dec a m) with
          | Some P' =>
              Some (conj P P')
          | None => None
          end
      end
  end.

Fixpoint construct_nodup {A: Type} {Aeq_dec: forall x y: A, {x = y} + {x <> y}} (l: list A) : option (NoDup l) :=
  match l as l' return option (NoDup l') with
  | nil => Some (NoDup_nil A)
  | a :: rest =>
      match (@construct_not_In A Aeq_dec a rest) with
      | Some P_not_in =>
          match (@construct_nodup A Aeq_dec rest) with
          | Some P_nodup =>
              Some (@NoDup_cons A a rest (not_In_implies_In_implies_False A a rest P_not_in) P_nodup)
          | None => None
          end
      | None => None
      end
  end.


Fixpoint construct_In {A: Type} (Aeq_dec : forall x y: A, {x = y} + {x <> y}) (a: A) (l: list A) : option (In a l) :=
  match l as l' return (option (In a l')) with
  | nil => None
  | b :: m =>
      match (Aeq_dec b a) with
      | left P_b_eq_a =>
          Some (or_introl P_b_eq_a)
      | right _ =>
          match (construct_In Aeq_dec a m) with
          | Some P_in => Some (or_intror P_in)
          | None => None
          end
      end
  end.

Ltac finite_nodup_reflective :=
  match goal with
  | [ |- @NoDup string ?l ] =>
      exact (optionOut (@NoDup string l) (@construct_nodup string string_dec l))
  | [ |- @NoDup ident ?l ] =>
      exact (optionOut (@NoDup ident l) (@construct_nodup ident string_dec l))
  | [ |- @NoDup fun_Imp_Lang ?l ] =>
      exact (optionOut (@NoDup fun_Imp_Lang l)
                       (@construct_nodup fun_Imp_Lang
                                         FunctionWellFormedReflection.fun_Imp_Lang_dec
                                         l))
  end.

Ltac finite_not_in_reflective :=
  match goal with
  | [ |- ~ @In ?tipe ?l ] =>
      match tipe with
      | string =>
          exact (optionOut (~ @In string l)
                           (@construct_not_In string string_dec l))
      | ident =>
          exact (optionOut (~ @In ident l)
                           (@construct_not_In ident string_dec l))
      | fun_Imp_Lang =>
          exact (optionOut (~ @In fun_Imp_Lang l)
                           (@construct_not_In fun_Imp_Lang
                                              FunctionWellFormedReflection.fun_Imp_Lang_dec
                                              l))
      end
  end.

Ltac finite_not_in_slow :=
  match goal with
  | [ |- ~ In ?x nil ] =>
      intros NOT;
      invs NOT
  | [ |- ~ In ?x (cons ?y ?rest_list) ] =>
      intros NOT;
      invc NOT; finite_not_in_slow
  | [ H: ?a = ?b |- False ] =>
      try invc H
  | [ H: In ?x (cons ?y ?rest_list) |- _ ] =>
      invc H;
      finite_not_in_slow
  | [ H: In ?x nil |- _ ] =>
      invc H
  end.

Ltac finite_not_in :=
  finite_not_in_reflective || finite_not_in_slow.

Ltac finite_nodup_slow :=
  match goal with
  | [ |- NoDup (cons _ _) ] =>
      constructor; [ finite_not_in | try finite_nodup_slow ]
  | [ |- NoDup nil ] =>
      constructor
  end.

Ltac finite_nodup :=
  finite_nodup_reflective || finite_nodup_slow.

Lemma probably_not_true :
  forall (P Q: Prop),
    ~ P /\ ~ Q ->
    ~ (P \/ Q).
Proof.
  intros. destruct H.
  intros PorQ.
  destruct PorQ.
  - contradiction.
  - contradiction.
Qed.

Example nodup_three :
  NoDup (1 :: 2 :: 3 :: nil).
Proof.
  finite_nodup.
Qed.

Example nodup_ten :
  NoDup (1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: 8 :: 9 :: 10 :: nil).
Proof.
  finite_nodup.
Qed.

From Coq Require Import String.

Local Open Scope string_scope.

Example nodup_abc :
  NoDup ("a" :: "b" :: "c" :: nil).
Proof.
  finite_nodup.
Qed.

Ltac finite_in :=
  match goal with
  | [ |- @In string ?x ?l ] =>
      exact (optionOut (@In string x l) (construct_In string_dec x l))
  | [ |- @In ident ?x ?l ] =>
      exact (optionOut (@In ident x l) (construct_In string_dec x l))
  | [ |- In ?x (cons ?x _) ] =>
      eapply in_eq
  | [ |- In ?x (cons _ _) ] =>
      eapply in_cons; finite_in
  | [ |- In _ nil ] =>
      idtac "got to nil, failing";
      fail
  | [ |- In _ ?listexpr ] =>
      let listExprId := fresh "listexpr" in
      let listExprEq := fresh "Heq" in
      remember (listexpr) as listExprId eqn:listExprEq;
      simpl in listExprEq;
      subst listExprId;
      finite_in
  end.

Example a_in_abc :
  In "a" ("a" :: "b" :: "c" :: nil).
Proof.
  finite_in.
Qed.

Example c_in_abc :
  In "c" ("a" :: "b" :: "c" :: nil).
Proof.
  finite_in.
Qed.

Require Import Imp_LangTrick.CodeCompiler.EnvToStack.

Ltac AbsEnv_rel_inversion :=
  repeat match goal with
         | [ H: AbsEnv_rel _ _ _ _ |- _ ] =>
             progress invc H
         | [ H: Imp_Lang_lp_rel _ _ _ _ |- _ ] =>
             progress invc H
         | [ H: eval_prop_rel _ _ |- _ ] =>
             progress invc H
         | [ H: b_Imp_Lang _ _ _ _ _ |- _ ] =>
             progress invc H
         | [ H: a_Imp_Lang (PARAM_Imp_Lang _) _ _ _ _ |- _ ] =>
             progress invc H
         end.

Lemma big_enough :
  forall vars nenv dbenv stk n N,
    state_to_stack vars nenv dbenv stk ->
    forall k,
      nth_error dbenv k = Some n ->
      N = Datatypes.length vars + k + 1 ->

    Datatypes.length stk >= N.
Proof.
  intros vars nenv dbenv stk n N.
  intros STATE.
  invs STATE.
  intros k. intros H. intros NEQUAL. subst N. revert H. clear STATE. revert dbenv.
  induction k; intros.
  - destruct dbenv. invs H.
    rewrite app_length. rewrite map_length. simpl.
    rewrite <- Nat.add_assoc.
    replace (0 + 1) with 1.
    unfold ge.
    eapply Plus.plus_le_compat_l_stt.
    eapply le_n_S. lia.
    lia.
  - destruct dbenv. invs H.
    invs H.
    rewrite app_length. rewrite map_length. simpl. rewrite Nat.add_succ_r.
    rewrite <- Nat.add_assoc.
    simpl. rewrite Nat.add_succ_r. eapply le_n_S. rewrite Nat.add_assoc. replace (Datatypes.length vars + k + 1 <=
                                                                                    Datatypes.length vars + Datatypes.length dbenv) with (Datatypes.length vars + Datatypes.length dbenv >= Datatypes.length vars + k + 1).
    Check map_length.
    rewrite <- map_length with (B := nat) (f := nenv) at 1.
    rewrite <- app_length. eapply IHk.
    assumption.
    unfold ge. reflexivity.
Qed.

Ltac get_rid_of_ridiculousness :=
  match goal with
  | [ H: nth_error nil _ = Some ?n' |- _ ] =>
      invs H
  | [ H: nth_error (cons ?n nil) 1 = Some ?n' |- _ ] =>
      invs H
  | [ H2 : state_to_stack (cons _ _) ?nenv ?dbenv nil |- _ ] =>
      invs H2
  | [ H : state_to_stack (cons ?x ?y) _ nil (_ :: _ :: _) |- _ ] =>
      invs H
  | [ H2 : state_to_stack (_ :: nil) _ ?dbenv (_ :: nil),
        H6 : nth_error ?dbenv ?n = Some _ |- _ ] =>
      match n with
      | 0 =>
          invs H2; invs H6
      | 1 =>
              invs H2; invs H6
      end
  | [ H: None = Some _ |- _ ] =>
      invs H
  | [ H: Some _ = None |- _ ] =>
      invs H
  end.

Ltac destruct_stks stk :=
  destruct stk;
  try get_rid_of_ridiculousness;
  match goal with
  | [ |- _ >= _ ] =>
      unfold ge
  | [ |- _ ] =>
      idtac
  end;
  match goal with
  | [ |- None = Some ?n ] =>
      get_rid_of_ridiculousness
      
      
      
      
      
      
      
      
  | [ |- Some ?n = Some ?n'] =>
      match goal with
      | [ H2 : state_to_stack _ _ _ _ |- _ ] =>
          invs H2;
          match goal with
          | [ H3 : nth_error _ _ = Some n' |- _ ] =>
              invs H3;
              reflexivity
          end
      end
  | [ |- 0 <= Datatypes.length nil ] =>
      simpl; constructor
  | [ |- _ <= Datatypes.length nil ] =>
      get_rid_of_ridiculousness
  | [ |- 1 <= Datatypes.length (_ :: nil ) ] =>
      simpl; lia
  | [ |- 2 <= (Datatypes.length (_ :: _ :: _)) ] =>
      simpl; lia
  | [ |- 2 <= (Datatypes.length (_ :: nil)) ] =>
      get_rid_of_ridiculousness
  | [ |- 3 <= Datatypes.length (_ :: _ :: _ :: _) ] =>
      simpl; lia
  | [ |- _ ] =>
      match goal with
      | [ H2 : state_to_stack _ _ _ _ |- _ ] =>
          try (progress invs H2)
      end
  end.

Ltac repeat_until_matches_le :=
  match goal with
  | [ |- _ <= _ ] =>
      idtac
  | [ |- _ ] =>
      econstructor;
      repeat_until_matches_le
  end.

Lemma nth_error_nil_none :
  forall A n,
    @nth_error A nil n = None.
Proof.
  intros A. destruct n.
  - simpl. reflexivity.
  - simpl. reflexivity.
Qed.

Ltac absstate_match_inversion :=
  match goal with
  | [ H : StackLogicGrammar.absstate_match_rel _ _ _ |- _ ] =>
      invc H; absstate_match_inversion
  | [ H: StackLogicGrammar.absstack_match_rel _ _ |- _ ] =>
      invc H; absstate_match_inversion
  | [ H: StackLogicGrammar.meta_match_rel _ _ _ |- _ ] =>
      idtac "meta"; invc H; absstate_match_inversion
  | [ H: eval_prop_rel _ _ |- _ ] =>
      invc H; absstate_match_inversion
  | [ H: bexp_stack_sem _ _ _ _ |- _ ] =>
      invc H; absstate_match_inversion
  | [ H: aexp_stack_sem _ _ _ _ |- _ ] =>
      invc H; absstate_match_inversion
  | [ |- _ ] =>
      idtac "done"
  end.

Ltac reflect_seq H := rewrite String.eqb_eq in H; subst.
Ltac destruct_seq x y := destruct (string_dec x y).

Ltac invs_exists H i :=
  invs H; try (exists i; reflexivity).

Ltac twice t := t; t.
Ltac thrice t := t; t; t.

Ltac list_finite x :=
  match x with
  | cons _ ?rest =>
      list_finite rest
  | nil =>
      idtac
  | _ =>
      fail
  end.

Ltac var_map_wf_finite :=
  match goal with
  | [ |- var_map_wf ?x ] =>
      list_finite x;
      unfold var_map_wf; repeat split;
      [ finite_nodup | intros .. ];
      [ eapply find_index_rel_implication
      | eapply second_wf_proof
      | eapply in_list_means_exists_index
      | eapply free_vars_in_imp_alternate
      ]; eassumption
  end.

Ltac finite_in_implication :=
  match goal with
  | [ H: In ?x ?listA |- In ?x ?listB ] =>
      list_finite listA;
      list_finite listB;
      simpl in *; destruct H;
      finite_in_implication
  | [ H: ?y = ?x |- ?y = ?x \/ _ ] =>
      left; eassumption
  | [ H: ?y = ?x |- ?z = ?x \/ _ ] =>
      match z with
      | y =>
          left; finite_in_implication
      | _ =>
          right; finite_in_implication
      end
  | [ H: _ = _ \/ _ |- _ ] =>
      destruct H; finite_in_implication
  | [ H: False |- _ ] =>
      invs H; finite_in_implication
  | [ |- _ ] =>
      idtac
  end.

Ltac imp_has_variable_implies_in :=
  match goal with
  | [ H: imp_has_variable ?x _ |- In ?x ?listA ] =>
      list_finite listA;
      invc H;
      imp_has_variable_implies_in
  | [ H: (?x =? ?y) = true |- In ?x ?listA ] =>
      list_finite listA;
      eapply String.eqb_eq in H; rewrite H; finite_in
  | [ H: aexp_has_variable ?x _ |- In ?x ?listA ] =>
      list_finite listA;
      invc H;
      imp_has_variable_implies_in
  | [ H: args_has_variable ?x _ |- In ?x ?listA ] =>
      list_finite listA;
      invc H;
      imp_has_variable_implies_in
  | [ |- _ ] =>
      idtac
  end.

Ltac destruct_nth_error_rec :=
  match goal with
  | [ H: nth_error _ 0 = Some _ |- _ ] =>
      simpl in H;
      match goal with
      | [ H: Some _ = Some _ |- _ ] =>
          invc H
      end
  | [ H: nth_error (_ :: nil) (S ?n) = Some _ |- _ ] =>
      simpl in H;
      rewrite nth_error_nil_none in H;
      discriminate
  end.

Ltac destruct_nth_error listName :=
  unfold listName in *;
  match goal with
  | [ H : nth_error (_ :: _) ?n = Some _ |- _ ] =>
      destruct n;
      destruct_nth_error_rec
  end.

Require Import StackExprWellFormed.

Ltac expr_well_formed_slow :=
  match goal with
  | [ |- aexp_well_formed _ ] =>
      econstructor; expr_well_formed_slow
  | [ |- 1 <= ?k ] =>
      try lia
  | [ |- args_well_formed _ ] =>
      econstructor; expr_well_formed_slow
  | [ |- bexp_well_formed _ ] =>
      econstructor; expr_well_formed_slow
  | [ |- lp_aexp_well_formed _ ] =>
      econstructor; expr_well_formed_slow
  | [ |- lp_bexp_well_formed _ ] =>
      econstructor; expr_well_formed_slow
  | [ |- mv_well_formed _ ] =>
      econstructor; expr_well_formed_slow
  | [ |- prop_rel _ _ ] =>
      econstructor; expr_well_formed_slow
  | [ |- absstate_well_formed _ ] =>
      econstructor; expr_well_formed_slow
  end.

Ltac expr_well_formed :=
  prove_absstate_well_formed || expr_well_formed_slow.