如何在 OCaml 编译器中遍历类型化抽象语法树
How to traverse typed abstract syntax tree in OCaml compiler
我正在尝试转储OCaml 项目中所有标识符的类型信息,基本上它与遍历类型化抽象语法树相同(https://github.com/ocaml/ocaml/blob/trunk/typing/typedtree.mli)。由于我是 OCaml 编译器代码库的新手,我不确定编译器是否提供了 api,以便我们可以轻松编写插件来完成这项工作,或者我们必须破解编译器代码?另外,这如何与 OCamlbuild 交互?感谢您的任何提示或建议。
OCaml 提供自己的编译器作为名为 compiler-libs
的库。它拥有一切,允许从具体语法转向可执行,所有中间步骤都在您的控制之下,当然包括 typedtree。
坏消息是它没有记录在案。我建议您使用 utop
或 merlin
来探索这个图书馆。
您不需要对 ocamlbuild 做任何特殊操作即可使用 compiler-libs
,它是一个常规库。
假设您已经以某种方式获得了 structure
类型的类型化 AST。
经典的方式就是自己写一个大的递归函数遍历AST
但是现在 OCaml 编译器源代码中有可用的模块 TypedtreeIter
,并且它暴露给 compiler-libs
。对于简单的遍历,这很方便。
TypedtreeIter
提供了一个仿函数来在类型化的 AST 上构建您自己的迭代器。这是一个非常简单的示例,用于打印所有模式标识符及其类型:
(* ocamlfind ocamlc -package compiler-libs.common -c example.ml *)
open Typedtree
open TypedtreeIter
module MyIteratorArgument = struct
include DefaultIteratorArgument
let enter_pattern p = match p.pat_desc with
| Tpat_var (id, _) ->
Format.printf "@[<2>%s@ : %a@]@."
(Ident.name id)
Printtyp.type_scheme p.pat_type
| _ -> ()
end
module Iterator = TypedtreeIter.MakeIterator(MyIteratorArgument)
模块类型 TypedtreeIter.IteratorArgument
是指定迭代器对每个 AST 构造执行的操作。您有两点来执行您的工作:遍历何时进入构造以及何时退出构造。例如,对于 pattern
,您有 enter_pattern
和 exit_pattern
。您无需担心递归遍历本身:这是函子 MakeIterator
的工作。给出一个 IteratorArgument
模块,它递归地连接所有 enter_*
和 exit_*
和 returns 一个带有一堆迭代器的模块。
通常你只对 AST 的某些部分感兴趣而想跳过其他部分。 DefaultIteratorArgument
是一个 enter_*
和 exit_*
什么都不做的模块。您的 IteratorArgument
模块应包含 DefaultIteratorArgument
以继承此默认行为,然后仅实现执行特殊操作的部分。
如果您不仅要遍历类型化 AST,还要修改其中的某些部分,请使用 TypedtreeMap
而不是 TypedtreeIter
。在 https://bitbucket.org/camlspotter/compiler-libs-hack/src/340072a7c14cbce624b98a57bf8c4c6509c40a31/overload/mod.ml?at=default.
有一个 TypedtreeMap
的小例子
(我没有使用ocamlbuild,所以我无能为力。)
我正在尝试转储OCaml 项目中所有标识符的类型信息,基本上它与遍历类型化抽象语法树相同(https://github.com/ocaml/ocaml/blob/trunk/typing/typedtree.mli)。由于我是 OCaml 编译器代码库的新手,我不确定编译器是否提供了 api,以便我们可以轻松编写插件来完成这项工作,或者我们必须破解编译器代码?另外,这如何与 OCamlbuild 交互?感谢您的任何提示或建议。
OCaml 提供自己的编译器作为名为 compiler-libs
的库。它拥有一切,允许从具体语法转向可执行,所有中间步骤都在您的控制之下,当然包括 typedtree。
坏消息是它没有记录在案。我建议您使用 utop
或 merlin
来探索这个图书馆。
您不需要对 ocamlbuild 做任何特殊操作即可使用 compiler-libs
,它是一个常规库。
假设您已经以某种方式获得了 structure
类型的类型化 AST。
经典的方式就是自己写一个大的递归函数遍历AST
但是现在 OCaml 编译器源代码中有可用的模块 TypedtreeIter
,并且它暴露给 compiler-libs
。对于简单的遍历,这很方便。
TypedtreeIter
提供了一个仿函数来在类型化的 AST 上构建您自己的迭代器。这是一个非常简单的示例,用于打印所有模式标识符及其类型:
(* ocamlfind ocamlc -package compiler-libs.common -c example.ml *)
open Typedtree
open TypedtreeIter
module MyIteratorArgument = struct
include DefaultIteratorArgument
let enter_pattern p = match p.pat_desc with
| Tpat_var (id, _) ->
Format.printf "@[<2>%s@ : %a@]@."
(Ident.name id)
Printtyp.type_scheme p.pat_type
| _ -> ()
end
module Iterator = TypedtreeIter.MakeIterator(MyIteratorArgument)
模块类型 TypedtreeIter.IteratorArgument
是指定迭代器对每个 AST 构造执行的操作。您有两点来执行您的工作:遍历何时进入构造以及何时退出构造。例如,对于 pattern
,您有 enter_pattern
和 exit_pattern
。您无需担心递归遍历本身:这是函子 MakeIterator
的工作。给出一个 IteratorArgument
模块,它递归地连接所有 enter_*
和 exit_*
和 returns 一个带有一堆迭代器的模块。
通常你只对 AST 的某些部分感兴趣而想跳过其他部分。 DefaultIteratorArgument
是一个 enter_*
和 exit_*
什么都不做的模块。您的 IteratorArgument
模块应包含 DefaultIteratorArgument
以继承此默认行为,然后仅实现执行特殊操作的部分。
如果您不仅要遍历类型化 AST,还要修改其中的某些部分,请使用 TypedtreeMap
而不是 TypedtreeIter
。在 https://bitbucket.org/camlspotter/compiler-libs-hack/src/340072a7c14cbce624b98a57bf8c4c6509c40a31/overload/mod.ml?at=default.
TypedtreeMap
的小例子
(我没有使用ocamlbuild,所以我无能为力。)