@@ -190,9 +190,14 @@ module Match =
190
190
end
191
191
192
192
193
+ (* Monadic Ppxlib error handling *)
194
+ let return = Ppxlib.With_errors. return
195
+ let (>> = ) = Ppxlib.With_errors. (>> = )
196
+ let (>> | ) = Ppxlib.With_errors. (>> | )
197
+
193
198
class mutate_mapper (rs : RS.t ) =
194
199
object (self )
195
- inherit Ppxlib.Ast_traverse. map_with_expansion_context as super
200
+ inherit Ppxlib.Ast_traverse. map_with_expansion_context_and_errors as super
196
201
197
202
val mutable mut_count = 0
198
203
val mutable mutations = []
@@ -235,7 +240,7 @@ class mutate_mapper (rs : RS.t) =
235
240
then [% e e_new]
236
241
else [% e e_rec]]
237
242
238
- method! constant _ctx e = e
243
+ method! constant _ctx e = return e
239
244
method mutate_constant _ctx c = match c with
240
245
| Pconst_integer (i ,None) ->
241
246
(match i with
@@ -262,7 +267,7 @@ class mutate_mapper (rs : RS.t) =
262
267
match e with
263
268
(* A special case mutations : omit 1+ * )
264
269
| [% expr 1 + [% e? exp]] ->
265
- let exp' = super#expression ctx exp in (* super avoids mut of exp in 1 + exp *)
270
+ super#expression ctx exp >> | fun exp' -> (* super avoids mut of exp in 1 + exp *)
266
271
let k, tmp_var = self#let_bind ~loc: exp.pexp_loc exp' in
267
272
k (self#mutaml_mutant ctx loc
268
273
{ e with pexp_desc = tmp_var.pexp_desc }
@@ -272,7 +277,7 @@ class mutate_mapper (rs : RS.t) =
272
277
| [% expr [% e? exp] + 1 ]
273
278
| [% expr [% e? exp] - 1 ] ->
274
279
let op = (match e.pexp_desc with | Pexp_apply (op , _args ) -> op | _ -> assert false ) in
275
- let exp' = super#expression ctx exp in (* super avoids mut of exp in exp +/- 1 *)
280
+ super#expression ctx exp >> | fun exp' -> (* super avoids mut of exp in exp +/- 1 *)
276
281
let k, tmp_var = self#let_bind ~loc: exp.pexp_loc exp' in
277
282
k (self#mutaml_mutant ctx loc
278
283
{ e with pexp_desc = tmp_var.pexp_desc }
@@ -291,16 +296,18 @@ class mutate_mapper (rs : RS.t) =
291
296
failwith (" mutaml_ppx, mutate_arithmetic: found some other operator case: " ^ (string_of_exp op))
292
297
)} in
293
298
(* Note: we bind exp2 before exp1 to preserve the current (unspecified) OCaml evaluation order. *)
294
- let k2, tmp_var2 = self#let_bind ~loc: exp2.pexp_loc (self#expression ctx exp2) in
295
- let k1, tmp_var1 = self#let_bind ~loc: exp1.pexp_loc (self#expression ctx exp1) in
299
+ self#expression ctx exp2 >> = fun exp2' ->
300
+ let k2, tmp_var2 = self#let_bind ~loc: exp2.pexp_loc exp2' in
301
+ self#expression ctx exp1 >> | fun exp1' ->
302
+ let k1, tmp_var1 = self#let_bind ~loc: exp1.pexp_loc exp1' in
296
303
k2 (k1 (self#mutaml_mutant ctx loc
297
304
{ e with pexp_desc = [% expr [% e mut_op] [% e tmp_var1] [% e tmp_var2]].pexp_desc }
298
305
{ e with pexp_desc = [% expr [% e op] [% e tmp_var1] [% e tmp_var2]].pexp_desc }
299
306
(string_of_exp [% expr [% e mut_op] [% e exp1] [% e exp2]])))
300
307
| _ -> failwith " mutaml_ppx, mutate_arithmetic: pattern matching on case is was not applied to"
301
308
302
309
method! cases ctx cases =
303
- let cases = super#cases ctx cases in (* visit individual cases first *)
310
+ super#cases ctx cases >> | fun cases -> (* visit individual cases first *)
304
311
let cases_exc, cases_pure =
305
312
List. partition (fun c -> Match. pat_matches_exception c.pc_lhs) cases in
306
313
let cases_contain_catch_all
@@ -395,15 +402,15 @@ class mutate_mapper (rs : RS.t) =
395
402
| Some x -> i+1
396
403
| None -> assert false
397
404
which is another reason to avoid mutating that particular form. *)
398
- | [% expr assert [% e? _]], _ -> e
405
+ | [% expr assert [% e? _]], _ -> return e
399
406
400
407
(* swap bool constructors *)
401
408
| [% expr true ],_ when self#choose_to_mutate ->
402
409
let false_exp = { e with pexp_desc = [% expr false ].pexp_desc } in
403
- self#mutaml_mutant ctx loc false_exp e (string_of_exp false_exp)
410
+ return ( self#mutaml_mutant ctx loc false_exp e (string_of_exp false_exp) )
404
411
| [% expr false ],_ when self#choose_to_mutate ->
405
412
let true_exp = { e with pexp_desc = [% expr true ].pexp_desc } in
406
- self#mutaml_mutant ctx loc true_exp e (string_of_exp true_exp)
413
+ return ( self#mutaml_mutant ctx loc true_exp e (string_of_exp true_exp) )
407
414
408
415
| [% expr [% e? _] + [% e? _]],_
409
416
| [% expr [% e? _] - [% e? _]],_
@@ -414,9 +421,9 @@ class mutate_mapper (rs : RS.t) =
414
421
415
422
| _ , Pexp_constant c when self#choose_to_mutate ->
416
423
let c' = self#mutate_constant ctx c in
417
- if c = c' then e else
424
+ if c = c' then return e else
418
425
let e_new = { e with pexp_desc = Pexp_constant c' } in
419
- self#mutaml_mutant ctx loc e_new e (string_of_exp e_new)
426
+ return ( self#mutaml_mutant ctx loc e_new e (string_of_exp e_new) )
420
427
421
428
(* we negate an if's condition rather than swapping its branches:
422
429
* it avoids duplication
@@ -428,31 +435,35 @@ class mutate_mapper (rs : RS.t) =
428
435
then e1
429
436
else e2 *)
430
437
| _ , Pexp_ifthenelse (e0 ,e1 ,e2_opt ) when self#choose_to_mutate ->
431
- let e0' = self#expression ctx e0 in
432
- let e1' = self#expression ctx e1 in
433
- let e2_opt' = Option. map (self#expression ctx) e2_opt in
438
+ self#expression ctx e0 >> = fun e0' ->
439
+ self#expression ctx e1 >> = fun e1' ->
440
+ let cont e2_opt' =
434
441
let k, tmp_var = self#let_bind ~loc: e0.pexp_loc e0' in
435
442
let e0'_guarded =
436
443
k (self#mutaml_mutant ctx e0.pexp_loc (* loc*)
437
444
[% expr not [% e tmp_var]]
438
445
[% expr [% e tmp_var]]
439
446
(string_of_exp [% expr not [% e e0]])) in
440
447
{ e with pexp_desc = Pexp_ifthenelse (e0'_guarded,e1',e2_opt') }
448
+ in
449
+ (match e2_opt with
450
+ | None -> return (cont None )
451
+ | Some e2 -> self#expression ctx e2 >> | fun e2' -> cont (Some e2'))
441
452
442
453
(* omit a unit-expression in a sequence:
443
454
444
455
(if __MUTAML_MUTANT__ = Some [%e mut_id_exp]
445
456
e0; e1 ~~> then ()
446
457
else e0'); e' *)
447
458
| _ , Pexp_sequence (e0 ,e1 ) when self#choose_to_mutate ->
448
- let e0' = self#expression ctx e0 in
449
- let e1' = self#expression ctx e1 in
459
+ self#expression ctx e0 >> = fun e0' ->
460
+ self#expression ctx e1 >> | fun e1' ->
450
461
let e0'' =
451
462
self#mutaml_mutant ctx loc(* e0.pexp_loc*) [% expr () ] e0' (string_of_exp e1) in
452
463
{ e0 with pexp_desc = Pexp_sequence (e0'',e1') }
453
464
454
465
| _ , Pexp_function cases ->
455
- let cases_pure = self#cases ctx cases in (* all cases are pure in 'function' *)
466
+ self#cases ctx cases >> | fun cases_pure -> (* all cases are pure in 'function' *)
456
467
let function_ = { e with pexp_desc = Pexp_function cases_pure } in
457
468
if Match. cases_contain_matching_patterns cases_pure
458
469
then
@@ -463,8 +474,8 @@ class mutate_mapper (rs : RS.t) =
463
474
else function_
464
475
465
476
| _ , Pexp_match (me ,cases ) ->
466
- let me = super#expression ctx me in
467
- let cases = self#cases ctx cases in
477
+ super#expression ctx me >> = fun me ->
478
+ self#cases ctx cases >> | fun cases ->
468
479
let cases_pure = List. filter (fun c -> not (Match. pat_matches_exception c.pc_lhs)) cases in
469
480
let match_ = { e with pexp_desc = Pexp_match (me, cases) } in
470
481
if Match. cases_contain_matching_patterns cases_pure
@@ -485,11 +496,17 @@ class mutate_mapper (rs : RS.t) =
485
496
Printf. printf " Mutation rate: %i %!" ! Options. mut_rate;
486
497
Printf. printf " GADTs enabled: %s\n %!" (Bool. to_string ! Options. gadt);
487
498
488
- let instrumented_ast = super#structure ctx impl_ast in
499
+ let instrumented_ast,errs = super#structure ctx impl_ast in
500
+ let errs =
501
+ List. map (fun error ->
502
+ Ast_builder.Default. pstr_extension
503
+ ~loc: (Location.Error. get_location error)
504
+ (Location.Error. to_extension error)
505
+ [] ) errs in
489
506
let mut_count = List. length mutations in
490
507
Printf. printf " Created %i mutation%s of %s\n %!" mut_count (if mut_count= 1 then " " else " s" ) input_name;
491
508
492
509
let output_name = write_muts_file input_name mutations in
493
510
let () = append_muts_file_to_log output_name in
494
- add_preamble instrumented_ast input_name
511
+ errs @ ( add_preamble instrumented_ast input_name)
495
512
end
0 commit comments