File: driver.ml

package info (click to toggle)
ppxlib 0.37.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,804 kB
  • sloc: ml: 66,587; sh: 103; makefile: 40; python: 36
file content (67 lines) | stat: -rw-r--r-- 2,200 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
open Ppxlib

let payload : unit -> (structure_item, label list -> 'a, 'a) Ast_pattern.t =
 fun () ->
  Ast_pattern.(
    pstr_eval (elist (pexp_constant (pconst_string __ drop drop))) drop)

let make_payload ~loc labels =
  let open Ast_builder.Make (struct
    let loc = loc
  end) in
  pstr_eval (elist (List.map estring labels)) []

let expand ~loc ident recurse =
  let open Ast_builder.Make (struct
    let loc = loc
  end) in
  let ident =
    Located.mk
      (match ident with
      | Lident x -> Lident (x ^ "x")
      | _ -> Location.raise_errorf ~loc "ident must be simple")
  in
  match recurse with
  | [] -> pexp_ident ident
  | "%ext" :: recurse ->
      pexp_extension
        ( Located.mk "ext",
          PStr [ pstr_eval (pexp_ident ident) []; make_payload ~loc recurse ] )
  | "@attr" :: recurse ->
      {
        pexp_desc = Pexp_ident ident;
        pexp_attributes =
          [
            attribute ~name:(Located.mk "attr")
              ~payload:(PStr [ make_payload ~loc recurse ]);
          ];
        pexp_loc = loc;
        pexp_loc_stack = [];
      }
  | hd :: _ -> Location.raise_errorf ~loc "invalid rewrite: %s" hd

let () =
  Driver.register_transformation "recursive"
    ~rules:
      [
        Context_free.Rule.extension
          (Extension.V3.declare "ext" Extension.Context.expression
             Ast_pattern.(
               pstr (pstr_eval (pexp_ident __) drop ^:: payload () ^:: nil))
             (fun ~ctxt ident recurse ->
               let loc = Expansion_context.Extension.extension_point_loc ctxt in
               let loc = { loc with loc_ghost = true } in
               expand ~loc ident recurse));
        Context_free.Rule.attr_replace "attr" Extension.Context.expression
          (Attribute.declare "attr" Attribute.Context.Expression
             Ast_pattern.(pstr (payload () ^:: nil))
             (fun x -> x))
          (fun ~ctxt:_ x recurse ->
            match x.pexp_desc with
            | Pexp_ident ident -> expand ~loc:x.pexp_loc ident.txt recurse
            | _ ->
                Location.raise_errorf ~loc:x.pexp_loc
                  "rewrite must be applied to an identifier");
      ]

let () = Driver.standalone ()