Source file attribute_handler_intf.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
open! Stdppx
open! Import
open Language.Typed
module Type = Language.Type
module Definitions = struct
type lookup =
| Preserve_atoms
(** When evaluating, do not expand identifiers into the set they represent. This form
of lookup is used when evaluating set mono and poly attributes for the purposes of
mangling, because we mangle by _names_ of sets, not canonical representations of
their contents. *)
| Expand_atoms_bound_to_sets
(** When evaluating, fully expand all identifiers. This form of lookup is used when
evaluating the right hand side of a non-set binding, since here we wish to bind
the pattern on the left against all values in the set on the right *)
module Binding = struct
type 'a t =
{ pattern : 'a Pattern.t
; expression : ('a, Expression.set) Expression.t Loc.t
; lookup : lookup
}
module Selector = struct
type ('bind, 'select) t =
| Id : ('a, 'a) t (** most bindings *)
| Fst : ('a * 'b, 'a) t (** [[@@alloc (a @ m) = ...]] and similar bindings *)
end
module With_selector = struct
type nonrec ('bind, 'select) t =
{ binding : 'bind t
; selector : ('bind, 'select Type.non_tuple) Selector.t
(** When an item [let lhs = rhs [@@attr pat = (expr1, expr2)]] is evaluated e.g.
on [expr1], the expression gets evaluated to a [Value.t]. A selector
determines what part of the [value] to use to mangle [lhs]. This is used to
enable [[@@alloc (a @ m) = ...]] to mangle only based on [a]. *)
}
type 'select packed = P : (_, 'select) t -> 'select packed
end
end
module Poly = struct
type t =
| Poly :
'select Type.non_tuple Axis.t * 'select Binding.With_selector.packed list
-> t
end
module Mono = struct
type t = Expression.Basic.packed Loc.t list Explicitness.With.t Axis.Map.t
end
type poly_w =
[ `value_binding
| `value_description
| `module_binding
| `module_declaration
| `type_declaration
| `module_type_declaration
| `include_infos
]
type mono_w =
[ `expression
| `module_expr
| `core_type
| `module_type
]
type exclave_if_w = [ `expression ]
type zero_alloc_if_w =
[ `expression
| `value_binding
| `value_description
]
type any_w =
[ poly_w
| mono_w
| zero_alloc_if_w
]
module Context = struct
type ('a, 'w) t =
| Expression : (expression, [> `expression ]) t
| Module_expr : (module_expr, [> `module_expr ]) t
| Core_type : (core_type, [> `core_type ]) t
| Module_type : (module_type, [> `module_type ]) t
| Value_binding : (value_binding, [> `value_binding ]) t
| Value_description : (value_description, [> `value_description ]) t
| Module_binding : (module_binding, [> `module_binding ]) t
| Module_declaration : (module_declaration, [> `module_declaration ]) t
| Type_declaration : (type_declaration, [> `type_declaration ]) t
| Module_type_declaration :
(module_type_declaration, [> `module_type_declaration ]) t
| Include_infos :
((module_expr, module_type) Either.t include_infos, [> `include_infos ]) t
type 'a poly = ('a, poly_w) t
type 'a mono = ('a, mono_w) t
type 'a zero_alloc_if = ('a, zero_alloc_if_w) t
type 'a any = ('a, any_w) t
end
module Exclave_if = struct
module Reason = struct
type t =
| May_return_local
| May_return_regional
| Will_return_unboxed
end
(** Represents attributes that introduce conditional exclaves into the code. [loc] is
the location of the attribute's payload. [expr] is the expression (mode, alloc,
etc.) to compare against to determine whether to apply [[@@exclave_if_*]].
[reasons] is the list of reasons for applying unconditionally, out of a list of
pre-defined reasons. *)
type ('typ, 'reasons) t =
{ expr : ('typ, Expression.singleton) Expression.t Loc.t
; reasons : 'reasons
}
end
module Zero_alloc_if = struct
(** Represents attributes that optionally annotate code as zero-alloc. [loc] is the
location of the attribute's payload. [expr] is the expression (mode, alloc, etc.)
to compare against to determine whether to apply [[@@zero_alloc]]. [args] is the
arguments to be given to the [[@@zero_alloc]] attribute. *)
type 'a t =
{ loc : location
; expr : ('a, Expression.singleton) Expression.t Loc.t
; args : expression list
}
end
end
module type Attribute_handler = sig
include module type of struct
include Definitions
end
module Binding : sig
include module type of struct
include Binding
end
module Selector : sig
include module type of struct
include Selector
end
val select : ('bind, 'select) t -> 'bind Value.t -> 'select Value.t
end
end
module Context : sig
include module type of struct
include Context
end
type 'w packed = private T : (_, 'w) t -> 'w packed [@@unboxed]
val poly_to_any : 'a poly -> 'a any
val mono_to_any : 'a mono -> 'a any
val zero_alloc_if_to_any : 'a zero_alloc_if -> 'a any
val location : ('a, 'b) t -> 'a -> Location.t
end
(** A [('w, 'b) t] is a handler that knows how to consume a particular attribute on ['w]
syntax items, and produce back ['b] values. Note: if the attribute isn't present,
the handler will return some default ['b], whether that be [None] (if ['b] is
[_ option]) or some semantic default for the given ['b]. *)
type ('w, 'b) t
(** [consume t ctx item] runs the handler [t] in the context [ctx] on [item]. The
handler [t] strips its corresponding attributes from [item] in addition to producing
its output. *)
val consume : ('w, 'b) t -> ('a, 'w) Context.t -> 'a -> ('a * 'b, Syntax_error.t) result
(** A map from [('a, 'w) Context.t] to [('a, 'b) Attribute.t]. *)
module Attribute_map : sig
type ('w, 'b) t
val find_exn
: ('w, 'b) t
-> ('a, 'w) Context.t
-> ('a, 'b) Attribute.t Explicitness.Each.t
end
module Poly : module type of struct
include Poly
end
(** A handler for attributes that make definitions/declarations polymorphic. Might
return an [Error _] if the attribute's payload is malformed. Defaults to
[Ok { kinds = None; modes = None }]. *)
val poly : (poly_w, Poly.t Explicitness.With.t list) t
module Mono : sig
include module type of struct
include Mono
end
val contexts : mono_w Context.packed list
type attr :=
( mono_w
, (Expression.Basic.packed Loc.t list, Syntax_error.t) result )
Attribute_map.t
val kind_attr : attr
val kind_set_attr : attr
val mode_attr : attr
val modality_attr : attr
val alloc_attr : attr
end
(** A handler for attributes that mangle identifiers to the correct monomorphized name.
Defaults to [{ kinds = []; modes = [] }]. *)
val mono : (mono_w, Mono.t) t
module Exclave_if : sig
include module type of struct
include Exclave_if
end
module Reason : sig
include module type of struct
include Exclave_if.Reason
end
end
end
(** A handler for attributes that optionally insert [exclave_] markers. We expect to
replace these attributes with mode-polymorphic tailcalls and/or unboxed types. *)
val exclave_if_local
: (exclave_if_w, (Type.mode, Exclave_if.Reason.t list) Exclave_if.t option) t
(** Like {!exclave_if_local}, but for allocation identifiers. *)
val exclave_if_stack : (exclave_if_w, (Type.alloc, unit) Exclave_if.t option) t
module Zero_alloc_if : sig
include module type of struct
include Zero_alloc_if
end
end
(** A handler for attributes that optionally annotate code as zero-alloc. *)
val zero_alloc_if_local : (zero_alloc_if_w, Type.mode Zero_alloc_if.t option) t
(** Like {!zero_alloc_if_local}, but for allocation identifiers. *)
val zero_alloc_if_stack : (zero_alloc_if_w, Type.alloc Zero_alloc_if.t option) t
val with_ : ([ `module_type ], signature option) t
val with_attr : (module_type, (signature, Syntax_error.t) result) Attribute.t
val functor_portable : ([ `module_binding | `module_declaration ], string loc option) t
val functor_stateless : ([ `module_binding | `module_declaration ], string loc option) t
val error_you_can_only_use_one_attribute_per_axis
: loc:location
-> (_, Syntax_error.t) result
module Floating : sig
type poly :=
[ `structure_item
| `signature_item
]
module Context : sig
type ('a, 'w) t =
| Structure_item : (structure_item, [> `structure_item ]) t
| Signature_item : (signature_item, [> `signature_item ]) t
type nonrec 'a poly = ('a, poly) t
val location : ('a, 'b) t -> 'a -> Location.t
end
module Define : sig
type t = Define : 'a Type.non_tuple Binding.t list -> t
end
module Poly : sig
type kind =
| Never_add_mangler
| Always_add_mangler
| Add_mangler_if_more_than_one_elt
(** Behaves like [Always_add_mangler] if the set on the RHS of the binding, when
evaluated with [Expand_atoms_bound_to_sets], has more than one element, and
like [Never_add_mangler] otherwise.
For [Add_mangler_if_more_than_one_elt] specifically, we only permit exactly
one [(_, singleton) Expression.t] on the RHS. Loosely speaking, if the
expression on the RHS contains a [Union], it is probably true that it always
evaluates to a set with more than one element, and the [Always_add_mangler]
version of the attribute should be used instead. *)
type t =
{ bindings : Poly.t
; kind : kind
}
(** Check if the provided ast node is a floating poly template attribute. Does not
mark the attribute as seen. *)
val is_present : ('a, poly) Context.t -> 'a -> bool
end
type t =
| Define of Define.t
| Poly of Poly.t Explicitness.With.t
(** Check if the provided ast node is a floating template attribute, and evaluate its
contents. Marks the attribute as seen. Returns an [Error _] if the payload of the
attribute is malformed or inconsistent. *)
val convert : ('a, poly) Context.t -> 'a -> (t option, Syntax_error.t) result
end
end