Version française
Home     About     Download     Resources     Contact us    

This site is updated infrequently. For up-to-date information, please visit the new OCaml website at

Browse thread
HOWTO create and install a new printer with camlp4 3.10
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Hendrik Tews <H.Tews@c...>
Subject: HOWTO create and install a new printer with camlp4 3.10

Posted in the hope to save somebody's time before the new camlp4
documentation gets out.

First a word on side effects: I mean those side effects that
newly loaded modules perform inside camlp4 to register their
functions in the camlp4 engine.

In the good old times one simply used assignments for that, for
	Pcaml.print_implem := f
has always been used to install f as printer for a .ml file.

In the new camlp4 (some of) these side effects are performed not
by the user but by camlp4 itself. The user only supplies the
structure. It works the following way: The user defines a 
functor Make that maps some structure to a structure that defines
the entities that camlp4 should use:

    module Make (some arg) = struct
      let important_fun ...

The user then uses Make in a functor application with a
higher-order, registering functor from camlp4:

   module IgnoreResult = Camlp4.Register.Purpose(Make)

where Purpose is one of the functors that Camlp4.Register
provides. On invocation Purpose applies the user supplied Make to
the right arguments, obtains a structure with important_fun and,
finally, performs the side effect to register important_fun in
the right hook. Actually the story is a bit more complicated,
because the side effects are delayed: First Make is registered as
a loaded module inside camlp4 together with a function that will
perform the necessary side effects some time later. See for
example functor Printer in camlp4/Camlp4/ line 73.

In order to install a new camlp4 printer we only have to find the
right registering functor and apply it to our arguments, put
everything into some file and compile it into a .cmo.

To install a new printer I chose Register.Printer, which takes
two arguments: an identification module and a Make functor with
my new printer functions inside. 

Here is the complete code:

  (* identification module *)
module Id = struct
    (* name is printed with the -loaded-modules switch *)
  let name = "Printer HOWTO"
    (* cvs id's seem to be the preferred version string *)
  let version = "$Id: howto verion 1 $"

  (* the real thing containing the real functions *)
module Make (Syntax : Camlp4.Sig.Syntax) : 
  Camlp4.Sig.Printer with module Ast = Syntax.Ast = 
  module Ast = Syntax.Ast
  let opt_string = function
    | None -> "<None>"
    | Some s -> s

  let info ?input_file ?output_file name =
      "printer on %s\n input : %s\n output : %s\n"
      (opt_string input_file)
      (opt_string output_file)

    (* print_interf shall be called on .mli files *)
  let print_interf ?input_file ?output_file ast = 
    info ?input_file ?output_file "signature"

    (* print_implem shall be called on .ml files *)
  let print_implem ?input_file ?output_file ast =
    info ?input_file ?output_file "structure"

  (* apply everything to register the new printer *)
module M = Camlp4.Register.Printer(Id)(Make)

(* end of source *)

Put the source into a file and compile with 

   ocamlc -c -I `camlp4 -where`

Use examples:

    gromit otags 7> camlp4o printer.cmo
    printer on structure
     input :
     output : <None>

    gromit otags 8> camlp4o -o output_file printer.cmo
    printer on structure
     input :
     output : output_file

    gromit otags 9> ocamlc -pp 'camlp4o printer.cmo'
    printer on structure
     input :
     output : <None>

Happy printing,