代码之家  ›  专栏  ›  技术社区  ›  Bailey Parker

使用ppx\U驱动程序进行AST转换(使用ocaml\U current\U AST进行register\U transformation\u)有什么好的用法示例吗?

  •  2
  • Bailey Parker  · 技术社区  · 7 年前

    tl;博士,我正在尝试使用 AST_mapper ppx_driver . 我不知道如何在 AST\U映射器 要使用的文档 ppx\U驱动程序 . 有没有关于如何使用的好例子 Ppx_driver.register_transformation_using_ocaml_current_ast ?

    我正在尝试移植这个示例 AST_mapper in the docs 与兼容 ppx\U驱动程序 . 具体来说,我希望创建一个二进制文件,该文件将源代码作为输入,使用此测试映射器转换源代码,然后输出转换后的源代码。不幸的是 default main provided by Ast_mapper 仅接受Ocaml AST作为输入(并可能将其作为输出生成)。这是不受欢迎的,因为我不想把这件事做完 ocamlc 具有 -dsource 获取我的输出。

    以下是我移植此功能的最佳尝试:

    test\u映射器。毫升

    open Asttypes
    open Parsetree
    open Ast_mapper
    
    let test_mapper argv =
      { default_mapper with
        expr = fun mapper expr ->
          Pprintast.expression Format.std_formatter expr;
          match expr with
          | { pexp_desc = Pexp_extension ({ txt = "test" }, PStr [])} ->
            Ast_helper.Exp.constant (Ast_helper.Const.int 42)
          | other -> default_mapper.expr mapper other; }
    
    let test_transformation ast =
      let mapper = (test_mapper ast) in
        mapper.structure mapper ast
    
    let () =
      Ppx_driver.register_transformation_using_ocaml_current_ast
        ~impl:test_transformation
        "test_transformation"
    

    需要注意的几点:

    • 文档中的示例不是现成的(在介绍之前 ppx\U驱动程序 ): Const_int 42 必须替换为 Ast_helper.Const.int 42
    • 出于某种原因 test_mapper Parsetree.structure -> mapper . (我不清楚为什么递归转换需要结构来创建映射器,但没关系。)但是,这种类型不是什么 Ppx\U驱动程序。使用\u ocaml\u current\u ast注册\u transformation\u 期望值。所以我写了一个草率的包装 test_transformation 使typechecker满意(这是基于 how Ast_mapper.apply_lazy appears to apply a mapper to an AST 因此从理论上讲,这应该是可行的)

    不幸的是,在将其编译为二进制文件后:

    ocamlfind ocamlc -predicates ppx_driver -o test_mapper test_mapper.ml -linkpkg -package ppx_driver.runner
    

    并在示例文件上运行它:

    样品毫升

    let x _ = [%test]
    

    具有以下功能:

    ./test_mapper sample.ml
    

    我没有看到任何转换发生(示例文件是逐字返回的)。更重要的是,日志记录 Pprintast.expression 我在代码中留下的没有打印任何内容,这对我来说意味着我的映射器从未访问过任何内容。

    我在野外找到的所有例子都是由Jane Street(他写道 ppx_* )而且似乎要么没有注册他们的转换(也许有一些魔法检测正在进行,这在我的头上),要么如果他们注册了 they use Ppx_driver.register_transformation ~rules 其中使用 Ppx_core.ContextFree (这似乎不完整,对我的实际用例也不起作用——但就这个问题而言,我正试图保持事物的普遍适用性)。

    有没有什么好的例子可以说明如何正确地做到这一点?为什么不 ppx\U驱动程序 使用我的转换?

    1 回复  |  直到 7 年前
        1
  •  1
  •   octachron    7 年前

    如果要使用单个模块制作独立的重写器,需要添加

    let () = Ppx_driver.standalone ()
    

    运行重写器并链接 ppx_driver 而不是 ppx_driver.runner : ppx\U驱动程序。跑步者 在加载驱动程序后立即运行驱动程序,因此在注册转换之前。还要注意,您至少应该指定特定的Ast版本和使用 Ppx_driver.register_transformation 而不是 Ppx_driver.register_transformation_using_current_ocaml_ast 否则,使用 ppx\U驱动程序 而不是用 compiler-libs 以及 Pparse 单元