Как обойти типизированное абстрактное синтаксическое дерево в компиляторе OCaml
Я пытаюсь сбросить информацию о типе всех идентификаторов в проекте OCaml, в основном это то же самое, что и обход типизированного абстрактного синтаксического дерева (https://github.com/ocaml/ocaml/blob/trunk/typing/typedtree.mli ). поскольку я новичок в кодовой базе компилятора OCaml, я не уверен, предоставляет ли компилятор API, чтобы мы могли легко написать плагин для выполнения этой работы, или нам нужно взломать код компилятора? Кроме того, как это взаимодействует с OCamlbuild? Спасибо за любые советы и подсказки.
2 ответа:
Предполагая, что вы уже получили типизированный AST типа
Классический способ - это просто написать большую рекурсивную функцию, чтобы самостоятельно пройти АСТ. Но теперь есть модульstructure
каким-то образом.TypedtreeIter
, доступный в исходном коде компилятора OCaml, и он открыт для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_*
рекурсивно и возвращает модуль с кучей итераторы.DefaultIteratorArgument
- это модуль, в которомenter_*
иexit_*
ничего не делают. Ваш модульIteratorArgument
должен включать в себяDefaultIteratorArgument
, чтобы наследовать это поведение по умолчанию, а затем реализовать только те части, которые делают что-то особенное.Если вы хотите не только обойти типизированные AST, но и изменить некоторую их часть, используйте
TypedtreeMap
вместоTypedtreeIter
. Есть небольшой примерTypedtreeMap
на https://bitbucket.org/camlspotter/compiler-libs-hack/src/340072a7c14cbce624b98a57bf8c4c6509c40a31/overload/mod.ml?at=default.(я не использую ocamlbuild, поэтому я не могу помочь этому пункту.)
OCaml предоставляет свой собственный компилятор в виде библиотеки с именем
Плохая новость заключается в том, что она не задокументирована. Я бы предложил вам использоватьcompiler-libs
. В нем есть все, что позволяет перейти от конкретного синтаксиса к исполняемому, со всеми промежуточными шагами под вашим контролем, включая typedtree, конечно.utop
илиmerlin
для изучения этой библиотеки.Вам не нужно ничего особенного делать с ocamlbuild, чтобы использовать
compiler-libs
, это обычная библиотека.