(** Information attached to global variables. *)
Record globvar (V: Type) : Type := mkglobvar {
gvar_info: V;                    (**r language-dependent info, e.g. a type *)
gvar_init: list init_data;       (**r initialization data *)
gvar_readonly: bool;             (**r read-only variable? (const) *)
gvar_volatile: bool              (**r volatile variable? *)
}.
(** Whole programs consist of: - a collection of global definitions (name and description); - a set of public names (the names that are visible outside this compilation unit); - the name of the ``main'' function that serves as entry point in the program.  A global definition is either a global function or a global variable. The type of function descriptions and that of additional information for variables vary among the various intermediate languages and are taken as parameters to the [program] type.  The other parts of whole programs are common to all languages. *)
Inductive globdef (F V: Type) : Type :=
| Gfun (f: F)
| Gvar (v: globvar V).
Arguments Gfun [F V].
Arguments Gvar [F V].
Record program (F V: Type) : Type := mkprogram {
prog_defs: list (ident * globdef F V);
prog_public: list ident;
prog_main: ident
}.
Definition prog_defs_names (F V: Type) (p: program F V) : list ident :=
List.map fst p.(prog_defs).
(** The "definition map" of a program maps names of globals to their definitions. If several definitions have the same name, the one appearing last in [p.(prog_defs)] wins. *)
Definition prog_defmap (F V: Type) (p: program F V) : PTree.t (globdef F V) :=
PTree_Properties.of_list p.(prog_defs).
Section DEFMAP.
Variables F V: Type.
Variable p: program F V.

(* Specifications: *)
Lemma in_prog_defmap:
forall id g, (prog_defmap p)!id = Some g -> In (id, g) (prog_defs p).
Lemma prog_defmap_dom:
forall id, In id (prog_defs_names p) -> exists g, (prog_defmap p)!id = Some g.
Lemma prog_defmap_unique:
forall defs1 id g defs2,
prog_defs p = defs1 ++ (id, g) :: defs2 ->
~In id (map fst defs2) ->
(prog_defmap p)!id = Some g.
Lemma prog_defmap_norepet:
forall id g,
list_norepet (prog_defs_names p) ->
In (id, g) (prog_defs p) ->
(prog_defmap p)!id = Some g.
Lemma in_prog_defmap:
forall id g, (prog_defmap p)!id = Some g -> In (id, g) (prog_defs p).
Lemma prog_defmap_dom:
forall id, In id (prog_defs_names p) -> exists g, (prog_defmap p)!id = Some g.
Lemma prog_defmap_unique:
forall defs1 id g defs2,
prog_defs p = defs1 ++ (id, g) :: defs2 ->
~In id (map fst defs2) ->
(prog_defmap p)!id = Some g.
Lemma prog_defmap_norepet:
forall id g,
list_norepet (prog_defs_names p) ->
In (id, g) (prog_defs p) ->
(prog_defmap p)!id = Some g.