Section PROGRAMS.
Variable F: Type.
(** Functions can either be defined ([Internal]) or declared as external functions ([External]). *)
Inductive fundef : Type :=
| Internal: F -> fundef
| External: external_function -> typelist -> type -> calling_convention -> fundef.
(** A program, or compilation unit, is composed of: - a list of definitions of functions and global variables; - the names of functions and global variables that are public (not static); - the name of the function that acts as entry point ("main" function). - a list of definitions for structure and union names - the corresponding composite environment - a proof that this environment is consistent with the definitions. *)
Record program : Type := {
prog_defs: list (ident * globdef fundef type);
prog_public: list ident;
prog_main: ident;
prog_types: list composite_definition;
prog_comp_env: composite_env;
prog_comp_env_eq: build_composite_env prog_types = OK prog_comp_env
}.
Definition program_of_program (p: program) : AST.program fundef type :=
{| AST.prog_defs := p.(prog_defs);
AST.prog_public := p.(prog_public);
AST.prog_main := p.(prog_main) |}.
Coercion program_of_program: program >-> AST.program.
Program Definition make_program (types: list composite_definition)
(defs: list (ident * globdef fundef type))
(public: list ident)
(main: ident) : res program :=
match build_composite_env types with
| Error e => Error e
| OK ce =>
OK {| prog_defs := defs;
prog_public := public;
prog_main := main;
prog_types := types;
prog_comp_env := ce;
prog_comp_env_eq := _ |}
end.
End PROGRAMS.
Arguments External {F} _ _ _ _.
Unset Implicit Arguments.
(** * Separate compilation and linking *)
(** ** Linking types *)
Program Instance Linker_types : Linker type := {
link := fun t1 t2 => if type_eq t1 t2 then Some t1 else None;
linkorder := fun t1 t2 => t1 = t2
}.
Next Obligation.
destruct (type_eq x y); inv H. auto.
Defined.
Global Opaque Linker_types.
(** ** Linking composite definitions *)
Definition check_compat_composite (l: list composite_definition) (cd: composite_definition) : bool :=
List.forallb
(fun cd' =>
if ident_eq (name_composite_def cd') (name_composite_def cd) then composite_def_eq cd cd' else true)
l.
Definition filter_redefs (l1 l2: list composite_definition) :=
let names1 := map name_composite_def l1 in
List.filter (fun cd => negb (In_dec ident_eq (name_composite_def cd) names1)) l2.
Definition link_composite_defs (l1 l2: list composite_definition): option (list composite_definition) :=
if List.forallb (check_compat_composite l2) l1
then Some (l1 ++ filter_redefs l1 l2)
else None.
Program Instance Linker_composite_defs : Linker (list composite_definition) := {
link := link_composite_defs;
linkorder := @List.incl composite_definition
}.
Next Obligation.
apply incl_refl.
Defined.
Next Obligation.
red; intros; eauto.
Defined.
Next Obligation.
apply link_composite_def_inv in H; destruct H as (A & B & C).
split; red; intros; apply C; auto.
Defined.
(** Connections with [build_composite_env]. *)

Theorem link_build_composite_env:
forall l1 l2 l env1 env2,
build_composite_env l1 = OK env1 ->
build_composite_env l2 = OK env2 ->
link l1 l2 = Some l ->
{ env |
build_composite_env l = OK env
/\ (forall id co, env1!id = Some co -> env!id = Some co)
/\ (forall id co, env2!id = Some co -> env!id = Some co) }.