End DEFMAP.
(** * Generic transformations over programs *)
(** We now define a general iterator over programs that applies a given code transformation function to all function descriptions and leaves the other parts of the program unchanged. *)
Section TRANSF_PROGRAM.
Variable A B V: Type.
Variable transf: A -> B.
Definition transform_program_globdef (idg: ident * globdef A V) : ident * globdef B V :=
match idg with
| (id, Gfun f) => (id, Gfun (transf f))
| (id, Gvar v) => (id, Gvar v)
end.
Definition transform_program (p: program A V) : program B V :=
mkprogram
(List.map transform_program_globdef p.(prog_defs))
p.(prog_public)
p.(prog_main).
End TRANSF_PROGRAM.
(** The following is a more general presentation of [transform_program]: - Global variable information can be transformed, in addition to function definitions. - The transformation functions can fail and return an error message. - The transformation for function definitions receives a global context (derived from the compilation unit being transformed) as additiona argument. - The transformation functions receive the name of the global as additional argument. *)
Local Open Scope error_monad_scope.
Section TRANSF_PROGRAM_GEN.
Variables A B V W: Type.
Variable transf_fun: ident -> A -> res B.
Variable transf_var: ident -> V -> res W.
Definition transf_globvar (i: ident) (g: globvar V) : res (globvar W) :=
do info' <- transf_var i g.(gvar_info);
OK (mkglobvar info' g.(gvar_init) g.(gvar_readonly) g.(gvar_volatile)).
Fixpoint transf_globdefs (l: list (ident * globdef A V)) : res (list (ident * globdef B W)) :=
match l with
| nil => OK nil
| (id, Gfun f) :: l' =>
match transf_fun id f with
| Error msg => Error (MSG "In function " :: CTX id :: MSG ": " :: msg)
| OK tf =>
do tl' <- transf_globdefs l'; OK ((id, Gfun tf) :: tl')
end
| (id, Gvar v) :: l' =>
match transf_globvar id v with
| Error msg => Error (MSG "In variable " :: CTX id :: MSG ": " :: msg)
| OK tv =>
do tl' <- transf_globdefs l'; OK ((id, Gvar tv) :: tl')
end
end.
Definition transform_partial_program2 (p: program A V) : res (program B W) :=
do gl' <- transf_globdefs p.(prog_defs);
OK (mkprogram gl' p.(prog_public) p.(prog_main)).
End TRANSF_PROGRAM_GEN.
(** The following is a special case of [transform_partial_program2], where only function definitions are transformed, but not variable definitions. *)
Section TRANSF_PARTIAL_PROGRAM.
Variable A B V: Type.
Variable transf_fun: A -> res B.
Definition transform_partial_program (p: program A V) : res (program B V) :=
transform_partial_program2 (fun i f => transf_fun f) (fun i v => OK v) p.
End TRANSF_PARTIAL_PROGRAM.

Lemma transform_program_partial_program:
forall (A B V: Type) (transf_fun: A -> B) (p: program A V),
transform_partial_program (fun f => OK (transf_fun f)) p = OK (transform_program transf_fun p).