Require Export Coq.Sorting.Permutation.
Local Open Scope logic.
Inductive localdef : Type :=
| temp: ident -> val -> localdef
| lvar: ident -> type -> val -> localdef   (* local variable *)
| gvars: globals -> localdef.              (* global variables *)
Arguments temp i%positive v.
Definition lvar_denote (i: ident) (t: type) (v: val) rho :=
match Map.get (ve_of rho) i with
| Some (b, ty') => t=ty' /\ v = Vptr b Ptrofs.zero
| None => False
end.
Definition gvars_denote (gv: globals) rho :=
gv = (fun i => match Map.get (ge_of rho) i with Some b => Vptr b Ptrofs.zero | None => Vundef end).
Definition locald_denote (d: localdef) : environ -> Prop :=
match d with
| temp i v => `and (`(eq v) (eval_id i)) `(v <> Vundef)
| lvar i t v => lvar_denote i t v
| gvars gv => gvars_denote gv
end.
Fixpoint fold_right_andp rho (l: list (environ -> Prop)) : Prop :=
match l with
| nil => True
| b::nil => b rho
| b::r => b rho /\ fold_right_andp rho r
end.
Definition PROPx (P: list Prop): forall (Q: environ->mpred), environ->mpred :=
andp (prop (fold_right and True P)).
Notation "'PROP' ( x ; .. ; y )   z" := (PROPx (cons x%type .. (cons y%type nil) ..) z) (at level 10).
Notation "'PROP' ()   z" :=   (PROPx nil z) (at level 10).
Notation "'PROP' ( )   z" :=   (PROPx nil z) (at level 10).
Definition LOCALx (Q: list localdef) : forall (R: environ->mpred), environ->mpred :=
andp (local (fold_right (`and) (`True) (map locald_denote Q))).
Notation " 'LOCAL' ( )   z" := (LOCALx nil z)  (at level 9).
Notation " 'LOCAL' ()   z" := (LOCALx nil z)  (at level 9).
Notation " 'LOCAL' ( x ; .. ; y )   z" := (LOCALx (cons x%type .. (cons y%type nil) ..) z)
(at level 9).
Definition SEPx (R: list mpred) : environ->mpred :=
fun _ => (fold_right_sepcon R).
Arguments SEPx R _ : simpl never.
Notation " 'SEP' ( x ; .. ; y )" := (SEPx (cons x%logic .. (cons y%logic nil) ..))
(at level 8).
Notation " 'SEP' ( ) " := (SEPx nil) (at level 8).
Notation " 'SEP' () " := (SEPx nil) (at level 8).
Declare Scope assert.
Delimit Scope assert with assert.
Opaque rmaps.dependent_type_functor_rec.
(* Possible ?? *)
(* Lemma SEPx_super_non_expansive: forall A (R: list (forall ts, functors.MixVariantFunctor._functor (rmaps.dependent_type_functor_rec ts (rmaps.ArrowType A rmaps.Mpred)) mpred)), Forall (fun R0: (forall ts, functors.MixVariantFunctor._functor (rmaps.dependent_type_functor_rec ts (rmaps.ArrowType A rmaps.Mpred)) mpred) => @super_non_expansive A (fun ts (a: functors.MixVariantFunctor._functor (rmaps.dependent_type_functor_rec ts A) mpred) (_: environ) => R0 ts a)) R -> @super_non_expansive A (fun ts (a: functors.MixVariantFunctor._functor (rmaps.dependent_type_functor_rec ts A) mpred) (rho: environ) => SEPx (map (fun R0: forall ts, functors.MixVariantFunctor._functor (rmaps.dependent_type_functor_rec ts (rmaps.ArrowType A rmaps.Mpred)) mpred => R0 ts a) R) rho).*)
Notation "'EX' x .. y , P " :=
(@exp (environ->mpred) _ _ (fun x =>
..
(@exp (environ->mpred) _ _ (fun y => P%assert))
..
)) (at level 65, x binder, y binder, right associativity) : assert.
Notation " 'ENTAIL' d ',' P '|--' Q " :=
(@derives (environ->mpred) _ (andp (local (tc_environ d)) P%assert) Q%assert) (at level 80, P at level 79, Q at level 79).
Arguments semax {CS} {Espec} Delta Pre%assert cmd Post%assert.

Lemma insert_local: forall Q1 P Q R,
local (locald_denote Q1) && (PROPx P (LOCALx Q (SEPx R))) = (PROPx P (LOCALx (Q1 :: Q) (SEPx R))).