使用ppx\U驱动程序的AST转换(使用ocaml\U current\U AST注册\U转换)有什么好的使用示例吗?
tl;dr我正试图使用使用ppx\U驱动程序的AST转换(使用ocaml\U current\U AST注册\U转换)有什么好的使用示例吗?,ocaml,abstract-syntax-tree,ppx,Ocaml,Abstract Syntax Tree,Ppx,tl;dr我正试图使用AST\u映射器和ppx\u驱动程序来生成一个源转换二进制文件。我不知道如何在AST\u映射程序docs中获取供ppx\u驱动程序使用的示例。有没有关于如何使用Ppx驱动程序的好例子。使用ocaml\u current\u ast注册转换 我正在尝试移植该示例以与ppx\u驱动程序兼容。具体地说,我希望创建一个二进制文件,它将源代码作为输入,使用这个测试映射器转换源代码,然后输出转换后的源代码。不幸的是,只接受Ocaml AST作为输入(并可能将其作为输出生成)。这是不可取
AST\u映射器
和ppx\u驱动程序
来生成一个源转换二进制文件。我不知道如何在AST\u映射程序docs中获取供ppx\u驱动程序使用的示例。有没有关于如何使用Ppx驱动程序的好例子。使用ocaml\u current\u ast注册转换
我正在尝试移植该示例以与ppx\u驱动程序
兼容。具体地说,我希望创建一个二进制文件,它将源代码作为输入,使用这个测试映射器转换源代码,然后输出转换后的源代码。不幸的是,只接受Ocaml AST作为输入(并可能将其作为输出生成)。这是不可取的,因为我不希望必须使用-dsource
通过ocamlc
来运行此命令才能获得输出
以下是我移植此功能的最佳尝试:
测试映射器.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"
let x _ = [%test]
需要注意的几点:
- 文档中的示例并非开箱即用(在引入
ppx\u驱动程序之前):Const\u int 42
必须替换为Ast\u helper.Const.int 42
- 出于某种原因,
test\u映射器
是Parsetree.structure->mapper
。(我不清楚为什么递归转换需要结构来创建映射器,但没关系。)但是,这种类型不是Ppx\u驱动程序所期望的类型。请使用\u ocaml\u current\u ast
注册转换。因此,我编写了一个草率的包装器test\u transformation
,以使typechecker满意(这是一个松散的基础,因此在理论上它应该可以工作)
不幸的是,在将其编译为二进制文件后:
ocamlfind ocamlc -predicates ppx_driver -o test_mapper test_mapper.ml -linkpkg -package ppx_driver.runner
并在示例文件上运行它:
sample.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"
let x _ = [%test]
以下是:
./test_mapper sample.ml
我没有看到任何转换发生(示例文件是逐字返回的)。更重要的是,我在代码中留下的日志ppritast.expression
没有打印任何内容,这表明我的映射程序从未访问过任何内容
我能在野外找到的所有例子都是由Jane Street(她写了ppx.*
)开源的,似乎要么没有注册它们的转换(也许有一些神奇的检测正在我脑中进行),要么它们使用了什么(这似乎不完整,对我的实际用例也不起作用——但出于这个问题的目的,我正试图让事情保持普遍适用性)
有没有好的例子可以说明如何正确地执行此操作?为什么不使用my transformation?如果您想使用单个模块制作一个独立的重写器,您需要添加
let () = Ppx_driver.standalone ()
要运行重写器并链接到ppx\u驱动程序而不是ppx\u驱动程序。runner
:ppx\u驱动程序。runner
在加载驱动程序后立即运行驱动程序,因此在注册转换之前。还要注意,您至少应该指定特定的Ast版本并使用ppx\u驱动程序。注册转换不要使用Ppx\u驱动程序。使用\u current\u ocaml\u ast
注册\u transformation\u,否则使用Ppx\u驱动程序
没有什么意义,而不是使用compiler libs
和Pparse
模块手工解析。非常感谢!这就成功了!至于指定ast版本和使用register_transformation
,你能对此进行扩展吗?正如我在问题末尾提到的,我在研究中看到了这两个方面,但我不确定如何进行(我找不到文档,只是未注释的使用示例).register\u转换
看起来像是使用了~规则
,它使用了Ppx\u核心。ContextFree
,根据其源代码中的注释(在我的答案中链接)是不完整的。您的建议是什么?可以通过打开AST\u 406
(或任何其他版本)来指定AST版本打开AST相关模块,然后使用OMP提供的转换器来回转换为ppx_驱动程序使用的AST版本之前:Migrate_parsetree_versions.Convert(AST_406)(AST_404).copy\u mapper
。然后,可以使用register\u transformation
的impl
参数,规则参数更受欢迎,因为规则对每个重写器的操作进行了精确描述,从而更容易编写多个重写器。(另外,请注意,OMP本身有一个驱动程序).Ah,那很方便。我肯定会走那条路,但我的特定应用程序不太适合。register\u转换
似乎只做structure->structure
和interface->interface
(这对源代码转换很有意义)。但是,我希望做interface->structure
(为接口创建存根),所以看起来我必须以一种无法很好地进行版本控制的方式深入研究AST内部。谢谢您的帮助!