Module ConseqFacts :=
SeparationLogicFacts.GenConseqFacts
(SeparationLogicAsLogicSoundness.MainTheorem.CSHL_PracticalLogic.CSHL_MinimumLogic.CSHL_Def)
(Conseq).
(* OLD VERSION: Lemma semax_post': forall R' Espec {cs: compspecs} Delta R P c, R' |-- R -> @semax cs Espec Delta P c (normal_ret_assert R') -> @semax cs Espec Delta P c (normal_ret_assert R). *)
intros.
destruct Q as [?Q ?Q ?Q ?Q].
eapply semax_post; eauto; intros; apply andp_left2; simpl; auto; normalize.
Qed.
Ltac frame_SEP' L :=  (* this should be generalized to permit framing on LOCAL part too *)
grab_indexes_SEP L;
match goal with
| |- @semax _ _ (PROPx _ (LOCALx _ (SEPx ?R))) _ _ =>
rewrite <- (firstn_skipn (length L) R);
simpl length; unfold firstn, skipn;
eapply (semax_frame_PQR nil);
[ unfold closed_wrt_modvars;  auto 50 with closed
| ]
| |- ENTAIL _ , (PROPx _ (LOCALx _ (SEPx ?R))) |-- _ =>
rewrite <- (firstn_skipn (length L) R);
simpl length; unfold firstn, skipn;
apply derives_frame_PQR
end.
Tactic Notation "frame_SEP" constr(a) :=
frame_SEP' (a::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) :=
frame_SEP' (a::b::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) :=
frame_SEP' (a::b::c::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) constr(d) :=
frame_SEP' (a::b::c::d::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) :=
frame_SEP' (a::b::c::d::e::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) :=
frame_SEP' (a::b::c::d::e::f::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) :=
frame_SEP' (a::b::c::d::e::f::g::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) constr(h) :=
frame_SEP' (a::b::c::d::e::f::g::h::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) constr(h) constr(i) :=
frame_SEP' (a::b::c::d::e::f::g::h::i::nil).
Tactic Notation "frame_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) constr(h) constr(i) constr(j) :=
frame_SEP' (a::b::c::d::e::f::g::h::i::j::nil).
Ltac gather_SEP' L :=
grab_indexes_SEP L;
match goal with |- context [SEPx ?R] =>
let r := fresh "R" in
set (r := (SEPx R));
revert r;
rewrite <- (firstn_skipn (length L) R);
unfold length at 1 2;
unfold firstn at 1; unfold skipn at 1;
rewrite gather_SEP;
unfold fold_right at 1; try  rewrite sepcon_emp;
try (intro r; unfold r; clear r)
end.
(* replaced by the new gather_SEP in freezer.v ... Tactic Notation "gather_SEP" constr(a) := gather_SEP' (a::nil). Tactic Notation "gather_SEP" constr(a) constr(b) := gather_SEP' (a::b::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) := gather_SEP' (a::b::c::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) constr(d) := gather_SEP' (a::b::c::d::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) := gather_SEP' (a::b::c::d::e::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) := gather_SEP' (a::b::c::d::e::f::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) := gather_SEP' (a::b::c::d::e::f::g::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) constr(h) := gather_SEP' (a::b::c::d::e::f::g::h::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) constr(h) constr(i) := gather_SEP' (a::b::c::d::e::f::g::h::i::nil). Tactic Notation "gather_SEP" constr(a) constr(b) constr(c) constr(d) constr(e) constr(f) constr(g) constr(h) constr(i) constr(j) := gather_SEP' (a::b::c::d::e::f::g::h::i::j::nil). *)
Fixpoint replace_nth {A} (n: nat) (al: list A) (x: A) {struct n}: list A :=
match n, al with
| O , a::al => x::al
| S n', a::al' => a :: replace_nth n' al' x
| _, nil => nil
end.
Fixpoint my_nth{A} (n: nat) (al: list A) (default: A) {struct n} : A :=
(* just like nth; make a new copy, for better control of unfolding *)
match n, al with
| O, a::al' => a
| S n', a::al' => my_nth n' al' default
| _, nil => default
end.
Tactic Notation "replace_SEP" constr(n) constr(R) :=
first [apply (replace_SEP' (Z.to_nat n) R) | apply (replace_SEP'' (Z.to_nat n) R)];
unfold my_nth,replace_nth; simpl Z.to_nat;
repeat simpl_nat_of_P; cbv beta iota; cbv beta iota.
Tactic Notation "replace_SEP" constr(n) constr(R) "by" tactic1(t):=
first [apply (replace_SEP' (Z.to_nat n) R) | apply (replace_SEP'' (Z.to_nat n) R)];
unfold my_nth,replace_nth; simpl Z.to_nat;
repeat simpl_nat_of_P; cbv beta iota; cbv beta iota; [ now t | ].
Tactic Notation "viewshift_SEP" constr(n) constr(R) :=
first [apply (replace_SEP'_bupd (Z.to_nat n) R) | apply (replace_SEP''_bupd (Z.to_nat n) R)];
unfold my_nth,replace_nth; simpl Z.to_nat;
repeat simpl_nat_of_P; cbv beta iota; cbv beta iota.
Tactic Notation "viewshift_SEP" constr(n) constr(R) "by" tactic1(t):=
first [apply (replace_SEP'_bupd (Z.to_nat n) R) | apply (replace_SEP''_bupd (Z.to_nat n) R)];
unfold my_nth,replace_nth; simpl Z.to_nat;
repeat simpl_nat_of_P; cbv beta iota; cbv beta iota; [ now t | ].
Ltac replace_in_pre S S' :=
match goal with |- @semax _ _ _ ?P _ _ =>
match P with context C[S] =>
let P' := context C[S'] in
apply semax_pre with P'; [ | ]
end
end.
Hint Resolve PROP_later_derives LOCAL_later_derives SEP_later_derives : derives.
Hint Rewrite @local_lift0: norm2.
Ltac repeat_extract_exists_pre :=
first [(apply extract_exists_pre;
let x := fresh "x" in intro x; normalize;
repeat_extract_exists_pre;
revert x)
| autorewrite with canon
].
Ltac extract_exists_in_SEP :=
match goal with |- @semax _ _ _ (PROPx _ (LOCALx _ (SEPx ?R))) _ _ =>
match R with context [ exp ?z :: _] =>
let n := find_in_list (exp z) R
in rewrite (grab_nth_SEP n); unfold nth, delete_nth; rewrite extract_exists_in_SEP;
repeat_extract_exists_pre
end
end.

Lemma flatten_sepcon_in_SEP:
forall P Q R1 R2 R,
PROPx P (LOCALx Q (SEPx ((R1*R2) :: R))) =
PROPx P (LOCALx Q (SEPx (R1 :: R2 :: R))).