Skip to content

Commit 4096e53

Browse files
authored
Merge pull request #27 from jmid/remove-ppxlib-bounds
Remove ppxlib upper bound
2 parents e1845ee + b3cdb83 commit 4096e53

File tree

10 files changed

+55
-459
lines changed

10 files changed

+55
-459
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Next release
22
------------
33

4+
- Add support for ppxlib.0.28 and above #27
45
- Avoid triggering 2 mutations of a pattern incl. a when-clause
56
causing a redundant sub-pattern warning #22, #23
67

dune-project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
(tags ("test" "mutation testing"))
2727
(depends
2828
(ocaml (>= 4.12.0))
29-
(ppxlib (and (>= 0.26.0) (< 0.28.0)))
29+
(ppxlib (>= 0.28.0))
3030
(ppx_yojson_conv (>= 0.14.0))
3131
stdlib-random
3232
conf-timeout

mutaml.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ bug-reports: "https://github.com/jmid/mutaml"
1818
depends: [
1919
"dune" {>= "3.0"}
2020
"ocaml" {>= "4.12.0"}
21-
"ppxlib" {>= "0.26.0" & < "0.28.0"}
21+
"ppxlib" {>= "0.28.0"}
2222
"ppx_yojson_conv" {>= "0.14.0"}
2323
"stdlib-random"
2424
"conf-timeout"

src/common/mutaml_common.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
open Ppx_yojson_conv_lib.Yojson_conv.Primitives
2+
13
type defaults =
24
{
35
ppx_output_prefix : string;

src/ppx/mutaml_ppx.ml

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,14 @@ module Match =
190190
end
191191

192192

193+
(* Monadic Ppxlib error handling *)
194+
let return = Ppxlib.With_errors.return
195+
let (>>=) = Ppxlib.With_errors.(>>=)
196+
let (>>|) = Ppxlib.With_errors.(>>|)
197+
193198
class mutate_mapper (rs : RS.t) =
194199
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
196201

197202
val mutable mut_count = 0
198203
val mutable mutations = []
@@ -235,7 +240,7 @@ class mutate_mapper (rs : RS.t) =
235240
then [%e e_new]
236241
else [%e e_rec]]
237242

238-
method! constant _ctx e = e
243+
method! constant _ctx e = return e
239244
method mutate_constant _ctx c = match c with
240245
| Pconst_integer (i,None) ->
241246
(match i with
@@ -262,7 +267,7 @@ class mutate_mapper (rs : RS.t) =
262267
match e with
263268
(* A special case mutations: omit 1+ *)
264269
| [%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 *)
266271
let k, tmp_var = self#let_bind ~loc:exp.pexp_loc exp' in
267272
k (self#mutaml_mutant ctx loc
268273
{ e with pexp_desc = tmp_var.pexp_desc }
@@ -272,7 +277,7 @@ class mutate_mapper (rs : RS.t) =
272277
| [%expr [%e? exp] + 1]
273278
| [%expr [%e? exp] - 1] ->
274279
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 *)
276281
let k, tmp_var = self#let_bind ~loc:exp.pexp_loc exp' in
277282
k (self#mutaml_mutant ctx loc
278283
{ e with pexp_desc = tmp_var.pexp_desc }
@@ -291,16 +296,18 @@ class mutate_mapper (rs : RS.t) =
291296
failwith ("mutaml_ppx, mutate_arithmetic: found some other operator case: " ^ (string_of_exp op))
292297
)} in
293298
(* 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
296303
k2 (k1 (self#mutaml_mutant ctx loc
297304
{ e with pexp_desc = [%expr [%e mut_op] [%e tmp_var1] [%e tmp_var2]].pexp_desc }
298305
{ e with pexp_desc = [%expr [%e op] [%e tmp_var1] [%e tmp_var2]].pexp_desc }
299306
(string_of_exp [%expr [%e mut_op] [%e exp1] [%e exp2]])))
300307
| _ -> failwith "mutaml_ppx, mutate_arithmetic: pattern matching on case is was not applied to"
301308

302309
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 *)
304311
let cases_exc, cases_pure =
305312
List.partition (fun c -> Match.pat_matches_exception c.pc_lhs) cases in
306313
let cases_contain_catch_all
@@ -395,15 +402,15 @@ class mutate_mapper (rs : RS.t) =
395402
| Some x -> i+1
396403
| None -> assert false
397404
which is another reason to avoid mutating that particular form. *)
398-
| [%expr assert [%e? _]], _-> e
405+
| [%expr assert [%e? _]], _-> return e
399406

400407
(* swap bool constructors *)
401408
| [%expr true],_ when self#choose_to_mutate ->
402409
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))
404411
| [%expr false],_ when self#choose_to_mutate ->
405412
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))
407414

