2525 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626 *
2727 *)
28+ #if OCAML_VERSION < (4 , 03 , 0 )
29+ #define STR_TYPE_RECURSIVE
30+ #define Pcstr_tuple (core_types) core_types
31+ #else
32+ #define STR_TYPE_RECURSIVE Recursive
33+ #endif
2834
2935(* * Generate mapper-record(s) for a given type.
3036
@@ -113,13 +119,20 @@ let attr_map attrs =
113119
114120let argn =
115121 Printf. sprintf " arg%d"
122+ let argl =
123+ Printf. sprintf " arg%s"
116124
117125let opt_pattn maps =
118126 List. mapi (fun i e -> match e with Some _ -> pvar (argn i) | None -> Pat. any () ) maps
119127
120128let pattn typs =
121129 List. mapi (fun i _ -> pvar (argn i)) typs
122130
131+ let pattl labels = List. map (fun { pld_name = { txt = n } } -> n, pvar (argl n)) labels
132+
133+ let pconstrrec name fields = pconstr name [precord ~closed: Closed fields]
134+ let constrrec name fields = constr name [record fields]
135+
123136let varn typs =
124137 List. mapi (fun i _ -> evar (argn i)) typs
125138
@@ -156,10 +169,19 @@ let reduce_map_seq ets =
156169 | (x ,None) :: es -> reduce_ (x::ds) es
157170 in
158171
159- match reduce_ [] ets with
160- [] -> None
161- | [e] -> Some e
162- | es -> Some (Exp. tuple es)
172+ reduce_ [] ets
173+
174+ let reduce_record_map_seq ets =
175+ (* Reduce a set of mapped arguments from record labels by applying all map-routines and create a tuple *)
176+ let rec reduce_ ds = function
177+ (* For each argument with a map-routine, apply that routine *)
178+ [] -> List. rev ds
179+ | (x ,Some f ) :: es -> reduce_ ((x, [% expr [% e f] [% e (evar (argl x))]])::ds) es
180+ | (x ,None) :: es -> reduce_ ((x, evar (argl x))::ds) es
181+ in
182+
183+ reduce_ [] ets
184+
163185
164186(* generate the map routine for a given type.
165187 In case of unknown types, returns None
@@ -189,8 +211,8 @@ let rec expr_of_typ names quoter typ =
189211 let maps = List. map expr_of_typ typs in
190212 let pat = pat_tuple (pattn maps) in
191213 let map = match reduce_map_seq (List. combine (varn typs) maps) with
192- Some e -> e
193- | None -> raise (Failure " Tuple invariant broken" )
214+ e :: es -> tuple (e::es)
215+ | [] -> raise (Failure " Tuple invariant broken" )
194216 in
195217 Some [% expr fun [%p pat ] -> [% e map]]
196218
@@ -202,7 +224,7 @@ let rec expr_of_typ names quoter typ =
202224
203225 (* select the approppriate map_routines for arguments and pass them through *)
204226 let arg_maps = args |> List. map
205- (fun ct -> match expr_of_typ ct with Some e -> (" " , e) | None -> (" " , map_pass))
227+ (fun ct -> match expr_of_typ ct with Some e -> (Label. nolabel , e) | None -> (Label. nolabel , map_pass))
206228 in
207229 if arg_maps = [] then Some [% expr [% e map_fn] self] else
208230 Some [% expr [% e Exp. apply map_fn arg_maps] self]
@@ -230,16 +252,19 @@ let process_decl quoter
230252 (* create a default mapper implementation for each variant *)
231253 let fields =
232254 constrs |>
233- List. map (fun { pcd_name; pcd_args = typs } ->
234- let maps = List. map (expr_of_typ names quoter) typs in
235- let pat = pat_tuple (pattn maps) in
255+ List. map (fun { pcd_name; pcd_args } ->
256+ let (pat, rhs) = match pcd_args with
257+ Pcstr_tuple typs ->
258+ let maps = List. map (expr_of_typ names quoter) typs in
259+ (pat_tuple (pattn maps), constr pcd_name.txt (reduce_map_seq (List. combine (varn typs) maps)))
260+ #if OCAML_VERSION > = (4 , 03 , 0 )
261+ | Pcstr_record labels ->
262+ let map_seq = List. map (fun {pld_name = {txt =l } ; pld_type} -> (l, expr_of_typ names quoter pld_type)) labels in
263+ (pat_tuple (List. map (fun {pld_name ={txt =l } } -> pvar (argl l)) labels), constrrec pcd_name.txt (reduce_record_map_seq map_seq))
264+ #endif
265+ in
236266 let subfield = Ppx_deriving. mangle_lid (`Prefix " map" ) (Lident pcd_name.txt) in
237- (mknoloc subfield, [% expr fun self [%p pat ] ->
238- [% e
239- (Exp. construct
240- {pcd_name with txt= Lident pcd_name.txt}
241- (reduce_map_seq (List. combine (varn typs) maps)))]
242- ]))
267+ (mknoloc subfield, [% expr fun self [%p pat ] -> [% e rhs]]))
243268 in
244269 (mknoloc (Lident on_var), (Exp. record fields None )) :: defaults
245270 | _ -> defaults
@@ -253,14 +278,22 @@ let process_decl quoter
253278 *)
254279 let cases =
255280 constrs |>
256- List. map (fun { pcd_name; pcd_args = typs } ->
281+ List. map (fun { pcd_name; pcd_args } ->
257282 let subfield = Ppx_deriving. mangle_lid (`Prefix " map" ) (Lident pcd_name.txt) in
258- Exp. case (pconstr pcd_name.txt (pattn typs))
283+ let (pat, mk) = match pcd_args with
284+ Pcstr_tuple typs -> ((pconstr pcd_name.txt (pattn typs)), tuple (varn typs))
285+ #if OCAML_VERSION > = (4 , 03 , 0 )
286+ | Pcstr_record labels ->
287+ (pconstrrec pcd_name.txt (pattl labels),
288+ tuple (List. map (fun {pld_name = { txt = l } } -> evar (argl l)) labels))
289+ #endif
290+ in
291+ Exp. case pat
259292 (Exp. apply
260293 (Exp. field
261294 (Exp. field [% expr self] (mknoloc (Lident on_var)))
262295 (mknoloc subfield))
263- [" " , evar " self" ; " " , tuple (varn typs) ]))
296+ [Label. nolabel , evar " self" ; Label. nolabel, mk ]))
264297 in
265298 [% expr fun self x -> [% e Exp. match_ [% expr x] cases]]
266299 | Ptype_record labels ->
@@ -272,7 +305,7 @@ let process_decl quoter
272305 ({pld_name with txt = Lident pld_name.txt},
273306 match expr_of_typ names quoter pld_type with
274307 None -> evar pld_name.txt
275- | Some map -> Exp. apply map [" " , evar pld_name.txt]
308+ | Some map -> Exp. apply map [Label. nolabel , evar pld_name.txt]
276309 )
277310 end
278311 in
@@ -312,7 +345,14 @@ let process_decl quoter
312345 in
313346
314347 (* create the map_fn signature for the rhs of a constructor *)
315- let typs_to_field { pcd_name; pcd_args = typs } =
348+ let typs_to_field { pcd_name; pcd_args} =
349+ let typs =
350+ match pcd_args with
351+ Pcstr_tuple typs -> typs
352+ #if OCAML_VERSION > = (4 , 03 , 0 )
353+ | Pcstr_record labels -> List. map (fun {pld_type} -> pld_type) labels
354+ #endif
355+ in
316356 Type. field (mknoloc (" map_" ^ pcd_name.txt)) (merge_typs typs) in
317357
318358 let fields = constrs |> List. map typs_to_field in
@@ -336,7 +376,7 @@ let process_decl quoter
336376
337377let mapper_to_str {names; defaults; sub_mappers; mapper_fields} =
338378 [
339- (Str. type_ (
379+ (Str. type_ STR_TYPE_RECURSIVE (
340380 Type. mk
341381 ~kind: (Ptype_record mapper_fields) (mknoloc " map_routines" ) ::
342382 Type. mk
0 commit comments