Тут -- информация про camlp4, синтаксический препроцессор, см. также StreamParsers.
API документация для Camlp4 3.12 доступна на сайте camlunity.
$ ocaml
Objective Caml version 3.11.1
# use "topfind";;
# #camlp4o;;
# open Camlp4.PreCast;;
# let expr = Gram.Entry.mk "expr";;
val expr : '_a Camlp4.PreCast.Gram.Entry.t = <abstr>
# EXTEND Gram
expr: [ [ x = expr; "+"; y = expr -> x + y
| e = INT -> int_of_string e ] ];
END;;
- : unit = ()
# let _loc = Loc.ghost;;
val _loc : Camlp4.PreCast.Loc.t = <abstr>
# Gram.parse_string expr _loc "1+3";;
- : int = 4
Quotations всегда пишите в revised синтаксисе, иначе могут вылезти трудноуловимые неочевидные косяки (или баги в самом Camlp4), основной код расширения можно писать и в original. См. например PR#5231
Пример командной строки для сборки расширения:
$ ocamlfind ocamlc -c -package camlp4.quotations.r,camlp4.extend -syntax camlp4o pa_xxx.ml
-
При компиляции, препроцессору можно передать дополнительные опции: ``-pp опции`
-
Используя ocamlfind, следует использовать
-ppopt
для передачи дополнительных ключей препроцессору -
Ключ
-no_quot
отключает обработку quotations, позволяя, например, использовать в коде<<
.
Кто-нибудь, опишите необходимую магию?
DEFINE, IFDEF, etc
ocamlfind -package camlp4.macro
Переменная окружения CAMLP4_DEBUG
Но см. PR#5120
$ echo 'let a = 2' > q.ml
$ camlp4o -filter Camlp4AstLifter q.ml
let loc = Loc.ghost
in
Ast.StVal (loc, Ast.BFalse,
Ast.BiEq (loc, Ast.PaId (loc, Ast.IdLid (loc, "a")),
Ast.ExInt (loc, "2")))
$ ocaml
Objective Caml version 3.12.1
# #camlp4o;;
Camlp4 Parsing version 3.12.1
# open Camlp4.PreCast;;
# Syntax.parse_implem Loc.ghost (Stream.of_string "2+2");;
- : Camlp4.PreCast.Syntax.Ast.str_item =
Camlp4.PreCast.Syntax.Ast.StExp (<abstr>,
Camlp4.PreCast.Syntax.Ast.ExApp (<abstr>,
Camlp4.PreCast.Syntax.Ast.ExApp (<abstr>,
Camlp4.PreCast.Syntax.Ast.ExId (<abstr>,
Camlp4.PreCast.Syntax.Ast.IdLid (<abstr>, "+")),
Camlp4.PreCast.Syntax.Ast.ExInt (<abstr>, "2")),
Camlp4.PreCast.Syntax.Ast.ExInt (<abstr>, "2")))
$ ocaml
Objective Caml version 3.11.2
# #use "topfind";;
- : unit = ()
# #camlp4o;;
Camlp4 Parsing version 3.11.2
# #require "camlp4.quotations";;
# open Camlp4.PreCast;; (* Будем использовать дефолтные модули Syntax Loc итд *)
# module P = Camlp4.Printers.OCaml.Make(Syntax);; (* Модуль для вывода в оригинальном синтаксисе *)
# let p = new P.printer ();; (* Создаём принтер *)
val p : P.printer = <obj>
# let _loc = Loc.ghost;; (* Пустой location для экспериментов *)
val _loc : Camlp4.PreCast.Loc.t = <abstr>
# let typ = <:ctyp< [ A | B ] >> in Format.printf "type is : %a\n%a\n" p#ctyp typ p#sig_item <:sig_item< type a = $typ$; >>;; (* содержимое quotation'ов в revised, а выводим в original! *)
type is : | A | B
type a = | A | B;;
- : unit = ()