@@ -157,7 +157,7 @@ module Regexp = struct
157
157
end
158
158
159
159
module Parser = struct
160
- let get_parser mode target = match mode with `Pcre -> Regexp. parse_exn ~target | `Mik -> Regexp. parse_mik_exn ~target
160
+ let get_parser ~ mode ~ target = match mode with `Pcre -> Regexp. parse_exn ~target | `Mik -> Regexp. parse_mik_exn ~target
161
161
162
162
let run ~parser ~ctx s =
163
163
let r, flags = parser s in
@@ -167,41 +167,57 @@ module Parser = struct
167
167
re, bs, nG, flags
168
168
end
169
169
170
- let make_default_rhs ~mode ~loc = function
170
+ let make_default_rhs ~mode ~target ~ loc = function
171
171
| [] ->
172
172
let open Lexing in
173
173
let pos = loc.Location. loc_start in
174
174
let pos_end = loc.Location. loc_end in
175
- let lnum = eint ~loc pos.pos_lnum in
176
- let lnum_end = eint ~loc pos_end.pos_lnum in
177
- let e0 = estring ~loc pos.pos_fname in
178
- let e2 = eint ~loc (pos.pos_cnum - pos.pos_bol) in
179
- let e2_start = eint ~loc (pos.pos_cnum - pos.pos_bol) in
180
- let e2_end = eint ~loc (pos_end.pos_cnum - pos_end.pos_bol) in
181
- begin
182
- match mode with
183
- | `Pcre ->
184
- let e = [% expr raise (Match_failure ([% e e0], [% e lnum], [% e e2]))] in
185
- Util. warn ~loc " A universal case is recommended for %%pcre." e
186
- | `Mik ->
187
- let str = [% expr Printf. sprintf " File %s, lines %d-%d, characters %d-%d: String did not match any of the mikmatch regexes." ] in
188
- [% expr raise (Failure ([% e str] [% e e0] [% e lnum] [% e lnum_end] [% e e2_start] [% e e2_end]))]
175
+
176
+ (* pcre match uses Match_failure for compatibility *)
177
+ if target = `Match && mode = `Pcre then begin
178
+ let e =
179
+ [% expr
180
+ raise (Match_failure ([% e estring ~loc pos.pos_fname], [% e eint ~loc pos.pos_lnum], [% e eint ~loc (pos.pos_cnum - pos.pos_bol)]))]
181
+ in
182
+ Util. warn ~loc " A universal case is recommended for %%pcre." e
183
+ end
184
+ else begin
185
+ (* all other cases use descriptive Failure *)
186
+ let context =
187
+ match target, mode with
188
+ | `Match , `Pcre -> " any pcre cases"
189
+ | `Match , `Mik -> " any mikmatch cases"
190
+ | `Let , `Pcre -> " the pcre regex"
191
+ | `Let , `Mik -> " the mikmatch regex"
192
+ in
193
+
194
+ let location_desc =
195
+ let char_start = pos.pos_cnum - pos.pos_bol in
196
+ let char_end = pos_end.pos_cnum - pos_end.pos_bol in
197
+ if pos.pos_lnum = pos_end.pos_lnum then Printf. sprintf " line %d, characters %d-%d" pos.pos_lnum char_start char_end
198
+ else Printf. sprintf " lines %d-%d, characters %d-%d" pos.pos_lnum pos_end.pos_lnum char_start char_end
199
+ in
200
+
201
+ let err_msg = Printf. sprintf " File %s, %s: String did not match %s." pos.pos_fname location_desc context in
202
+ [% expr raise (Failure [% e estring ~loc err_msg])]
189
203
end
190
204
| default_cases ->
191
205
let transformed =
192
206
List. map
193
- (fun case ->
194
- match case.pc_lhs.ppat_desc with
195
- | Ppat_var var ->
196
- {
197
- case with
198
- pc_lhs = ppat_any ~loc ;
199
- pc_rhs =
200
- [% expr
201
- let [% p ppat_var ~loc var] = _ppx_regexp_v in
202
- [% e case.pc_rhs]];
203
- }
204
- | _ -> case)
207
+ begin
208
+ fun case ->
209
+ match case.pc_lhs.ppat_desc with
210
+ | Ppat_var var ->
211
+ {
212
+ case with
213
+ pc_lhs = ppat_any ~loc ;
214
+ pc_rhs =
215
+ [% expr
216
+ let [% p ppat_var ~loc var] = _ppx_regexp_v in
217
+ [% e case.pc_rhs]];
218
+ }
219
+ | _ -> case
220
+ end
205
221
default_cases
206
222
in
207
223
begin
@@ -216,7 +232,7 @@ let build_exec_match ~loc ~re_var ~continue_next ~on_match =
216
232
(* Transformations *)
217
233
218
234
let transform_let ~mode ~ctx =
219
- let parser = Parser. get_parser mode `Let in
235
+ let parser = Parser. get_parser ~ mode ~target: `Let in
220
236
List. map
221
237
begin
222
238
fun vb ->
@@ -238,6 +254,42 @@ let transform_let ~mode ~ctx =
238
254
| _ -> vb
239
255
end
240
256
257
+ let transform_destructuring_let ~mode ~ctx ~loc pattern_str expr =
258
+ let pos = loc.loc_start in
259
+ let parser = Parser. get_parser ~mode ~target: `Match ~pos in
260
+ let re, bs, _, flags = Parser. run ~parser ~ctx pattern_str in
261
+ let capture_names = List. map (fun (name , _ , _ , _ ) -> name) (List. rev bs) in
262
+
263
+ let lhs_pattern =
264
+ match capture_names with
265
+ | [] -> [% pat? () ]
266
+ | [ name ] -> ppat_var ~loc name
267
+ | names -> ppat_tuple ~loc (List. map (fun n -> ppat_var ~loc n) names)
268
+ in
269
+
270
+ let re_var = Util. fresh_var () in
271
+ let re_binding = Re_comp. compile ~loc re_var [ re, flags ] in
272
+
273
+ let on_match =
274
+ match capture_names with
275
+ | [] -> [% expr () ]
276
+ | [ _ ] -> [% expr Re.Group. get _g 1 ]
277
+ | names ->
278
+ let exprs = List. mapi (fun i _ -> [% expr Re.Group. get _g [% e eint ~loc (i + 1 )]]) names in
279
+ pexp_tuple ~loc exprs
280
+ in
281
+
282
+ let default_rhs = [% expr [% e make_default_rhs ~mode ~target: `Let ~loc []]] in
283
+
284
+ let re_var = pexp_ident ~loc { txt = Lident re_var; loc } in
285
+ let rhs_expr =
286
+ [% expr
287
+ let _ppx_regexp_v = [% e expr] in
288
+ [% e build_exec_match ~loc ~re_var ~continue_next: default_rhs ~on_match ]]
289
+ in
290
+
291
+ { pvb_pat = lhs_pattern; pvb_expr = rhs_expr; pvb_attributes = [] ; pvb_loc = loc }, [ re_binding ]
292
+
241
293
let transform_cases ~mode ~loc ~ctx cases =
242
294
let partition_cases cases =
243
295
let rec partition pattern_cases = function
@@ -252,7 +304,7 @@ let transform_cases ~mode ~loc ~ctx cases =
252
304
Ast_pattern. (parse (pstring __')) case.pc_lhs.ppat_loc case.pc_lhs (fun { txt = re_src ; loc = { loc_start; loc_end; _ } } ->
253
305
let re_offset = (loc_end.pos_cnum - loc_start.pos_cnum - String. length re_src) / 2 in
254
306
let pos = { loc_start with pos_cnum = loc_start.pos_cnum + re_offset; pos_lnum = loc_end.pos_lnum } in
255
- let parser = Parser. get_parser mode `Match ~pos in
307
+ let parser = Parser. get_parser ~ mode ~target: `Match ~pos in
256
308
let re, bs, nG, flags = Parser. run ~parser ~ctx re_src in
257
309
let re_str = Pprintast. string_of_expression re in
258
310
re, re_str, nG, bs, case.pc_rhs, case.pc_guard, flags)
@@ -289,7 +341,7 @@ let transform_cases ~mode ~loc ~ctx cases =
289
341
| Some (re_data , existing ) -> (key, (re_data, handlers :: existing)) :: List. remove_assoc key patterns
290
342
| None -> (key, (re_data, [ handlers ])) :: patterns
291
343
in
292
- List. fold_left add_case [] cases |> List. map (fun ((_re_str , _flags ), (re_data , handlers )) -> re_data, List. rev handlers) |> List. rev
344
+ List. fold_left add_case [] cases |> List. map (fun ((_ , _ ), (re_data , handlers )) -> re_data, List. rev handlers) |> List. rev
293
345
in
294
346
295
347
let add_offsets patterns =
@@ -330,9 +382,11 @@ let transform_cases ~mode ~loc ~ctx cases =
330
382
in
331
383
332
384
let handler_bindings =
333
- processed_groups
334
- |> List. concat_map (fun (_ , _ , handlers ) ->
335
- handlers |> List. map (fun (name , body ) -> value_binding ~loc ~pat: (ppat_var ~loc { txt = name; loc }) ~expr: body))
385
+ List. concat_map
386
+ begin
387
+ fun (_ , _ , handlers ) -> List. map (fun (name , expr ) -> value_binding ~loc ~pat: (ppat_var ~loc { txt = name; loc }) ~expr ) handlers
388
+ end
389
+ processed_groups
336
390
in
337
391
338
392
let build_match_cascade () =
@@ -343,14 +397,16 @@ let transform_cases ~mode ~loc ~ctx cases =
343
397
let is_single = match patterns with [ _ ] -> true | _ -> false in
344
398
345
399
let on_match =
346
- if is_single then (
400
+ if is_single then begin
347
401
let handler = pexp_ident ~loc { txt = Lident (fst (List. hd handlers)); loc } in
348
- [% expr match [% e handler] _g with Some result -> result | None -> [% e continue]])
349
- else (
402
+ [% expr match [% e handler] _g with Some result -> result | None -> [% e continue]]
403
+ end
404
+ else begin
350
405
let handler_array = handlers |> List. map (fun (name , _ ) -> pexp_ident ~loc { txt = Lident name; loc }) |> pexp_array ~loc in
351
406
let dispatch = [% expr __ppx_regexp_dispatch (snd [% e re_var]) [% e handler_array] _g] in
352
407
if has_guards then [% expr match [% e dispatch] with Some result -> result | None -> [% e continue]]
353
- else [% expr match [% e dispatch] with Some result -> result | None -> assert false ])
408
+ else [% expr match [% e dispatch] with Some result -> result | None -> assert false ]
409
+ end
354
410
in
355
411
356
412
case
@@ -372,11 +428,13 @@ let transform_cases ~mode ~loc ~ctx cases =
372
428
in
373
429
374
430
let pattern_cases, default_cases = partition_cases cases in
375
- let default_rhs = make_default_rhs ~mode ~loc default_cases in
376
-
377
- pattern_cases |> List. map (parse_pattern ~mode ~ctx ) |> create_compilation_groups |> fun groups ->
378
- let processed = List. mapi process_compilation_group groups in
379
- generate_code groups processed default_rhs
431
+ let default_rhs = make_default_rhs ~mode ~target: `Match ~loc default_cases in
432
+ if pattern_cases = [] then default_rhs, [] (* no patterns, no need for match cascading *)
433
+ else begin
434
+ pattern_cases |> List. map (parse_pattern ~mode ~ctx ) |> create_compilation_groups |> fun groups ->
435
+ let processed = List. mapi process_compilation_group groups in
436
+ generate_code groups processed default_rhs
437
+ end
380
438
381
439
let transform_mixed_match ~loc ~ctx ?matched_expr cases acc =
382
440
let aux case =
@@ -386,7 +444,7 @@ let transform_mixed_match ~loc ~ctx ?matched_expr cases acc =
386
444
PStr [ { pstr_desc = Pstr_eval ({ pexp_desc = Pexp_constant (Pconst_string (pat, str_loc, _)); _ }, _); _ } ] ) ->
387
445
let pos = str_loc.loc_start in
388
446
let mode = if " pcre" = ext then `Pcre else `Mik in
389
- let parser = Parser. get_parser mode `Match ~pos in
447
+ let parser = Parser. get_parser ~ mode ~target: `Match ~pos in
390
448
let re, bs, nG, flags = Parser. run ~parser ~ctx pat in
391
449
`Ext (re, nG, bs, case.pc_rhs, case.pc_guard, flags)
392
450
| _ -> `Regular case
0 commit comments