408415
| [%expr [%e? _] + [%e? _]],_
409416
| [%expr [%e? _] - [%e? _]],_
@@ -414,9 +421,9 @@ class mutate_mapper (rs : RS.t) =
414421

415422
| _, Pexp_constant c when self#choose_to_mutate ->
416423
let c' = self#mutate_constant ctx c in
417-
if c = c' then e else
424+
if c = c' then return e else
418425
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))
420427

421428
(* we negate an if's condition rather than swapping its branches:
422429
* it avoids duplication
@@ -428,31 +435,35 @@ class mutate_mapper (rs : RS.t) =
428435
then e1
429436
else e2 *)
430437
| _, 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' =
434441
let k, tmp_var = self#let_bind ~loc:e0.pexp_loc e0' in
435442
let e0'_guarded =
436443
k (self#mutaml_mutant ctx e0.pexp_loc (*loc*)
437444
[%expr not [%e tmp_var]]
438445
[%expr [%e tmp_var]]
439446
(string_of_exp [%expr not [%e e0]])) in
440447
{ 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'))
441452

442453
(* omit a unit-expression in a sequence:
443454
444455
(if __MUTAML_MUTANT__ = Some [%e mut_id_exp]
445456
e0; e1 ~~> then ()
446457
else e0'); e' *)
447458
| _, 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' ->
450461
let e0'' =
451462
self#mutaml_mutant ctx loc(*e0.pexp_loc*) [%expr ()] e0' (string_of_exp e1) in
452463
{ e0 with pexp_desc = Pexp_sequence (e0'',e1') }
453464

454465
| _, 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' *)
456467
let function_ = { e with pexp_desc = Pexp_function cases_pure } in
457468
if Match.cases_contain_matching_patterns cases_pure
458469
then
@@ -463,8 +474,8 @@ class mutate_mapper (rs : RS.t) =
463474
else function_
464475

465476
| _, 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 ->
468479
let cases_pure = List.filter (fun c -> not (Match.pat_matches_exception c.pc_lhs)) cases in
469480
let match_ = { e with pexp_desc = Pexp_match (me, cases) } in
470481
if Match.cases_contain_matching_patterns cases_pure
@@ -485,11 +496,17 @@ class mutate_mapper (rs : RS.t) =
485496
Printf.printf "Mutation rate: %i %!" !Options.mut_rate;
486497
Printf.printf "GADTs enabled: %s\n%!" (Bool.to_string !Options.gadt);
487498

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
489506
let mut_count = List.length mutations in
490507
Printf.printf "Created %i mutation%s of %s\n%!" mut_count (if mut_count=1 then "" else "s") input_name;
491508

492509
let output_name = write_muts_file input_name mutations in
493510
let () = append_muts_file_to_log output_name in
494-
add_preamble instrumented_ast input_name
511+
errs @ (add_preamble instrumented_ast input_name)
495512
end

test/instrumentation-tests/arith.t

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Test - 1:
6060

6161

6262
Test 1 +:
63-
63+
z
6464
$ cat > test.ml <<'EOF'
6565
> let f x = 1 + x;;
6666
> assert (f 5 = 6)
@@ -109,77 +109,6 @@ Test addition:
109109

110110
--------------------------------------------------------------------------------
111111

112-
Parse tree of simple arithmetic:
113-
114-
$ ocamlc -dparsetree test.ml
115-
[
116-
structure_item (test.ml[1,0+0]..[1,0+17])
117-
Pstr_value Nonrec
118-
[
119-
<def>
120-
pattern (test.ml[1,0+4]..[1,0+5])
121-
Ppat_var "f" (test.ml[1,0+4]..[1,0+5])
122-
expression (test.ml[1,0+6]..[1,0+17]) ghost
123-
Pexp_fun
124-
Nolabel
125-
None
126-
pattern (test.ml[1,0+6]..[1,0+7])
127-
Ppat_var "x" (test.ml[1,0+6]..[1,0+7])
128-
expression (test.ml[1,0+8]..[1,0+17]) ghost
129-
Pexp_fun
130-
Nolabel
131-
None
132-
pattern (test.ml[1,0+8]..[1,0+9])
133-
Ppat_var "y" (test.ml[1,0+8]..[1,0+9])
134-
expression (test.ml[1,0+12]..[1,0+17])
135-
Pexp_apply
136-
expression (test.ml[1,0+14]..[1,0+15])
137-
Pexp_ident "+" (test.ml[1,0+14]..[1,0+15])
138-
[
139-
<arg>
140-
Nolabel
141-
expression (test.ml[1,0+12]..[1,0+13])
142-
Pexp_ident "x" (test.ml[1,0+12]..[1,0+13])
143-
<arg>
144-
Nolabel
145-
expression (test.ml[1,0+16]..[1,0+17])
146-
Pexp_ident "y" (test.ml[1,0+16]..[1,0+17])
147-
]
148-
]
149-
structure_item (test.ml[2,20+0]..[2,20+19])
150-
Pstr_eval
151-
expression (test.ml[2,20+0]..[2,20+19])
152-
Pexp_assert
153-
expression (test.ml[2,20+7]..[2,20+19])
154-
Pexp_apply
155-
expression (test.ml[2,20+14]..[2,20+15])
156-
Pexp_ident "=" (test.ml[2,20+14]..[2,20+15])
157-
[
158-
<arg>
159-
Nolabel
160-
expression (test.ml[2,20+8]..[2,20+13])
161-
Pexp_apply
162-
expression (test.ml[2,20+8]..[2,20+9])
163-
Pexp_ident "f" (test.ml[2,20+8]..[2,20+9])
164-
[
165-
<arg>
166-
Nolabel
167-
expression (test.ml[2,20+10]..[2,20+11])
168-
Pexp_constant PConst_int (5,None)
169-
<arg>
170-
Nolabel
171-
expression (test.ml[2,20+12]..[2,20+13])
172-
Pexp_constant PConst_int (6,None)
173-
]
174-
<arg>
175-
Nolabel
176-
expression (test.ml[2,20+16]..[2,20+18])
177-
Pexp_constant PConst_int (11,None)
178-
]
179-
]
180-
181-
--------------------------------------------------------------------------------
182-
183112
Test subtraction mutation:
184113

185114
$ cat > test.ml <<'EOF'

test/instrumentation-tests/function-merge-consecutive.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ Same example that triggers merge-of-consecutive-patterns w/GADTs false
625625
$ export MUTAML_GADT=false
626626
$ export MUTAML_SEED=896745231
627627

628-
$ bash ../filter_dune_build.sh ./test.bc --instrument-with mutaml
628+
$ bash ../filter_dune_build.sh ./test.bc --instrument-with mutaml | sed 's/ | / | /' | sed 's/ \{9\}l/ l/' | sed 's/(((f/((f/' | sed 's/ \{9\}i/ i/' | sed 's/v1))/v1)/'
629629
Running mutaml instrumentation on "test.ml"
630630
Randomness seed: 896745231 Mutation rate: 100 GADTs enabled: false
631631
Created 6 mutations of test.ml

0 commit comments

Comments
 (0)