package metapp
Install
Dune Dependency
Authors
Maintainers
Sources
sha512=08edbd4ec92eae6e3ad7062cdb1787cdc1429164d15425a5b126c5c56c51e5ec51bd69052a4f1594b70f34034e1c00d8f82d1be2acf9b9c2a06130858bcc53c5
Description
Meta-preprocessor for OCaml: extends the language with [%meta ... ] construction where ... stands for OCaml code evaluated at compile-time.
Published: 02 Oct 2020
README
metapp
: meta-preprocessor for OCaml
metapp
is a PPX rewriter that provides a [%meta ...]
extension, where the dots ...
are arbitrary OCaml expressions that are substituted at compile-time by the AST nodes they evaluate into. These expressions build AST nodes either by quoting some code directly, or by using compiler-libs
(Parsetree
, Ast_helper
, ...).
In particular, this preprocessor is easy to use for conditional compilation, and is an alternative to cppo
and ppx_optcomp
.
let option_get o =
[%meta if Sys.ocaml_version >= "4.08.0" then
[%e Option.get o]
else
[%e match o with
| None -> invalid_arg "option_get"
| Some x -> x]]
metapp
can be used with dune
by using the preprocess
field.
(executable
...
(preprocess (pps metapp.ppx))
...)
Inside [%meta ...]
code, the [%e ...]
extension quotes expressions (of type [Parsetree.expression
]). There are other quotations available: the full list is given below.
Quotation | Type |
---|---|
[%e ...] or [%expr ...] |
Parsetree.expression |
[%p? ...] or [%pat? ...] |
Parsetree.pattern |
[%t: ...] or [%type: ...] |
Parsetree.core_type |
[%sig: ...] |
Parsetree.signature |
[%sigi: ...] |
Parsetree.signature_item |
[%str ...] |
Parsetree.structure |
[%stri ...] |
Parsetree.structure_item |
Quoted expressions can in turn contain further [%meta ...]
code. Moreover, [%meta ...]
code can itself contain other levels of [%meta ...]
code, for multi-stage programming.
In addition to this syntax extension, the Metapp
module provided by the metapp
package provides convenient functions for AST constructions. In particular, this module provides an OCaml-version-independent interface. Moveover, this module provides a common signature ValueS
for constructing and transforming expressions (module Exp
), patterns (module Pat
) or both at the same time (module Value
).
The Metapp
module also provides a filter
mapper, which handles [@if <bool>]
attributes à la ppx_optcomp
. The [@if <bool>]
attribute can appear mostly everywhere syntax elements are enumerated, including tuples, function applications, arrays, etc.
[%%meta Metapp.include_structure (
Metapp.filter.structure Metapp.filter [%str
type t =
| A of int
| B of int * int
[@if [%meta Metapp.Exp.of_bool (Sys.ocaml_version >= "4.04.0")]]
...
match (v: t) with
| A x -> something x
| B (y,z)
[@if [%meta Metapp.Exp.of_bool (Sys.ocaml_version >= "4.04.0")]] ->
something' y z
... ])]
Global definitions for meta-code can be included with [%%metadef ...]
. By default, the meta-code is compiled with the compiler-libs
package. Other packages can be loaded with [%%metapackage ...]
. More generally, flags can be passed to the compiler to compile meta-code with [%%metaflag ...]
(there is another convenient notation for adding interface directories: [%%metadir ...]
). [%%metaload ...]
loads a particular compilation unit. For instance, [%%metapackage metapp]
links the meta-code with the metapp
package in order to use the Metapp
module. All these notations can be applied to multiple arguments at once by using comma as separator.
Note that dynamic package loading is broken in PPX with dune (#3214). When packages are loaded with [%%metapackage ...]
, a workaround (see discussion) is used to load the packages correctly, but only with OCaml >=4.08. If you need to use [%%metapackage ...]
with a prior version of OCaml, you still can statically link the packages you need by listing them in the (preprocess (pps ...))
list. You will still have to import them with [%%metapackage ...]
to let the compiler see their interface when compiling the meta-code.
Compilation commands can be logged by adding [%%metaverbose]
to the preprocessed file.