模块 Ast_mapper

module Ast_mapper: sig .. end

-ppx 重写器的接口

-ppx 重写器是一个程序,它接收一个序列化后的抽象语法树,并输出另一个可能经过修改的抽象语法树。此模块封装了编译器和 -ppx 重写器之间的接口,处理序列化格式、命令行标志的转发以及状态的存储等细节。

Ast_mapper.mapper 使用开放递归启用 AST 重写。一个典型的映射器将基于 Ast_mapper.default_mapper,一个深度恒等映射器,并将回退到它来处理它不修改的语法。例如

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 (Pconst_integer ("42", None))
      | other -> default_mapper.expr mapper other; }

let () =
  register "ppx_test" test_mapper

这个 -ppx 重写器,它将表达式中的 [%test] 替换为常量 42,可以使用 ocamlc -o ppx_test -I +compiler-libs ocamlcommon.cma ppx_test.ml 编译。

警告:此模块不稳定,并且是 compiler-libs 的一部分。


一个通用的 Parsetree 映射器

type mapper = {
   attribute : mapper -> Parsetree.attribute -> Parsetree.attribute;
   attributes : mapper -> Parsetree.attribute list -> Parsetree.attribute list;
   binding_op : mapper -> Parsetree.binding_op -> Parsetree.binding_op;
   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;
   constant : mapper -> Parsetree.constant -> Parsetree.constant;
   constructor_declaration : mapper ->
Parsetree.constructor_declaration -> Parsetree.constructor_declaration
;
   directive_argument : mapper ->
Parsetree.directive_argument -> Parsetree.directive_argument
;
   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_substitution : mapper ->
Parsetree.module_substitution -> Parsetree.module_substitution
;
   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_declaration : mapper -> Parsetree.open_declaration -> Parsetree.open_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;
   toplevel_directive : mapper ->
Parsetree.toplevel_directive -> Parsetree.toplevel_directive
;
   toplevel_phrase : mapper -> Parsetree.toplevel_phrase -> Parsetree.toplevel_phrase;
   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_exception : mapper -> Parsetree.type_exception -> Parsetree.type_exception;
   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;
}

映射器记录为每个语法类别实现一个“方法”,使用开放递归样式:每个方法都将要应用于语法树中子节点的映射器作为其第一个参数。

val default_mapper : mapper

一个默认映射器,它实现了一个“深度恒等”映射。

将映射器应用于编译单元

val tool_name : unit -> string

可以在 ppx 预处理器中使用,以了解哪个工具正在调用它 "ocamlc""ocamlopt""ocamldoc""ocamldep""ocaml" 等。一些反映命令行选项的全局变量会在调用工具和 ppx 预处理器之间自动同步:Clflags.include_dirsClflags.hidden_include_dirsLoad_pathClflags.open_modulesClflags.for_packageClflags.debug

val apply : source:string -> target:string -> mapper -> unit

将一个映射器(由单元名称参数化)应用于在 source 文件中找到的已转储的语法树,并将结果放入 target 文件中。映射器的 structuresignature 字段将应用于实现或接口。

val run_main : (string list -> mapper) -> unit

调用入口点,用于从一个映射器实现一个独立的 -ppx 重写器,由命令行参数进行参数化。当前单元名称可以通过 Location.input_name 获取。此函数实现了对未捕获异常的正确错误报告。

注册 API

val register_function : (string -> (string list -> mapper) -> unit) ref
val register : string -> (string list -> mapper) -> unit

应用 register_function。默认行为是立即运行映射器,从进程命令行获取参数。这是为了支持将映射器链接为独立可执行文件的场景。

可以覆盖 register_function 来定义“-ppx 驱动程序”,这些驱动程序将多个映射器组合到单个进程中。通常,驱动程序首先将 register_function 定义为自定义实现,然后让 ppx 重写器(静态或动态链接)自行注册,然后运行所有或其中一些重写器。也可以让 -ppx 驱动程序仅将重写器应用于 AST 的特定部分。

register 的第一个参数是 ppx 驱动程序要使用的符号名称。

编写映射器的便捷函数

val map_opt : ('a -> 'b) -> 'a option -> 'b option
val extension_of_error : Location.error -> Parsetree.extension

将错误编码为一个“ocaml.error”扩展节点,该节点可以插入到生成的语法树中。编译器将负责报告错误。

val attribute_of_warning : Location.t -> string -> Parsetree.attribute

将警告消息编码为一个“ocaml.ppwarning”属性,该属性可以插入到生成的语法树中。编译器将负责报告警告。

调用外部映射器的辅助函数

val add_ppx_context_str : tool_name:string -> Parsetree.structure -> Parsetree.structure

从当前环境中提取信息并将其编码为一个属性,该属性将被附加到结构项列表的前面,以便将信息传递给外部处理器。

val add_ppx_context_sig : tool_name:string -> Parsetree.signature -> Parsetree.signature

add_ppx_context_str 相同,但用于签名。

val drop_ppx_context_str : restore:bool -> Parsetree.structure -> Parsetree.structure

从结构中删除 ocaml.ppx.context 属性。如果 restore 为真,则还恢复当前进程中的关联数据。

val drop_ppx_context_sig : restore:bool -> Parsetree.signature -> Parsetree.signature

drop_ppx_context_str 相同,但用于签名。

Cookie

Cookie 用于在从 OCaml 顶层(或支持 Cookie 的其他工具)调用时,将信息从一个 ppx 处理器传递到其自身的进一步调用。

val set_cookie : string -> Parsetree.expression -> unit
val get_cookie : string -> Parsetree.expression option