WARNING ppx_optcomp_old
is the old ppx_optcomp
. It is a text
preprocessor rather than a pure ppx rewriter like the new
ppx_optcomp
. ppx_optcomp_old
is deprecated and its use is strongly
discouraged. In order to upgrade to the new syntax, write this in your
jbuild
file:
(library
(...
(preprocess (pps (... ppx_optcomp_old -upgrade-optcomp-syntax)))))
then run jbuilder build --auto-promote
. This will override the
source files by ones using the new syntax. The resulting files might
need to be tweaked as sometimes the upgrade produce invalid files.
ppx_optcomp stands for Optional Compilation. It is a tool used to handle optional compilations of pieces of code depending of the word size, the version of the compiler, ...
ppx_optcomp can be used a a standalone pre-processor, but is also integrated in the ppx_driver.
The syntax is quite similar to cpp:
#if ocaml_version < (4, 02, 0)
let x = 1
#else
let y = 2
#endif
Note that ppx_optcomp does not support macros like cpp, we only use it for optional compilations.
ppx_optcomp runs after the OCaml lexer and before the OCaml parser. This means that parts of the file that are dropped by ppx_optcomp needs to be lexically correct but not grammatically correct.
ppx_optcomp will interpret all lines that start with a #
. #
has
to be the first character, if there are spaces before ppx_optcomp
will not try to interpret the line and will pass it as-is to the OCaml
parser. The syntax is:
#identifier directive-argument
The argument is everything up to the end of the line. You can use \
at the end of lines to span the argument over multiple line. Optcomp
will also automatically fetch arguments past the end of line if a set
of parentheses is not properly closed.
So for instance one can write:
#if ocaml_version < ( 4
, 02
, 0
)
Note that since ppx_optcomp runs after the lexer it won't interpret
lines starting with #
if they are inside another token. So for
instance these won't work:
-
#
-directive inside a string:let x = " #if foo "
-
#
-directive inside a comment:(* #if foo *)
-
#let
pattern=
expression -
#define
identifier expression
We also allow: #define
identifier. This will define identifier
to ()
.
You can also undefine a variable using #undef
identifier.
The following directives are available for conditional compilations:
-
#if
expression -
#elif
expression #else
#endif
In all cases expression must be an expression that evaluates to a boolean value. Ppx_optcomp will fail if it is not the case.
For people used to cpp, we also allow these:
-
#ifdef
identifier -
#ifndef
identifier -
#elifdef
identifier -
#elifndef
identifier
Which will test if a variable is defined. Note that ppx_optcomp will
only accept to test if a variable is defined if it has seen it before,
in one of #let
, #define
or #undef
. This allows ppx_opcompt to
check for typos.
We do however allow this special case:
#ifndef VAR
#define VAR
#warning
expression will cause the pre-processor to print a
message on stderr.
#error
expression will cause the pre-processor to fail with the
following error message.
Note that in both cases expression can be an arbitrary expression.
Ppx_optcomp allows one to import another file using:
#import
filename
where filename is a string constant. Filenames to import are resolved as follow:
- if filename is relative, i.e. doesn't start with
/
, it is considered as relative to the directory of the file being parsed - if filename is absolute, i.e. starts with
/
, it is used as it
To keep things simple ppx_optcomp only allows for #
-directives in
imported files. The intended use is having this at the beginning of a
file:
#import "config.mlh"
ppx_optcomp supports a subset of OCaml expressions and patterns:
- literals: integers, characters and strings
- tuples
-
true
andfalse
- let-bindings
- pattern matching
And it provides the following functions:
- comparison operators:
=
,<
, ... - boolean operators:
||
,&&
,not
, ... - arithmetic operators:
+
,-
,*
,/
-
min
andmax
-
fst
andsnd
- conversion functions:
to_int
,to_string
,to_char
,to_bool
-
show
: pretty-print a value
It also provides defined
which is a special function to test if a
variable is defined. But the same remark as for #ifdef
applies to
defined
.