ppx_driver (register_transformation_using_ocaml_current_ast) 的 AST 转换有什么好的用法示例?
Any good usage examples of an AST transformation with ppx_driver (register_transformation_using_ocaml_current_ast)?
tl;dr 我正在尝试使用 AST_mapper
和 ppx_driver
制作源转换二进制文件。我不知道如何获取 AST_mapper
文档中的示例以供 ppx_driver
使用。有没有关于如何使用 Ppx_driver.register_transformation_using_ocaml_current_ast
的好例子?
我正在尝试移植示例 AST_mapper
in the docs to be compatible with ppx_driver
. Specifically, I'm looking to create a binary that takes source as input, transforms the source using this test mapper, and then outputs the transformed source. Unfortunately, the default main provided by Ast_mapper
只接受 Ocaml AST 作为输入(并且可能将其作为输出生成)。这是不可取的,因为我不想通过 ocamlc
和 -dsource
运行 来获得我的输出。
这是我移植这个的最佳尝试:
test_mapper.ml
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_driver
之前):Const_int 42
必须替换为 Ast_helper.Const.int 42
- 由于某种原因
test_mapper
是 Parsetree.structure -> mapper
。 (我不清楚为什么递归转换需要结构来创建映射器,但没关系。)但是,这种类型不是 Ppx_driver.register_transformation_using_ocaml_current_ast
所期望的。所以我写了一个草率的包装器 test_transformation
来让类型检查器满意(它松散地基于 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
并且运行将它放在示例文件中:
sample.ml
let x _ = [%test]
具有以下内容:
./test_mapper sample.ml
我没有看到任何转换发生(示例文件逐字反省)。更重要的是,我留在代码中的日志记录 Pprintast.expression
没有打印任何东西,这向我表明我的映射器从不访问任何东西。
我在野外找到的所有示例都是 Jane Street(ppx_*
的作者)开源的,并且似乎没有注册他们的转换(也许正在进行一些神奇的检测这让我难以理解)或者如果他们这样做了 they use Ppx_driver.register_transformation ~rules
which uses Ppx_core.ContextFree
(这似乎并不完整并且不适用于我的实际用例 - 但出于这个问题的目的,我试图保持一般适用的东西)。
有没有很好的例子说明如何正确执行此操作?为什么 ppx_driver
不使用我的转换?
如果你想用单个模块做一个独立的重写器,你需要添加
let () = Ppx_driver.standalone ()
到 运行 重写器并链接到 ppx_driver
而不是 ppx_driver.runner
: ppx_driver.runner
运行 驱动程序一旦加载,因此在您的转换被注册之前。另请注意,您至少应该指定一个特定的 Ast 版本并使用 Ppx_driver.register_transformation
而不是 Ppx_driver.register_transformation_using_current_ocaml_ast
否则使用 ppx_driver
而不是使用 [=17= 手动解析几乎没有意义] 和 Pparse
模块。
tl;dr 我正在尝试使用 AST_mapper
和 ppx_driver
制作源转换二进制文件。我不知道如何获取 AST_mapper
文档中的示例以供 ppx_driver
使用。有没有关于如何使用 Ppx_driver.register_transformation_using_ocaml_current_ast
的好例子?
我正在尝试移植示例 AST_mapper
in the docs to be compatible with ppx_driver
. Specifically, I'm looking to create a binary that takes source as input, transforms the source using this test mapper, and then outputs the transformed source. Unfortunately, the default main provided by Ast_mapper
只接受 Ocaml AST 作为输入(并且可能将其作为输出生成)。这是不可取的,因为我不想通过 ocamlc
和 -dsource
运行 来获得我的输出。
这是我移植这个的最佳尝试:
test_mapper.ml
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_driver
之前):Const_int 42
必须替换为Ast_helper.Const.int 42
- 由于某种原因
test_mapper
是Parsetree.structure -> mapper
。 (我不清楚为什么递归转换需要结构来创建映射器,但没关系。)但是,这种类型不是Ppx_driver.register_transformation_using_ocaml_current_ast
所期望的。所以我写了一个草率的包装器test_transformation
来让类型检查器满意(它松散地基于 howAst_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
并且运行将它放在示例文件中:
sample.ml
let x _ = [%test]
具有以下内容:
./test_mapper sample.ml
我没有看到任何转换发生(示例文件逐字反省)。更重要的是,我留在代码中的日志记录 Pprintast.expression
没有打印任何东西,这向我表明我的映射器从不访问任何东西。
我在野外找到的所有示例都是 Jane Street(ppx_*
的作者)开源的,并且似乎没有注册他们的转换(也许正在进行一些神奇的检测这让我难以理解)或者如果他们这样做了 they use Ppx_driver.register_transformation ~rules
which uses Ppx_core.ContextFree
(这似乎并不完整并且不适用于我的实际用例 - 但出于这个问题的目的,我试图保持一般适用的东西)。
有没有很好的例子说明如何正确执行此操作?为什么 ppx_driver
不使用我的转换?
如果你想用单个模块做一个独立的重写器,你需要添加
let () = Ppx_driver.standalone ()
到 运行 重写器并链接到 ppx_driver
而不是 ppx_driver.runner
: ppx_driver.runner
运行 驱动程序一旦加载,因此在您的转换被注册之前。另请注意,您至少应该指定一个特定的 Ast 版本并使用 Ppx_driver.register_transformation
而不是 Ppx_driver.register_transformation_using_current_ocaml_ast
否则使用 ppx_driver
而不是使用 [=17= 手动解析几乎没有意义] 和 Pparse
模块。