module Ast_mapper: sig .. end
A -ppx rewriter is a program that accepts a serialized abstract syntax tree and outputs another, possibly modified, abstract syntax tree. This module encapsulates the interface between the compiler and the -ppx rewriters, handling such details as the serialization format, forwarding of command-line flags, and storing state.
Ast_mapper.mapper
allows to implement AST rewriting using open recursion.
A typical mapper would be based on Ast_mapper.default_mapper
, a deep
identity mapper, and will fall back on it for handling the syntax it
does not modify. For example:
open Asttypes open Parsetree open Ast_mapper let test_mapper argv = { default_mapper with expr = fun mapper expr -> match expr with | { pexp_desc = Pexp_extension ({ txt = "test" }, PStr [])} -> Ast_helper.Exp.constant (Const_int 42) | other -> default_mapper.expr mapper other; } let () = register "ppx_test" test_mapper
This -ppx rewriter, which replaces [%test]
in expressions with
the constant 42
, can be compiled using
ocamlc -o ppx_test -I +compiler-libs ocamlcommon.cma ppx_test.ml
.
type mapper = {
|
attribute : mapper -> Parsetree.attribute -> Parsetree.attribute; |
|
attributes : mapper -> Parsetree.attribute list -> Parsetree.attribute list; |
|
case : mapper -> Parsetree.case -> Parsetree.case; |
|
cases : mapper -> Parsetree.case list -> Parsetree.case list; |
|
class_declaration : mapper -> Parsetree.class_declaration -> Parsetree.class_declaration; |
|
class_description : mapper -> Parsetree.class_description -> Parsetree.class_description; |
|
class_expr : mapper -> Parsetree.class_expr -> Parsetree.class_expr; |
|
class_field : mapper -> Parsetree.class_field -> Parsetree.class_field; |
|
class_signature : mapper -> Parsetree.class_signature -> Parsetree.class_signature; |
|
class_structure : mapper -> Parsetree.class_structure -> Parsetree.class_structure; |
|
class_type : mapper -> Parsetree.class_type -> Parsetree.class_type; |
|
class_type_declaration : mapper -> Parsetree.class_type_declaration -> Parsetree.class_type_declaration; |
|
class_type_field : mapper -> Parsetree.class_type_field -> Parsetree.class_type_field; |
|
constructor_declaration : mapper -> Parsetree.constructor_declaration -> Parsetree.constructor_declaration; |
|
expr : mapper -> Parsetree.expression -> Parsetree.expression; |
|
extension : mapper -> Parsetree.extension -> Parsetree.extension; |
|
extension_constructor : mapper -> Parsetree.extension_constructor -> Parsetree.extension_constructor; |
|
include_declaration : mapper -> Parsetree.include_declaration -> Parsetree.include_declaration; |
|
include_description : mapper -> Parsetree.include_description -> Parsetree.include_description; |
|
label_declaration : mapper -> Parsetree.label_declaration -> Parsetree.label_declaration; |
|
location : mapper -> Location.t -> Location.t; |
|
module_binding : mapper -> Parsetree.module_binding -> Parsetree.module_binding; |
|
module_declaration : mapper -> Parsetree.module_declaration -> Parsetree.module_declaration; |
|
module_expr : mapper -> Parsetree.module_expr -> Parsetree.module_expr; |
|
module_type : mapper -> Parsetree.module_type -> Parsetree.module_type; |
|
module_type_declaration : mapper -> Parsetree.module_type_declaration -> Parsetree.module_type_declaration; |
|
open_description : mapper -> Parsetree.open_description -> Parsetree.open_description; |
|
pat : mapper -> Parsetree.pattern -> Parsetree.pattern; |
|
payload : mapper -> Parsetree.payload -> Parsetree.payload; |
|
signature : mapper -> Parsetree.signature -> Parsetree.signature; |
|
signature_item : mapper -> Parsetree.signature_item -> Parsetree.signature_item; |
|
structure : mapper -> Parsetree.structure -> Parsetree.structure; |
|
structure_item : mapper -> Parsetree.structure_item -> Parsetree.structure_item; |
|
typ : mapper -> Parsetree.core_type -> Parsetree.core_type; |
|
type_declaration : mapper -> Parsetree.type_declaration -> Parsetree.type_declaration; |
|
type_extension : mapper -> Parsetree.type_extension -> Parsetree.type_extension; |
|
type_kind : mapper -> Parsetree.type_kind -> Parsetree.type_kind; |
|
value_binding : mapper -> Parsetree.value_binding -> Parsetree.value_binding; |
|
value_description : mapper -> Parsetree.value_description -> Parsetree.value_description; |
|
with_constraint : mapper -> Parsetree.with_constraint -> Parsetree.with_constraint; |
let default_mapper: mapper;
let tool_name: unit => string;
"ocamlc"
, "ocamlopt"
, "ocamldoc"
, "ocamldep"
,
"ocaml"
, ... Some global variables that reflect command-line
options are automatically synchronized between the calling tool
and the ppx preprocessor: Clflags.include_dirs
,
Config.load_path
, Clflags.open_modules
, Clflags.for_package
,
Clflags.debug
.let apply: (~source: string, ~target: string, mapper) => unit;
source
file and put the result in the
target
file. The structure
or signature
field of the mapper
is applied to the implementation or interface.let run_main: (list(string) => mapper) => unit;
Location.input_name
. This
function implements proper error reporting for uncaught
exceptions.let register_function:
Pervasives.ref((string, list(string) => mapper) => unit);
let register: (string, list(string) => mapper) => unit;
register_function
. The default behavior is to run the
mapper immediately, taking arguments from the process command
line. This is to support a scenario where a mapper is linked as a
stand-alone executable.
It is possible to overwrite the register_function
to define
"-ppx drivers", which combine several mappers in a single process.
Typically, a driver starts by defining register_function
to a
custom implementation, then lets ppx rewriters (linked statically
or dynamically) register themselves, and then run all or some of
them. It is also possible to have -ppx drivers apply rewriters to
only specific parts of an AST.
The first argument to register
is a symbolic name to be used by
the ppx driver.
let map_opt: ('a => 'b, option('a)) => option('b);
let extension_of_error: Location.error => Parsetree.extension;
let attribute_of_warning: (Location.t, string) => Parsetree.attribute;
let add_ppx_context_str:
(~tool_name: string, Parsetree.structure) => Parsetree.structure;
let add_ppx_context_sig:
(~tool_name: string, Parsetree.signature) => Parsetree.signature;
add_ppx_context_str
, but for signatures.let drop_ppx_context_str:
(~restore: bool, Parsetree.structure) => Parsetree.structure;
restore
is true, also restore the associated data in the current
process.let drop_ppx_context_sig:
(~restore: bool, Parsetree.signature) => Parsetree.signature;
drop_ppx_context_str
, but for signatures.let set_cookie: (string, Parsetree.expression) => unit;
let get_cookie: string => option(Parsetree.expression);