Source file mangle.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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
open! Stdppx
open! Import
open Language.Typed
module Type = Language.Type
let rec mangle_value : type a. a Type.non_tuple Value.t -> string =
let group strings = strings |> String.concat ~sep:"_" |> Printf.sprintf "'%s'" in
fun value ->
match value with
| Identifier ident -> ident.ident
| Kind_product kinds ->
kinds |> Nonempty_list.to_list |> List.map ~f:mangle_value |> group
| Kind_mod (kind, modifiers) ->
mangle_value kind
:: "mod"
:: (modifiers
|> Nonempty_list.to_list
|> List.map ~f:mangle_value
|> List.sort_uniq ~cmp:String.compare)
|> group
;;
let concat_with_underscores = String.concat ~sep:"__"
module Suffix = struct
type t = string list loc
let is_empty t = List.is_empty t.txt
let create mono =
let open Explicitness.With.Export in
let axis =
match Axis.Map.find_opt (P axis) mono with
| None -> []
| Some { explicitness; what = manglers } ->
List.fold_right
manglers
~init:Axis.Sub_axis.Map.empty
~f:(fun (Value.Basic.P value as mangler) map ->
Axis.Sub_axis.Map.add_to_list (P (Axis.Sub_axis.of_value value)) mangler map)
|> Axis.Sub_axis.Map.to_list
|> List.concat_map ~f:(fun (_, manglers) ->
match (explicitness : Explicitness.t) with
| Drop_axis_if_all_defaults
when List.for_all manglers ~f:(fun (Value.Basic.P value) ->
match Value.defaultness value with
| Actual_default | Default_for_standard_mangling -> true
| Not_a_default -> false) -> []
| Drop_axis_if_all_defaults | Explicit | Explicit_plus_unmangled ->
List.map manglers ~f:(fun (P value) ->
let mangler = mangle_value value in
match axis with
| Set _ -> Printf.sprintf "''%s''" mangler
| Singleton _ -> mangler))
in
{ txt =
extract (Set Kind)
@ extract (Singleton Kind)
@ extract (Singleton Mode)
@ extract (Singleton Modality)
@ extract (Singleton Alloc)
@ extract (Singleton Synchro)
; loc = Location.none
}
;;
end
let suffix_for_manual_mangling ?modes ?kinds () =
let kind_explicitness, (kinds : jkind_annotation list) =
Option.value kinds ~default:(Explicitness.Drop_axis_if_all_defaults, [])
in
let mode_explicitness, (modes : modes) =
Option.value modes ~default:(Explicitness.Drop_axis_if_all_defaults, [])
in
let open Result.Let_syntax in
let* kinds =
List.map kinds ~f:(fun ({ pjka_loc; _ } as jkind) ->
let* jkind =
Expression.of_parsetree_jkind jkind
|> Result.map_error ~f:(fun { loc; txt } ->
Syntax_error.createf ~loc "%s expected" txt)
in
let+ jkind = Env.eval_singleton Env.initial { txt = jkind; loc = pjka_loc } in
(P jkind : Value.Basic.packed))
|> Result.syntax_errors_of_list
in
let+ modes =
List.map modes ~f:(fun { txt = Mode mode; loc } ->
let+ mode =
Env.eval_singleton
Env.initial
{ txt = Identifier { type_ = Non_tuple Mode; ident = mode }; loc }
in
(P mode : Value.Basic.packed))
|> Result.syntax_errors_of_list
in
let suffix =
Suffix.create
(Axis.Map.of_list
[ ( P (Singleton Kind)
, { Explicitness.With.explicitness = kind_explicitness; what = kinds } )
; ( P (Singleton Mode)
, { Explicitness.With.explicitness = mode_explicitness; what = modes } )
])
in
String.concat ~sep:"__" ("" :: suffix.txt)
;;
let explicitly_drop = Attribute.explicitly_drop
let mangle_error { txt; loc } kind explicitly_drop_method node =
explicitly_drop_method node;
Location.error_extensionf
~loc
"[%%template]: don't know how to mangle this %s (suffix: %s)"
kind
(concat_with_underscores txt)
;;
module Outcome = struct
type t =
| Did_not_mangle
| Mangled
let mangled_either a b =
match a, b with
| Did_not_mangle, Did_not_mangle -> Did_not_mangle
| Did_not_mangle, Mangled | Mangled, Did_not_mangle | Mangled, Mangled -> Mangled
;;
let mangled_any l = List.fold_left ~init:Did_not_mangle ~f:mangled_either l
let did_mangle = function
| Did_not_mangle -> false
| Mangled -> true
;;
end
let t =
object (self)
inherit [Suffix.t, Outcome.t] Ast_traverse.lift_map_with_context as super
method other _ _ = Did_not_mangle
method unit _ () = (), Did_not_mangle
method bool _ b = b, Did_not_mangle
method char _ c = c, Did_not_mangle
method int _ i = i, Did_not_mangle
method int32 _ i = i, Did_not_mangle
method int64 _ i = i, Did_not_mangle
method nativeint _ i = i, Did_not_mangle
method float _ f = f, Did_not_mangle
method array f suffix a =
let res, a =
Array.fold_left_map a ~init:Did_not_mangle ~f:(fun acc x ->
let x, res = f suffix x in
Outcome.mangled_either acc res, x)
in
a, res
method record _ r = r |> List.map ~f:snd |> Outcome.mangled_any
method constr _ _ c = Outcome.mangled_any c
method tuple _ t = Outcome.mangled_any t
method string suffix name =
if Suffix.is_empty suffix
then name, Did_not_mangle
else (
let name =
if String.ends_with ~suffix:"#" name
then concat_with_underscores (String.drop_suffix name 1 :: suffix.txt) ^ "#"
else concat_with_underscores (name :: suffix.txt)
in
name, Mangled)
method! longident suffix =
function
| (Lident _ | Lapply _) as ident -> super#longident suffix ident
| Ldot (path, name) ->
self#string suffix name |> map_fst ~f:(fun name -> Ldot (path, name))
method! location _ loc = loc, Did_not_mangle
method! extension suffix (ext, payload) =
self#loc self#string suffix ext |> map_fst ~f:(fun ext -> ext, payload)
method! expression_desc suffix =
function
| (Pexp_ident _ | Pexp_extension _) as desc -> super#expression_desc suffix desc
| expr_desc ->
( Pexp_extension
(mangle_error suffix "expression" explicitly_drop#expression_desc expr_desc)
, Did_not_mangle )
method! expression suffix expr =
self#expression_desc { suffix with loc = expr.pexp_loc } expr.pexp_desc
|> map_fst ~f:(fun pexp_desc -> { expr with pexp_desc })
method! module_expr_desc suffix =
function
| Pmod_ident _ as desc -> super#module_expr_desc suffix desc
| mod_expr_desc ->
( Pmod_extension
(mangle_error
suffix
"module expression"
explicitly_drop#module_expr_desc
mod_expr_desc)
, Did_not_mangle )
method! module_expr suffix mod_expr =
self#module_expr_desc { suffix with loc = mod_expr.pmod_loc } mod_expr.pmod_desc
|> map_fst ~f:(fun pmod_desc -> { mod_expr with pmod_desc })
method! core_type_desc suffix =
function
| Ptyp_constr (name, params) ->
self#loc self#longident suffix name
|> map_fst ~f:(fun name -> Ptyp_constr (name, params))
| Ptyp_package (name, params) ->
self#loc self#longident suffix name
|> map_fst ~f:(fun name -> Ptyp_package (name, params))
| Ptyp_extension _ as desc -> super#core_type_desc suffix desc
| core_type_desc ->
( Ptyp_extension
(mangle_error
suffix
"core type"
explicitly_drop#core_type_desc
core_type_desc)
, Did_not_mangle )
method! core_type suffix typ =
self#core_type_desc { suffix with loc = typ.ptyp_loc } typ.ptyp_desc
|> map_fst ~f:(fun ptyp_desc -> { typ with ptyp_desc })
method! module_type_desc suffix =
function
| Pmty_ident _ as desc -> super#module_type_desc suffix desc
| mod_type_desc ->
( Pmty_extension
(mangle_error
suffix
"module type"
explicitly_drop#module_type_desc
mod_type_desc)
, Did_not_mangle )
method! module_type suffix mod_typ =
self#module_type_desc { suffix with loc = mod_typ.pmty_loc } mod_typ.pmty_desc
|> map_fst ~f:(fun pmty_desc -> { mod_typ with pmty_desc })
method! pattern_desc suffix pattern_desc =
match Ppxlib_jane.Shim.Pattern_desc.of_parsetree pattern_desc with
| Ppat_any | Ppat_var _ | Ppat_alias _ -> super#pattern_desc suffix pattern_desc
| Ppat_constraint (pat, typ, modes) ->
self#pattern suffix pat
|> map_fst ~f:(fun pat ->
Ppxlib_jane.Shim.Pattern_desc.to_parsetree
~loc:pat.ppat_loc
(Ppat_constraint (pat, typ, modes)))
| _ ->
( (if List.is_empty suffix.txt
then pattern_desc
else
Ppat_extension
(mangle_error suffix "pattern" explicitly_drop#pattern_desc pattern_desc))
, Did_not_mangle )
method! pattern suffix pat =
self#pattern_desc { suffix with loc = pat.ppat_loc } pat.ppat_desc
|> map_fst ~f:(fun ppat_desc -> { pat with ppat_desc })
method! value_binding suffix binding =
self#pattern suffix binding.pvb_pat
|> map_fst ~f:(fun pvb_pat -> { binding with pvb_pat })
method! value_description suffix desc =
self#loc self#string suffix desc.pval_name
|> map_fst ~f:(fun pval_name -> { desc with pval_name })
method! module_binding suffix binding =
self#loc (self#option self#string) suffix binding.pmb_name
|> map_fst ~f:(fun pmb_name -> { binding with pmb_name })
method! module_declaration suffix decl =
self#loc (self#option self#string) suffix decl.pmd_name
|> map_fst ~f:(fun pmd_name -> { decl with pmd_name })
method! type_declaration suffix decl =
self#loc self#string suffix decl.ptype_name
|> map_fst ~f:(fun ptype_name -> { decl with ptype_name })
method! module_type_declaration suffix decl =
self#loc self#string suffix decl.pmtd_name
|> map_fst ~f:(fun pmtd_name -> { decl with pmtd_name })
method! include_infos _ suffix info =
let mangled : Outcome.t =
if Suffix.is_empty suffix then Did_not_mangle else Mangled
in
info, mangled
end
;;
let mangle
(type a)
(attr_ctx : a Attribute_handler.Context.mono)
(node : a)
mangle_exprs
~env
=
if Axis.Map.is_empty mangle_exprs
then node
else (
let results =
Axis.Map.map
(fun me ->
Explicitness.With.map me ~f:(fun exprs ->
List.Or_first_error.map
exprs
~f:(fun { txt = Expression.Basic.P expr; loc } ->
Result.map
(Env.eval_singleton env { txt = expr; loc })
~f:(fun value -> Value.Basic.P value)))
|> Explicitness.With.ok)
mangle_exprs
in
let manglers =
Axis.Map.filter_map
(fun _ -> function
| Ok x -> Some x
| Error _ -> None)
results
in
let errors =
Axis.Map.filter_map
(fun _ -> function
| Ok _ -> None
| Error e -> Some e)
results
in
match Axis.Map.to_list errors with
| [] ->
let suffix = Suffix.create manglers in
let (node : a), (_ : Outcome.t) =
match attr_ctx with
| Expression -> t#expression suffix node
| Module_expr -> t#module_expr suffix node
| Core_type -> t#core_type suffix node
| Module_type -> t#module_type suffix node
in
node
| [ (_, err) ] ->
Syntax_error_conversion.to_extension_node
(Attribute_handler.Context.mono_to_any attr_ctx)
node
err
| (_, err) :: (_ :: _ as alist) ->
Syntax_error_conversion.to_extension_node
(Attribute_handler.Context.mono_to_any attr_ctx)
node
(Syntax_error.combine (err :: List.map alist ~f:snd)))
;;