-
Notifications
You must be signed in to change notification settings - Fork 98
/
test.ml
142 lines (120 loc) · 3.88 KB
/
test.ml
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
open Ppxlib
(* Generates a [let derived_<type_name> = "ok"] or a
[let derived_<type_name> = "uninterpreted extension in input"] if
the type manifest is an uninterpreted extension. *)
let deriver =
let binding ~loc type_name expr =
let var_name = "derived_" ^ type_name in
let pat = Ast_builder.Default.ppat_var ~loc {txt = var_name; loc} in
let vb = Ast_builder.Default.value_binding ~loc ~pat ~expr in
[Ast_builder.Default.pstr_value ~loc Nonrecursive [vb]]
in
let str_type_decl =
Deriving.Generator.V2.make_noarg
(fun ~ctxt (_rec_flag, type_decls) ->
let loc = Expansion_context.Deriver.derived_item_loc ctxt in
match type_decls with
| { ptype_manifest = Some {ptyp_desc = Ptyp_extension _; _}
; ptype_name = {txt; _}; _}::_ ->
binding ~loc txt [%expr "uninterpreted extension in input"]
| {ptype_name = {txt; _}; _}::_ ->
binding ~loc txt [%expr "ok"]
| [] -> assert false)
in
Deriving.add ~str_type_decl "derived"
[%%expect{|
val deriver : Deriving.t = <abstr>
|}]
(* Generates a [type t = int] *)
let gen_type_decl =
Extension.V3.declare
"gen_type_decl"
Extension.Context.structure_item
Ast_pattern.(pstr nil)
(fun ~ctxt ->
let loc = Expansion_context.Extension.extension_point_loc ctxt in
[%stri type t = int])
|> Context_free.Rule.extension
let () = Driver.register_transformation ~rules:[gen_type_decl] "gen_type_decl"
[%%expect{|
val gen_type_decl : Context_free.Rule.t = <abstr>
|}]
(* You cannot attach attributes to structure item extension points *)
[%%gen_type_decl]
[@@deriving derived]
[%%expect{|
Line _, characters 3-19:
Error: Attributes not allowed here
|}]
(* Generates a [type t = int[@@deriving derived]] *)
let gen_type_decl_with_derived =
Extension.V3.declare
"gen_type_decl_with_derived"
Extension.Context.structure_item
Ast_pattern.(pstr nil)
(fun ~ctxt ->
let loc = Expansion_context.Extension.extension_point_loc ctxt in
[%stri type t = int[@@deriving derived]])
|> Context_free.Rule.extension
let () =
Driver.register_transformation
~rules:[gen_type_decl_with_derived]
"gen_type_decl_with_derived"
[%%expect{|
val gen_type_decl_with_derived : Context_free.Rule.t = <abstr>
|}]
(* Attributes rule must be applied in code generated by a structure item
extension *)
[%%gen_type_decl_with_derived]
[%%expect{|
type t = int
val derived_t : string = "ok"
|}]
let gen_inline_type_decls_with_derived =
Extension.V3.declare_inline
"gen_inline_type_decls_with_derived"
Extension.Context.structure_item
Ast_pattern.(pstr nil)
(fun ~ctxt ->
let loc = Expansion_context.Extension.extension_point_loc ctxt in
[%str
type t = int[@@deriving derived]
type u = float[@@deriving derived]])
|> Context_free.Rule.extension
let () =
Driver.register_transformation
~rules:[gen_inline_type_decls_with_derived]
"gen_inline_type_decls_with_derived"
[%%expect{|
val gen_inline_type_decls_with_derived : Context_free.Rule.t = <abstr>
|}]
(* That also stands for inline extension rules *)
[%%gen_inline_type_decls_with_derived]
[%%expect{|
type t = int
val derived_t : string = "ok"
type u = float
val derived_u : string = "ok"
|}]
let id =
Extension.V3.declare
"id"
Extension.Context.core_type
Ast_pattern.(ptyp __)
(fun ~ctxt:_ core_type -> core_type)
|> Context_free.Rule.extension
let () = Driver.register_transformation ~rules:[id] "id"
[%%expect{|
val id : Context_free.Rule.t = <abstr>
|}]
(* Nodes with attributes are expanded before attribute-based, inline
code generation rules are applied.
In this below, the `[[%id: int]]` is interpreted before the deriver
is applied, meaning it can't see this extension point in its expand
function argument. *)
type t = [%id: int]
[@@deriving derived]
[%%expect{|
type t = int
val derived_t : string = "ok"
|}]