[intro] [example] [advanced] [download]
Camlmix is a generic preprocessor which converts text with embedded
OCaml into an
OCaml program with embedded text.
It produces text documents from one or several templates.
Camlmix is not a
Camlp4 syntax extension.
The basic syntaxic rules are:
Some text ## (* Some OCaml statements *) ... ## More text ...
Some text ##= (* Some OCaml string expression *) ... ## More text ...
This prints actually 2 # symbols: ###
Camlmix does not provide a library for text-processing, but all existing libraries and syntax extensions can be used, such as HereDoc, Micmatch or xstrp4. You can also find some examples of code in the Camlmix Toolbox if you are not familiar with I/O in OCaml.
The file example.mlx
contains the following:
## open Printf let color col s = sprintf "<span style=\"color:%s\">%s</span>" col s ## This is ##= color "red" "red text" ##, but that is a ##= color "blue" "blue one" ##.
The command
camlmix example.mlx -o example.html
will produce the following example.html
file:
This is <span style="color:red">red text</span>, but that is a <span style="color:blue">blue one</span>.
This piece of HTML will be displayed as: This is red text, but that is a blue one.
You may now have a look at the Camlmix/HTML colorized source of this web page, which was itself made using a Camlmix template.
Camlmix also allows you to convert a template into a regular OCaml source file
which is equipped with a single function named render
:
camlmix example.mlx -c -fun -co example.ml
The signature of the render
function would be:
val render : ?print:(string -> unit) -> 'a -> unit
where the 'a
parameter stands for the type of the argument which
is passed to the rendering function. It is available in the template
under the name param
, and its usage determines its
actual type. The print
function is the one which is used
to handle text. By default, it prints the text onto stdout, but
it can be replaced by any other function, as long as the user-defined
code of the template uses it.
The result example.ml
is a regular OCaml file which would
be integrated into a regular OCaml program.
The full set of features and options is described in
the output of camlmix -help
A block of code that starts with an @
character will not
be handled as OCaml code but as a sequence of directives for
Camlmix.
There is one useful directive: include
.
This mechanism allows the insertion of templates and subtemplates that
inherit the whole OCaml environment, and possibly modify it.
These templates are not only
parametrized by string variables but also by any type of OCaml data,
including functions, and even by types and modules!
The include
directive reads a file
(e.g. included.mlx
)
in the Camlmix syntax exactly as if its
contents was inserted in the current file (e.g. main.mlx
):
main.mlx:
## let print_counter = (* increments the counter and displays its new value *) let n = ref 0 in fun () -> incr n; print_int !n ## Should be 1: ## print_counter () ## Should be 2: ## @include "included.mlx" ## Should be 3: ## print_counter () ##
included.mlx:
## print_counter () ##
camlmix main.mlx
returns the following:
Should be 1: 1 Should be 2: 2 Should be 3: 3
This is not totally satisfying because two undesired empty lines were inserted.
In Camlmix 1.2, you can skip whitespace until the end of the line and the
newline character by using
.##
instead of ##
as the closing delimiter.
This results in the following program:
## let print_counter = (* increments the counter and displays its new value *) let n = ref 0 in fun () -> incr n; print_int !n .## Should be 1: ## print_counter () ## Should be 2: ## @include "included.mlx" .## Should be 3: ## print_counter () ##
which now produces:
Should be 1: 1 Should be 2: 2 Should be 3: 3
A skip
directive also exists: it ignores the next block of text.
It is not much useful since the .##
delimiter was introduced in
Camlmix 1.2.
It was useful when a block of OCaml had to follow a block of directives,
without printing anything between them:
## @include "somefile.mlx"; skip (* skips the newline character(s) -> *) ## ## print_something () ##
The OCaml program that is generated from the Camlmix files first defines a module called Camlmix. This module contains several variables that are updated automatically and possibly explicitely by the user. Its signature is:
module Camlmix : sig val source : string ref val line : int ref val char : int ref
source
, line
and char
refer to the location of the first
character of the current block in its source file
(source file, line number starting from 1, position in the line
starting from 1). They are updated automatically at the beginning
of each code block or text block.
val printer : (string -> unit) ref
the function that prints the text blocks
val print_with : (string -> unit) -> unit
print_with f
prints the next block of text using
f
instead
of the current printer.
Its behavior is undefined if it is called several
times in the same OCaml block.
val print_if : bool -> unit
print_if cond
prints the next block of text only
if cond
is true.
It uses print_with
.
end
The command line options are returned by
camlmix -help
.
Camlmix can be installed automatically from GODI.
You can also use the traditional way. Just download the source code: camlmix-1.3.0.tar.bz2 or camlmix-1.3.0.tar.gz. It should work on any platform where OCaml is available.
I would be happy if you send me any positive or negative feedback.
Thanks to Nadji Gauthier, Jean-Baptiste Rouquier, Arthur E., Janne Hellsten and those that I forget, for their contributions.