• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Kakadu / zanuda / 26

17 Sep 2025 06:48PM UTC coverage: 86.245% (+0.4%) from 85.847%
26

push

github

web-flow
Merge pull request #72: OCaml 5.3 support

243 of 296 new or added lines in 18 files covered. (82.09%)

8 existing lines in 5 files now uncovered.

2207 of 2559 relevant lines covered (86.24%)

524.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.75
/src/pattern/Tast_pattern.ml
1
[@@@ocaml.text "/*"]
2

3
(** Copyright 2021-2025, Kakadu. *)
4

5
(** SPDX-License-Identifier: LGPL-3.0-or-later *)
6

7
[@@@ocaml.text "/*"]
8

9
module Ast_pattern0 = struct
10
  exception Expected of Location.t * string
11

12
  let fail loc expected = raise (Expected (loc, expected))
70,085✔
13

14
  type context =
15
    { (* [matched] counts how many constructors have been matched. This is used to find what
16
         pattern matches the most some piece of ast in [Ast_pattern.alt]. In the case where
17
         all branches fail to match, we report the error from the one that matches the
18
         most.
19
         This is only incremented by combinators that can fail. *)
20
      mutable matched : int
21
    }
22

23
  type ('matched_value, 'k, 'k_result) t =
24
    | T of (context -> Location.t -> 'matched_value -> 'k -> 'k_result)
25

26
  (* end of copy-paste from https://github.com/ocaml-ppx/ppxlib/blob/0.22.2/src/ast_pattern0.ml *)
27
  (* TODO: deal with licencing issues *)
28
end
29

30
open Location
31
open Format
32
open Ast_pattern0
33

34
let debug_enabled = false
35

36
let log fmt =
37
  let open Format in
1,198✔
38
  if debug_enabled then kasprintf (printf "%s\n%!") fmt else ifprintf std_formatter fmt
×
39
;;
40

41
type ('a, 'b, 'c) t = ('a, 'b, 'c) Ast_pattern0.t
42

43
let save_context ctx = ctx.matched
123,129✔
44
let restore_context ctx backup = ctx.matched <- backup
80,964✔
45
let incr_matched c = c.matched <- c.matched + 1
4,057✔
46

47
let parse (T f) loc ?on_error x k =
48
  try f { matched = 0 } loc x k with
1,598✔
49
  | Expected (loc, expected) ->
29,064✔
50
    (match on_error with
51
     | None -> Location.raise_errorf ~loc "%s expected" expected
×
52
     | Some f -> f expected)
29,064✔
53
;;
54

55
module Packed = struct
56
  type ('a, 'b) t = T : ('a, 'b, 'c) Ast_pattern0.t * 'b -> ('a, 'c) t
57

58
  let create t f = T (t, f)
×
59
  let parse (T (t, f)) loc x = parse t loc x f
×
60
end
61

62
let __ : 'a 'b. ('a, 'a -> 'b, 'b) t =
63
  T
64
    (fun ctx _loc x k ->
65
      incr_matched ctx;
2,786✔
66
      k x)
2,786✔
67
;;
68

69
let as__ : 'a 'b 'c. ('a, 'b, 'c) t -> ('a, 'a -> 'b, 'c) t =
70
  fun (T f1) ->
71
  T
3,606✔
72
    (fun ctx loc x k ->
73
      let k = f1 ctx loc x (k x) in
259✔
74
      k)
120✔
75
;;
76

77
let pair (T f1) (T f2) =
78
  T
9,378✔
79
    (fun ctx loc (x1, x2) k ->
80
      let k = f1 ctx loc x1 k in
408✔
81
      let k = f2 ctx loc x2 k in
389✔
82
      k)
260✔
83
;;
84

85
let ( ** ) = pair
86

87
let __' =
88
  T
89
    (fun ctx loc x k ->
90
      incr_matched ctx;
21✔
91
      k { loc; txt = x })
21✔
92
;;
93

94
let drop : 'a 'b. ('a, 'b, 'b) t =
95
  T
96
    (fun ctx _loc _ k ->
97
      incr_matched ctx;
1,199✔
98
      k)
1,199✔
99
;;
100

101
let cst ~to_string ?(equal = Stdlib.( = )) v =
5,399✔
102
  T
5,399✔
103
    (fun ctx loc x k ->
104
      if equal x v
135✔
105
      then (
51✔
106
        incr_matched ctx;
107
        (* printf "cst succeeded for %s\n%!" (to_string v); *)
108
        k)
51✔
109
      else fail loc (to_string v))
84✔
110
;;
111

112
let int v = cst ~to_string:Int.to_string v
470✔
113
let char v = cst ~to_string:(Printf.sprintf "%C") v
×
114
let string v = cst ~to_string:(Printf.sprintf "%S") v
4,929✔
115
let float v = cst ~to_string:Float.to_string v
×
116
let int32 v = cst ~to_string:Int32.to_string v
×
117
let int64 v = cst ~to_string:Int64.to_string v
×
118
let nativeint v = cst ~to_string:Nativeint.to_string v
×
119
let bool v = cst ~to_string:Bool.to_string v
×
120

121
let false_ =
122
  T
123
    (fun ctx loc x k ->
124
      match x with
×
125
      | false ->
×
126
        ctx.matched <- ctx.matched + 1;
127
        k
128
      | _ -> fail loc "false")
×
129
;;
130

131
let true_ =
132
  T
133
    (fun ctx loc x k ->
134
      match x with
×
135
      | true ->
×
136
        ctx.matched <- ctx.matched + 1;
137
        k
138
      | _ -> fail loc "true")
×
139
;;
140

141
let nil =
142
  T
143
    (fun ctx loc x k ->
144
      log "trying [] \n%!";
402✔
145
      match x with
402✔
146
      | [] ->
315✔
147
        ctx.matched <- ctx.matched + 1;
148
        k
149
      | _ -> fail loc "[]")
87✔
150
;;
151

152
let ( ^:: ) (T f0) (T f1) =
153
  T
22,472✔
154
    (fun ctx loc x k ->
155
      match x with
651✔
156
      | x0 :: x1 ->
600✔
157
        ctx.matched <- ctx.matched + 1;
158
        (* Format.printf "trying elem of cons cell\n%!"; *)
159
        let k = f0 ctx loc x0 k in
160
        (* Format.printf "trying tail of cons cell\n%!"; *)
161
        let k = f1 ctx loc x1 k in
498✔
162
        (* Format.printf "trying  cons cell succeeded\n%!"; *)
163
        k
359✔
164
      | _ ->
51✔
165
        (* Format.printf "failing elem of cons cell\n%!"; *)
166
        fail loc "::")
167
;;
168

169
let list (T fel) =
170
  let rec helper acc ctx loc xs k =
2✔
171
    match xs with
6✔
172
    | [] -> k (List.rev acc)
2✔
173
    | h :: tl ->
4✔
174
      (match fel ctx loc h Fun.id with
175
       | x -> helper (x :: acc) ctx loc tl k)
4✔
176
  in
177
  T (fun ctx loc xs k -> helper [] ctx loc xs k)
2✔
178
;;
179

180
let none =
181
  T
182
    (fun ctx loc x k ->
183
      match x with
72✔
184
      | None ->
72✔
185
        ctx.matched <- ctx.matched + 1;
186
        k
187
      | _ -> fail loc "None")
×
188
;;
189

190
let some (T f0) =
191
  T
8,186✔
192
    (fun ctx loc x k ->
193
      match x with
156✔
194
      | Some x0 ->
156✔
195
        ctx.matched <- ctx.matched + 1;
196
        let k = f0 ctx loc x0 k in
197
        k
73✔
198
      | _ -> fail loc "Some")
×
199
;;
200

201
let triple (T f1) (T f2) (T f3) =
202
  T
×
203
    (fun ctx loc (x1, x2, x3) k ->
204
      let k = f1 ctx loc x1 k in
×
205
      let k = f2 ctx loc x2 k in
×
206
      let k = f3 ctx loc x3 k in
×
207
      k)
×
208
;;
209

210
let alt (T f1) (T f2) =
211
  T
12,338✔
212
    (fun ctx loc x k ->
213
      let backup = save_context ctx in
41,838✔
214
      try f1 ctx loc x k with
817✔
215
      | e1 ->
41,021✔
216
        let m1 = save_context ctx in
217
        restore_context ctx backup;
41,021✔
218
        (try f2 ctx loc x k with
751✔
219
         | e2 ->
40,270✔
220
           let m2 = save_context ctx in
221
           if m1 >= m2
40,270✔
222
           then (
39,943✔
223
             restore_context ctx m1;
224
             raise e1)
39,943✔
225
           else raise e2))
327✔
226
;;
227

228
let ( ||| ) = alt
229
let map (T func) ~f = T (fun ctx loc x k -> func ctx loc x (f k))
×
230
let map' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (f loc k))
×
231
let map_result (T func) ~f = T (fun ctx loc x k -> f (func ctx loc x k))
×
232
let ( >>| ) t f = map t ~f
×
233
let map0 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (k f))
330✔
234
let map1 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a -> k (f a)))
604✔
235
let map2 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a b -> k (f a b)))
367✔
236
let map3 (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a b c -> k (f a b c)))
57✔
237

238
let map4 (T func) ~f =
239
  T (fun ctx loc x k -> func ctx loc x (fun a b c d -> k (f a b c d)))
9✔
240
;;
241

242
let map5 (T func) ~f =
243
  T (fun ctx loc x k -> func ctx loc x (fun a b c d e -> k (f a b c d e)))
22✔
244
;;
245

246
let map6 (T func) ~f:fmap =
247
  T (fun ctx loc x k -> func ctx loc x (fun a b c d e f -> k (fmap a b c d e f)))
1✔
248
;;
249

250
let map7 (T func) ~f:fmap =
251
  T (fun ctx loc x k -> func ctx loc x (fun a b c d e f g -> k (fmap a b c d e f g)))
3✔
252
;;
253

254
let map0' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (k (f loc)))
×
255
let map1' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a -> k (f loc a)))
×
256
let map2' (T func) ~f = T (fun ctx loc x k -> func ctx loc x (fun a b -> k (f loc a b)))
×
257
let map_result (T func) ~f = T (fun ctx loc x k -> f (func ctx loc x k))
×
258
let alt_option some none = alt (map1 some ~f:(fun x -> Some x)) (map0 none ~f:None)
×
259

260
let many (T f) =
261
  T (fun ctx loc l k -> k (ListLabels.map l ~f:(fun x -> f ctx loc x (fun x -> x))))
×
262
;;
263

264
let loc (T f) = T (fun ctx _loc (x : _ Ppxlib.Loc.t) k -> f ctx x.loc x.txt k)
×
265
let pack0 t = map t ~f:(fun f -> f ())
×
266
let pack2 t = map t ~f:(fun f x y -> f (x, y))
×
267
let pack3 t = map t ~f:(fun f x y z -> f (x, y, z))
×
268

269
(* end of copy-paste from https://github.com/ocaml-ppx/ppxlib/blob/0.22.2/src/ast_pattern.ml *)
270
(* TODO: deal with licencing issues *)
271

272
let lident (T fident) =
273
  T
584✔
274
    (fun ctx loc x k ->
275
      match x with
136✔
276
      | Longident.Lident id ->
126✔
277
        ctx.matched <- ctx.matched + 1;
278
        k |> fident ctx loc id
279
      | _ -> fail loc "lident")
10✔
280
;;
281

282
let elongident (lident : Longident.t) =
283
  T
56✔
284
    (fun ctx loc x k ->
285
      if Stdlib.compare x lident = 0
183✔
286
      then (
15✔
287
        ctx.matched <- ctx.matched + 1;
288
        k)
289
      else fail loc "elongident")
168✔
290
;;
291

292
let path_pident (T fident) =
293
  T
×
294
    (fun ctx loc x k ->
295
      match x with
×
296
      | Path.Pident id ->
×
297
        ctx.matched <- ctx.matched + 1;
298
        k |> fident ctx loc id
299
      | _ -> fail loc (sprintf "path_pident"))
×
300
;;
301

302
let path xs =
303
  let rec helper ps ctx loc x k =
5,657✔
304
    let cmp_names l r =
13,444✔
305
      let ans = String.equal l r in
7,060✔
306
      (* printf "\t\tCompare names %s and %s:  %b\n%!" l r ans; *)
307
      ans
7,060✔
308
    in
309
    match x, ps with
310
    | Path.Pident id, [ id0 ] ->
117✔
311
      if cmp_names (Ident.name id) id0
117✔
312
      then (
110✔
313
        let () = ctx.matched <- ctx.matched + 1 in
314
        k)
315
      else fail loc "path"
7✔
316
    | Path.Pdot (next, id), id0 :: ids when cmp_names id id0 -> helper ids ctx loc next k
152✔
317
    | Path.Papply _, _ -> fail loc "path got Papply"
×
318
    | _ -> fail loc (sprintf "path %s" (String.concat "." xs))
13,175✔
319
  in
320
  T (helper (List.rev xs))
5,657✔
321
;;
322

323
let path_of_list = function
324
  | [] -> failwith "Bad argument: path_of_list"
×
325
  | s :: tl ->
2✔
326
    ListLabels.fold_left
327
      tl
328
      ~init:(Path.Pident (Ident.create_local s))
2✔
329
      ~f:(fun acc x -> Path.Pdot (acc, x))
4✔
330
;;
331

332
let%test_module " " =
333
  (module struct
334
    let names = [ "Stdlib!"; "List"; "length" ]
335

336
    [%%if ocaml_version < (5, 0, 0)]
337

338
    let pp_path = Path.print
339

340
    [%%else]
341

342
    let pp_path = Format_doc.compat Path.print
343

344
    [%%endif]
345

346
    let%test_unit _ =
347
      let old = !Clflags.unique_ids in
348
      Clflags.unique_ids := false;
349
      [%test_eq: Base.string]
1✔
350
        "Stdlib!.List.length"
351
        (asprintf "%a" pp_path (path_of_list names));
1✔
352
      Clflags.unique_ids := old
1✔
353
    ;;
354

355
    let%test _ =
356
      let noloc =
1✔
357
        Warnings.
358
          { loc_start = Lexing.dummy_pos; loc_end = Lexing.dummy_pos; loc_ghost = true }
359
      in
360
      parse (path names) noloc ~on_error:(fun _ -> false) (path_of_list names) true
×
361
    ;;
362
  end)
363
;;
364

365
open Typedtree
366

367
let econst (T f0) =
368
  T
×
369
    (fun ctx loc x k ->
370
      match x.exp_desc with
×
371
      | Texp_constant n ->
×
372
        ctx.matched <- ctx.matched + 1;
373
        f0 ctx loc n k
374
      | _ -> fail loc (sprintf "econst"))
×
375
;;
376

377
let eint (T f0) =
378
  T
470✔
379
    (fun ctx loc x k ->
380
      match x.exp_desc with
17✔
381
      | Texp_constant (Asttypes.Const_int n) ->
8✔
382
        ctx.matched <- ctx.matched + 1;
383
        f0 ctx loc n k
384
      | _ -> fail loc "eint")
9✔
385
;;
386

387
let estring =
388
  T
389
    (fun ctx loc x k ->
390
      match x.exp_desc with
15✔
391
      | Texp_constant (Asttypes.Const_string (s, _, None)) ->
15✔
392
        ctx.matched <- ctx.matched + 1;
393
        k s
394
      | _ -> fail loc "estring")
×
395
;;
396

397
let ebool =
398
  T
399
    (fun ctx loc x k ->
400
      match x.exp_desc with
95✔
401
      | Texp_construct ({ txt = Lident "true" }, _, []) ->
11✔
402
        ctx.matched <- ctx.matched + 1;
403
        k true
404
      | Texp_construct ({ txt = Lident "false" }, _, []) ->
8✔
405
        ctx.matched <- ctx.matched + 1;
406
        k false
407
      | _ -> fail loc (sprintf "ebool"))
76✔
408
;;
409

410
[%%if ocaml_version < (5, 0, 0)]
411

412
let tpat_var (T fname) =
413
  T
1,519✔
414
    (fun ctx loc x k ->
415
      match x.pat_desc with
51✔
416
      | Tpat_var (_, { txt }) ->
51✔
417
        ctx.matched <- ctx.matched + 1;
418
        k |> fname ctx loc txt
419
      | _ -> fail loc "tpat_var")
×
420
;;
421

422
let tpat_id (T fname) =
423
  T
1,888✔
424
    (fun ctx loc x k ->
425
      match x.pat_desc with
291✔
426
      | Tpat_var (id, { loc }) ->
231✔
427
        ctx.matched <- ctx.matched + 1;
428
        k |> fname ctx loc id
429
      | _ -> fail loc "tpat_var_id")
60✔
430
;;
431

432
[%%else]
433

434
let tpat_var (T fname) =
435
  T
436
    (fun (type kind) ctx loc (x : kind pattern_desc pattern_data) k ->
437
      match x.pat_desc with
438
      | Tpat_var (_, { txt }, _uid) ->
439
        ctx.matched <- ctx.matched + 1;
440
        k |> fname ctx loc txt
441
      | Tpat_value v ->
442
        (match (v :> pattern).pat_desc with
443
         | Tpat_var (_, { txt }, _uid) ->
444
           ctx.matched <- ctx.matched + 1;
445
           k |> fname ctx loc txt
446
         | _ -> fail loc "tpat_var")
447
      | _ -> fail loc "tpat_var")
448
;;
449

450
let tpat_id (T fname) =
451
  T
452
    (fun (type kind) ctx loc (x : kind pattern_desc pattern_data) k ->
453
      match x.pat_desc with
454
      | Typedtree.Tpat_value v ->
455
        (match (v :> pattern).pat_desc with
456
         | Tpat_var (id, { loc }, _uid) ->
457
           ctx.matched <- ctx.matched + 1;
458
           k |> fname ctx loc id
459
         | _ -> fail loc "tpat_id")
460
      | Tpat_var (id, { loc }, _uid) ->
461
        ctx.matched <- ctx.matched + 1;
462
        k |> fname ctx loc id
463
      | _ -> fail loc "tpat_id 2")
464
;;
465

466
[%%endif]
467

468
let tpat_constructor (T fname) (T fargs) =
469
  T
5,796✔
470
    (fun ctx loc x k ->
471
      match x.pat_desc with
84✔
472
      | Tpat_construct ({ txt }, _, args, _) ->
75✔
473
        ctx.matched <- ctx.matched + 1;
474
        k |> fname ctx loc txt |> fargs ctx loc args
66✔
475
      | _ -> fail loc "tpat_constructor")
9✔
476
;;
477

478
let tpat_tuple (T fargs) =
479
  T
×
480
    (fun ctx loc x k ->
481
      match x.pat_desc with
×
482
      | Tpat_tuple pats ->
×
483
        ctx.matched <- ctx.matched + 1;
484
        k |> fargs ctx loc pats
485
      | _ -> fail loc "tpat_tuple")
×
486
;;
487

488
let tpat_value (T fpat) =
489
  T
×
490
    (fun ctx loc x k ->
491
      match x.pat_desc with
×
492
      | Tpat_value arg ->
×
493
        let inner = (arg :> value pattern_desc pattern_data) in
494
        ctx.matched <- ctx.matched + 1;
495
        k |> fpat ctx loc inner
496
      | _ -> fail loc "tpat_value")
×
497
;;
498

499
let tpat_exception (T fpat) =
500
  T
×
501
    (fun ctx loc x k ->
502
      match x.pat_desc with
×
503
      | Tpat_exception exc ->
×
504
        ctx.matched <- ctx.matched + 1;
505
        k |> fpat ctx loc exc
506
      | _ -> fail loc "tpat_exception")
×
507
;;
508

509
let tpat_any =
510
  T
511
    (fun ctx loc x k ->
512
      match x.pat_desc with
3✔
513
      | Tpat_any ->
2✔
514
        ctx.matched <- ctx.matched + 1;
515
        k
516
      | _ -> fail loc "tpat_any")
1✔
517
;;
518

519
let texp_ident (T fpath) =
520
  T
14,703✔
521
    (fun ctx loc x k ->
522
      let __ _ = log "texp_ident %a\n%!" My_printtyped.expr x in
×
523
      match x.exp_desc with
524
      | Texp_ident (path, _, _) ->
11,725✔
525
        ctx.matched <- ctx.matched + 1;
526
        let ans = fpath ctx loc path k in
527
        log "texp_ident + %a\n%!" My_printtyped.expr x;
796✔
528
        ans
796✔
529
      | _ -> fail loc "texp_ident")
3,123✔
530
;;
531

532
let texp_ident_loc (T fpath) =
533
  T
1,247✔
534
    (fun ctx loc x k ->
535
      match x.exp_desc with
14✔
536
      | Texp_ident (path, _, _) ->
10✔
537
        ctx.matched <- ctx.matched + 1;
538
        k x.exp_loc |> fpath ctx loc path
10✔
539
      | _ -> fail loc "texp_ident")
4✔
540
;;
541

542
(* TODO(Kakadu): accept and Ident, and not a string *)
543
let pident (T fstr) =
544
  T
7,439✔
545
    (fun ctx loc x k ->
546
      match x with
211✔
547
      | Path.Pident id -> fstr ctx loc (Ident.name id) k
93✔
548
      | _ -> fail loc "pident")
118✔
549
;;
550

551
let texp_ident_typ (T fpath) (T ftyp) =
552
  T
279✔
553
    (fun ctx loc x k ->
554
      (* let __ _ = Format.printf "texp_ident_typ %a\n%!" MyPrinttyped.expr x in *)
555
      match x.exp_desc with
1,597✔
556
      | Texp_ident (path, _, typ) ->
829✔
557
        ctx.matched <- ctx.matched + 1;
558
        k |> fpath ctx loc path |> ftyp ctx loc typ.Types.val_type
437✔
559
      | _ -> fail loc "texp_ident_typ")
768✔
560
;;
561

562
[%%if ocaml_version < (5, 0, 0)]
563

564
let texp_assert (T fexp) =
565
  T
56✔
566
    (fun ctx loc x k ->
567
      match x.exp_desc with
1,457✔
568
      | Texp_assert e ->
1✔
569
        ctx.matched <- ctx.matched + 1;
570
        fexp ctx loc e k
571
      | _ -> fail loc "texp_assert")
1,456✔
572
;;
573

574
[%%else]
575

576
let texp_assert (T fexp) =
577
  T
578
    (fun ctx loc x k ->
579
       match x.exp_desc with
580
       | Texp_assert (e, _) ->
581
         ctx.matched <- ctx.matched + 1;
582
         fexp ctx loc e k
583
       | _ -> fail loc "texp_assert"
584
     : context -> Warnings.loc -> expression -> 'a -> 'b)
585
;;
586

587
[%%endif]
588

589
let texp_apply (T f0) (T args0) =
590
  T
5,963✔
591
    (fun ctx loc x k ->
592
      (* let __ _ = log "texp_apply %a\n%!" MyPrinttyped.expr x in *)
593
      match x.exp_desc with
25,683✔
594
      | Texp_apply (f, args) ->
3,584✔
595
        ctx.matched <- ctx.matched + 1;
596
        let ans = k |> f0 ctx loc f |> args0 ctx loc args in
73✔
597
        (* let _ = log "texp_apply + %a\n%!" MyPrinttyped.expr x in *)
598
        ans
43✔
599
      | _ -> fail loc "texp_apply")
22,099✔
600
;;
601

602
let texp_apply_nolabelled (T f0) (T args0) =
603
  let exception EarlyExit in
1,538✔
604
  T
605
    (fun ctx loc x k ->
606
      match x.exp_desc with
3,082✔
607
      | Texp_apply (f, args) ->
482✔
608
        ctx.matched <- ctx.matched + 1;
609
        let k = f0 ctx loc f k in
610
        (try
95✔
611
           let args =
612
             ListLabels.map args ~f:(function
613
               | Asttypes.Labelled _, _ | Asttypes.Optional _, _ | _, None ->
×
614
                 raise EarlyExit
615
               | _, Some x -> x)
206✔
616
           in
617
           args0 ctx loc args k
22✔
618
         with
619
         | EarlyExit -> fail loc "texp_apply: None among the arguments ")
2✔
620
      | _ -> fail loc "texp_apply")
2,600✔
621
;;
622

623
let texp_construct (T fpath) (T fcd) (T fargs) =
624
  T
216✔
625
    (fun ctx loc x k ->
626
      match x.exp_desc with
1,481✔
627
      | Texp_construct (path, cd, args) ->
192✔
628
        ctx.matched <- ctx.matched + 1;
629
        let k = fpath ctx loc path.txt k in
630
        k |> fcd ctx loc cd |> fargs ctx loc args
24✔
631
      | _ -> fail loc (sprintf "texp_construct"))
1,289✔
632
;;
633

634
let texp_assert_false () = texp_assert (texp_construct (lident (string "false")) drop nil)
56✔
635

636
let texp_let (T fvbs) (T fexpr) =
637
  T
1,469✔
638
    (fun ctx loc x k ->
639
      match x.exp_desc with
1,267✔
640
      | Texp_let (_flg, vbs, expr) ->
18✔
641
        ctx.matched <- ctx.matched + 1;
642
        k |> fvbs ctx loc vbs |> fexpr ctx loc expr
15✔
643
      | _ -> fail loc (sprintf "texp_let"))
1,249✔
644
;;
645

646
let nolabel =
647
  T
648
    (fun ctx loc x k ->
649
      match x with
253✔
650
      | Asttypes.Nolabel ->
234✔
651
        ctx.matched <- ctx.matched + 1;
652
        k
653
      | _ -> fail loc "nolabel")
19✔
654
;;
655

656
let labelled (T fstr) =
657
  T
56✔
658
    (fun ctx loc x k ->
659
      match x with
2✔
660
      | Asttypes.Labelled s ->
2✔
661
        ctx.matched <- ctx.matched + 1;
662
        k |> fstr ctx loc s
663
      | _ -> fail loc "labelled")
×
664
;;
665

666
let texp_apply1 f x = texp_apply f ((nolabel ** some x) ^:: nil)
3,404✔
667
let texp_apply2 f x y = texp_apply f ((nolabel ** some x) ^:: (nolabel ** some y) ^:: nil)
2,167✔
668

669
[%%if ocaml_version < (4, 11, 2)]
670

671
(* 4.10 *)
672
type case_val = Typedtree.case
673
type case_comp = Typedtree.case
674
type value_pat = pattern
675
type comp_pat = pattern
676

677
[%%else]
678

679
type case_val = value case
680
type case_comp = computation case
681
type value_pat = value pattern_desc pattern_data
682
type comp_pat = computation pattern_desc pattern_data
683

684
[%%endif]
685
[%%if ocaml_version < (5, 0, 0)]
686

687
let texp_function (T fcases) =
UNCOV
688
  T
×
689
    (fun ctx loc e k ->
UNCOV
690
      match e.exp_desc with
×
UNCOV
691
      | Texp_function { cases } ->
×
692
        ctx.matched <- ctx.matched + 1;
693
        k |> fcases ctx loc cases
694
      | _ -> fail loc "texp_function")
×
695
;;
696

697
let texp_function_body (T fargs) (T frhs) =
698
  let rec helper acc ctx loc e k =
6,786✔
699
    match e.exp_desc with
6,265✔
700
    | Texp_function
944✔
701
        { cases =
702
            [ { c_lhs = { pat_desc = Tpat_var (pid, _); pat_loc; _ }
703
              ; c_rhs
704
              ; c_guard = None
705
              }
706
            ]
707
        ; arg_label
708
        ; partial = Total
709
        } -> helper ((arg_label, (pid, pat_loc)) :: acc) ctx loc c_rhs k
710
    | _ when [] = acc -> fail loc "texp_function_body"
4,631✔
711
    | _ -> k |> fargs ctx loc (List.rev acc) |> frhs ctx loc e
603✔
712
  in
713
  T (helper [])
6,786✔
714
;;
715

716
let texp_function_cases
717
  :  ((Asttypes.arg_label * (Ident.t * Location.t)) list, 'a, 'b) t
718
  -> (value case list, 'b, 'c) t -> (expression, 'a, 'c) t
719
  =
720
  fun (T fargs) (T frhs) ->
721
  let rec helper acc ctx loc e k =
5,818✔
722
    match e.exp_desc with
4,730✔
723
    | Typedtree.Texp_function
560✔
724
        { cases =
725
            [ { c_lhs = { pat_desc = Tpat_var (pid, tag); _ }; c_rhs; c_guard = _ } ]
726
        ; arg_label
727
        ; partial = Total
728
        } -> helper ((arg_label, (pid, tag.loc)) :: acc) ctx loc c_rhs k
729
    | Texp_function { cases = _ :: _ :: _ as cases; _ } ->
91✔
730
      k |> fargs ctx loc (List.rev acc) |> frhs ctx loc cases
62✔
731
    | _ -> fail loc "texp_function_cases"
4,079✔
732
  in
733
  T (helper [])
5,818✔
734
;;
735

736
[%%else]
737

738
let texp_function_cases (T fparam) (T fcases) =
739
  T
740
    (fun ctx loc e k ->
741
      match e.exp_desc with
742
      | Texp_function (params, Tfunction_cases cases) ->
743
        ctx.matched <- ctx.matched + 1;
744
        k
745
        |> fparam
746
             ctx
747
             loc
748
             (List.map (fun p -> p.Typedtree.fp_arg_label, (p.fp_param, p.fp_loc)) params)
749
        |> fcases ctx loc cases.cases
750
      | _ -> fail loc "texp_function")
751
;;
752

753
let texp_function_body (T fparam) (T fcases) =
754
  T
755
    (fun ctx loc e k ->
756
      match e.exp_desc with
757
      | Typedtree.Texp_function (params, Tfunction_body e) ->
758
        ctx.matched <- ctx.matched + 1;
759
        k
760
        |> fparam
761
             ctx
762
             loc
763
             (List.map (fun p -> p.fp_arg_label, (p.fp_param, p.fp_loc)) params)
764
        |> fcases ctx loc e
765
      | _ -> fail loc "texp_function")
766
;;
767

768
[%%endif]
769

770
let case (T pat) (T guard) (T rhs) =
771
  T
7,319✔
772
    (fun ctx loc { c_lhs; c_rhs; c_guard } k ->
773
      k |> pat ctx loc c_lhs |> guard ctx loc c_guard |> rhs ctx loc c_rhs)
53✔
774
;;
775

776
let ccase (T pat) (T guard) (T rhs) =
777
  T
×
778
    (fun ctx loc { c_lhs; c_rhs; c_guard } k ->
779
      k |> pat ctx loc c_lhs |> guard ctx loc c_guard |> rhs ctx loc c_rhs)
×
780
;;
781

782
[%%if ocaml_version < (5, 0, 0)]
783

784
let texp_match (T fexpr) (T fcomp_cases) (T fval_cases) =
785
  let rec split (type _a) (comps, vals) (cases : _ case list) =
2,726✔
786
    let _ : case_comp list = comps in
209✔
787
    let _ : case_val list = vals in
788
    let wrap (type a) comps vals : a case -> case_comp list * case_val list =
789
      let _ : case_comp list = comps in
143✔
790
      let _ : case_val list = vals in
791
      fun case ->
792
        match case with
143✔
793
        | { c_lhs = { pat_desc = Tpat_value p }; _ } ->
140✔
794
          ( comps
795
          , { c_lhs = (p :> pattern); c_rhs = case.c_rhs; c_guard = case.c_guard } :: vals
796
          )
797
        | { c_lhs = { pat_desc = Tpat_any }; _ } -> comps, (case :> case_val) :: vals
×
798
        | { c_lhs = { pat_desc = Tpat_var _ }; _ } -> comps, (case :> case_val) :: vals
×
799
        | { c_lhs = { pat_desc = Tpat_alias _ }; _ } -> comps, (case :> case_val) :: vals
×
800
        | { c_lhs = { pat_desc = Tpat_constant _ }; _ } ->
×
801
          comps, (case :> case_val) :: vals
802
        | { c_lhs = { pat_desc = Tpat_construct _ }; _ } ->
×
803
          comps, (case :> case_val) :: vals
804
        | { c_lhs = { pat_desc = Tpat_variant _ }; _ } ->
×
805
          comps, (case :> case_val) :: vals
806
        | { c_lhs = { pat_desc = Tpat_record _ }; _ } -> comps, (case :> case_val) :: vals
×
807
        | { c_lhs = { pat_desc = Tpat_array _ }; _ } -> comps, (case :> case_val) :: vals
×
808
        | { c_lhs = { pat_desc = Tpat_lazy _ }; _ } -> comps, (case :> case_val) :: vals
×
809
        (* | { c_lhs = { pat_desc = Tpat_value _ }; _ } -> (case :> case_comp) :: comps, vals *)
810
        | { c_lhs = { pat_desc = Tpat_exception _ }; _ } ->
3✔
811
          (case :> case_comp) :: comps, vals
812
        | { c_lhs = { pat_desc = Tpat_or _ }; _ } ->
×
813
          failwith "Or-patterns are not yet implemented"
814
        | { c_lhs; _ } ->
×
815
          (* Format.eprintf "%a\n%!" My_printtyped.pattern c_lhs; *)
816
          Format.eprintf
817
            "Unsupported pattern: tag = %d, is_block = %b\n"
818
            Obj.(tag @@ repr c_lhs)
×
819
            Obj.(is_block @@ repr c_lhs);
×
820
          assert false
×
821
    in
822
    match cases with
823
    | h :: tl -> split (wrap comps vals h) tl
143✔
824
    | [] -> List.rev comps, List.rev vals
66✔
825
  in
826
  T
827
    (fun ctx loc e k ->
828
      match e.exp_desc with
2,944✔
829
      | Texp_match (e, cases, _) ->
66✔
830
        ctx.matched <- ctx.matched + 1;
831
        let comp_cases, val_cases = split ([], []) cases in
832
        (* log
833
           "There are %d comp cases and %d val cases"
834
           (List.length comp_cases)
835
           (List.length val_cases); *)
836
        k
66✔
837
        |> fexpr ctx loc e
838
        |> fcomp_cases ctx loc comp_cases
61✔
839
        |> fval_cases ctx loc val_cases
61✔
840
      | _ -> fail loc "texp_match")
2,878✔
841
;;
842

843
[%%else]
844

845
let texp_match (T fexpr) (T fcomp_cases) (T fval_cases) =
846
  T
847
    (fun ctx loc e k ->
848
      match e.Typedtree.exp_desc with
849
      | Texp_match (e, ccases, vcases, _) ->
850
        let ccases, vcases =
851
          List.fold_left
852
            (fun (cacc, vacc) c ->
853
              match c.c_lhs.pat_desc with
854
              | Tpat_value v ->
855
                cacc, { c with c_lhs = (v :> value general_pattern) } :: vacc
856
              | _ -> cacc, vacc)
857
            ([], vcases)
858
            ccases
859
        in
860
        ctx.matched <- ctx.matched + 1;
861
        k |> fexpr ctx loc e |> fcomp_cases ctx loc ccases |> fval_cases ctx loc vcases
862
      | _ -> fail loc "texp_match")
863
;;
864

865
[%%endif]
866

867
let texp_ite (T pred) (T fthen) (T felse) =
868
  T
672✔
869
    (fun ctx loc e k ->
870
      match e.exp_desc with
7,895✔
871
      | Texp_ifthenelse (p, thenb, elseb) ->
185✔
872
        ctx.matched <- ctx.matched + 1;
873
        k |> pred ctx loc p |> fthen ctx loc thenb |> felse ctx loc elseb
77✔
874
      | _ -> fail loc "texp_ite")
7,710✔
875
;;
876

877
[%%if ocaml_version < (5, 0, 0)]
878

879
let texp_try (T fexpr) (T fcases) =
880
  T
56✔
881
    (fun ctx loc e k ->
882
      match e.exp_desc with
1,459✔
883
      | Texp_try (e, cases) ->
3✔
884
        ctx.matched <- ctx.matched + 1;
885
        k |> fexpr ctx loc e |> fcases ctx loc cases
3✔
886
      | _ -> fail loc "texp_try")
1,456✔
887
;;
888

889
[%%else]
890

891
let texp_try (T fexpr) (T fcases) =
892
  T
893
    (fun ctx loc e k ->
894
      match e.exp_desc with
895
      | Typedtree.Texp_try (e, cases, _) ->
896
        (* TODO: support effects *)
897
        ctx.matched <- ctx.matched + 1;
898
        k |> fexpr ctx loc e |> fcases ctx loc cases
899
      | _ -> fail loc "texp_try")
900
;;
901

902
[%%endif]
903

904
let texp_record (T fext) (T ffields) =
905
  T
1,467✔
906
    (fun ctx loc e k ->
907
      match e.exp_desc with
1,467✔
908
      | Texp_record { fields; extended_expression; _ } ->
19✔
909
        ctx.matched <- ctx.matched + 1;
910
        k |> fext ctx loc extended_expression |> ffields ctx loc fields
19✔
911
      | _ -> fail loc "texp_record")
1,448✔
912
;;
913

914
let texp_field (T fexpr) (T fdesc) =
915
  T
56✔
916
    (fun ctx loc e k ->
917
      match e.exp_desc with
51✔
918
      | Texp_field (e, _, desc) ->
17✔
919
        ctx.matched <- ctx.matched + 1;
920
        k |> fexpr ctx loc e |> fdesc ctx loc desc
17✔
921
      | _ -> fail loc "texp_field")
34✔
922
;;
923

924
let label_desc (T fname) =
925
  T
112✔
926
    (fun ctx loc e k ->
927
      match e with
95✔
928
      | { Types.lbl_name; _ } ->
95✔
929
        ctx.matched <- ctx.matched + 1;
930
        k |> fname ctx loc lbl_name)
931
;;
932

933
let rld_kept =
934
  T
935
    (fun ctx loc e k ->
936
      match e with
56✔
937
      | Kept _ ->
×
938
        ctx.matched <- ctx.matched + 1;
939
        k
940
      | _ -> fail loc "rld_kept")
56✔
941
;;
942

943
let rld_overriden (T flident) (T fexpr) =
944
  T
112✔
945
    (fun ctx loc e k ->
946
      match e with
95✔
947
      | Overridden ({ txt = lident }, e) ->
95✔
948
        ctx.matched <- ctx.matched + 1;
949
        k |> flident ctx loc lident |> fexpr ctx loc e
85✔
950
      | _ -> fail loc "rld_overriden")
×
951
;;
952

953
let value_binding (T fpat) (T fexpr) =
954
  T
1,573✔
955
    (fun ctx loc { vb_pat; vb_expr } k ->
956
      ctx.matched <- ctx.matched + 1;
119✔
957
      k |> fpat ctx loc vb_pat |> fexpr ctx loc vb_expr)
117✔
958
;;
959

960
(*   let hack0 (T path0) =
961
     T
962
     (fun ctx loc x k ->
963
     match x.Types.val_type.Types.desc with
964
     | Tconstr (path, [], _) ->
965
     ctx.matched <- ctx.matched + 1;
966
     path0 ctx loc path k
967
     | _ -> fail loc "hack0")
968
     ;;
969

970
     let hack1 ?(on_vd = drop) (T path0) =
971
     T
972
     (fun ctx loc x k ->
973
     match x.exp_desc with
974
     | Texp_ident (path, _, vd) ->
975
     ctx.matched <- ctx.matched + 1;
976
     let (T fvd) = on_vd in
977
     k |> path0 ctx loc path |> fvd ctx loc vd
978
     | _ -> fail loc "texp_ident")
979
     ;;
980

981
     let __ path = hack1 __ path *)
982
let rec core_typ (T ftexpr) = T (fun ctx loc x k -> ftexpr ctx loc x.ctyp_type k)
166✔
983

984
let rec typ_constr (T fpath) (T fargs) =
985
  let rec helper ctx loc x k =
661✔
986
    (* Format.printf "typ = %a\n%!" Printtyp.type_expr x; *)
987
    match Types.get_desc x with
2,374✔
988
    | Tconstr (path, args, _) ->
1,277✔
989
      ctx.matched <- ctx.matched + 1;
990
      k |> fpath ctx loc path |> fargs ctx loc args
205✔
991
    | Tlink arg -> helper ctx loc arg k
×
992
    | _ -> fail loc "typ_constr"
1,097✔
993
  in
994
  T helper
995
;;
996

997
let rec typ_arrow (T l) (T r) =
998
  let rec helper ctx loc x k =
338✔
999
    (* Format.printf "typ = %a\n%!" Printtyp.type_expr x; *)
1000
    match Types.get_desc x with
22✔
1001
    | Tarrow (_, tl, tr, _) ->
22✔
1002
      ctx.matched <- ctx.matched + 1;
1003
      k |> l ctx loc tl |> r ctx loc tr
22✔
1004
    | _ -> fail loc "typ_arrow"
×
1005
  in
1006
  T helper
1007
;;
1008

1009
let typ_kind_abstract =
1010
  T
1011
    (fun ctx loc x k ->
1012
      match x with
67✔
1013
      | Typedtree.Ttype_abstract ->
8✔
1014
        ctx.matched <- ctx.matched + 1;
1015
        k
1016
      | _ -> fail loc "typ_kind_abstract")
59✔
1017
;;
1018

1019
let typ_kind_open =
1020
  T
1021
    (fun ctx loc x k ->
1022
      match x with
67✔
NEW
1023
      | Typedtree.Ttype_open ->
×
1024
        ctx.matched <- ctx.matched + 1;
1025
        k
1026
      | _ -> fail loc "typ_kind_open")
67✔
1027
;;
1028

1029
let typ_kind_variant =
1030
  T
1031
    (fun ctx loc x k ->
1032
      match x with
59✔
1033
      | Typedtree.Ttype_variant _ ->
49✔
1034
        ctx.matched <- ctx.matched + 1;
1035
        k
1036
      | _ -> fail loc "typ_kind_variant")
10✔
1037
;;
1038

1039
let typ_kind_record (T flabels) =
1040
  T
54✔
1041
    (fun ctx loc x k ->
1042
      match x with
10✔
1043
      | Typedtree.Ttype_record labels ->
10✔
1044
        ctx.matched <- ctx.matched + 1;
1045
        k |> flabels ctx loc labels
NEW
1046
      | _ -> fail loc "typ_kind_record")
×
1047
;;
1048

1049
(* Structure *)
1050

1051
let tstr_attribute (T fattr) =
1052
  T
40✔
1053
    (fun ctx loc str k ->
1054
      match str.str_desc with
40✔
1055
      | Tstr_attribute attr ->
15✔
1056
        ctx.matched <- ctx.matched + 1;
1057
        k |> fattr ctx loc attr
1058
      | _ -> fail loc "tstr_attribute")
25✔
1059
;;
1060

1061
let tsig_attribute (T fattr) =
1062
  T
3✔
1063
    (fun ctx loc str k ->
1064
      match str.sig_desc with
3✔
1065
      | Tsig_attribute attr ->
2✔
1066
        ctx.matched <- ctx.matched + 1;
1067
        k |> fattr ctx loc attr
1068
      | _ -> fail loc "tsig_attribute")
1✔
1069
;;
1070

1071
let tsig_val_name (T fname) =
1072
  T
×
1073
    (fun ctx loc str k ->
1074
      match str.sig_desc with
×
1075
      | Tsig_value { val_id = txt } ->
×
1076
        ctx.matched <- ctx.matched + 1;
1077
        k |> fname ctx loc txt
1078
      | _ -> fail loc "tsig_val_name")
×
1079
;;
1080

1081
let attribute (T fname) (T fpayload) =
1082
  T
43✔
1083
    (fun ctx loc attr k ->
1084
      let open Parsetree in
17✔
1085
      k |> fname ctx loc attr.attr_name.txt |> fpayload ctx loc attr.attr_payload)
17✔
1086
;;
1087

1088
let payload_stru (T fstru) =
1089
  T
43✔
1090
    (fun ctx loc x k ->
1091
      match x with
17✔
1092
      | Parsetree.PStr stru -> k |> fstru ctx loc stru
17✔
NEW
1093
      | _ -> fail loc "payload_stru")
×
1094
;;
1095

1096
let pstr_eval (T f) =
1097
  T
43✔
1098
    (fun ctx loc x k ->
1099
      match x.Parsetree.pstr_desc with
17✔
1100
      | Parsetree.Pstr_eval (e, _) -> k |> f ctx loc e
17✔
NEW
1101
      | _ -> fail loc "pstr_eval")
×
1102
;;
1103

1104
let pexp_constant (T f) =
1105
  T
43✔
1106
    (fun ctx loc e k ->
1107
      match e.Parsetree.pexp_desc with
17✔
1108
      | Parsetree.Pexp_constant e -> k |> f ctx loc e
13✔
1109
      | _ -> fail loc "pexp_constant")
4✔
1110
;;
1111

1112
[%%if ocaml_version < (5, 0, 0)]
1113

1114
let pexp_function_cases (T fargs) (T fcases) =
1115
  let open Parsetree in
3✔
1116
  let rec helper acc ctx loc x k =
1117
    match x.pexp_desc with
9✔
1118
    | Pexp_fun (Asttypes.Nolabel, None, pat, rhs) -> helper (pat :: acc) ctx loc rhs k
6✔
1119
    | Pexp_function cases -> k |> fargs ctx loc (List.rev acc) |> fcases ctx loc cases
3✔
1120
    | _ -> fail loc "pexp_function_cases"
×
1121
  in
1122
  T (helper [])
3✔
1123
;;
1124

1125
let pexp_function_body (T fargs) (T fcases) =
1126
  let open Parsetree in
1✔
1127
  let rec helper acc ctx loc x k =
1128
    match x.pexp_desc with
3✔
1129
    | Pexp_fun (Asttypes.Nolabel, None, pat, rhs) -> helper (pat :: acc) ctx loc rhs k
2✔
1130
    | _ -> k |> fargs ctx loc (List.rev acc) |> fcases ctx loc x
1✔
1131
  in
1132
  T (helper [])
1✔
1133
;;
1134

1135
let pconst_string (T fstring) =
1136
  T
43✔
1137
    (fun ctx loc x k ->
1138
      match x with
13✔
1139
      | Parsetree.Pconst_string (s, _, _) -> k |> fstring ctx loc s
13✔
NEW
1140
      | _ -> fail loc "pconst_string")
×
1141
;;
1142

1143
[%%else]
1144

1145
let pexp_function_body (T fargs) (T fbody) =
1146
  let open Parsetree in
1147
  T
1148
    (fun ctx loc x k ->
1149
      match x.pexp_desc with
1150
      | Pexp_function (params, _, Pfunction_body e) ->
1151
        let args =
1152
          List.map
1153
            (fun p ->
1154
              match p.pparam_desc with
1155
              | Pparam_val (Nolabel, _, pat) -> pat
1156
              | Pparam_newtype _ | _ -> fail loc "pexp_function_body: params")
1157
            params
1158
        in
1159
        k |> fargs ctx loc args |> fbody ctx loc e
1160
      | _ -> fail loc "pexp_function_body")
1161
;;
1162

1163
let pexp_function_cases (T fargs) (T fcases) =
1164
  let open Parsetree in
1165
  T
1166
    (fun ctx loc x k ->
1167
      match x.pexp_desc with
1168
      | Pexp_function (params, _, Pfunction_cases (cases, _, _)) ->
1169
        let args =
1170
          List.map
1171
            (fun p ->
1172
              match p.pparam_desc with
1173
              | Pparam_val (Nolabel, _, pat) -> pat
1174
              | Pparam_newtype _ | _ -> fail loc "pexp_function_cases: params")
1175
            params
1176
        in
1177
        k |> fargs ctx loc args |> fcases ctx loc cases
1178
      | _ -> fail loc "pexp_function_cases")
1179
;;
1180

1181
let pconst_string (T fstring) =
1182
  T
1183
    (fun ctx loc x k ->
1184
      match x.Parsetree.pconst_desc with
1185
      | Parsetree.Pconst_string (s, _, _) -> k |> fstring ctx loc s
1186
      | _ -> fail loc "pconst_string")
1187
;;
1188

1189
[%%endif]
1190

1191
let pexp_apply (T f) (T fargs) =
1192
  let open Parsetree in
1✔
1193
  let helper ctx loc x k =
1194
    match x.pexp_desc with
1✔
1195
    | Pexp_apply (efun, eargs) -> k |> f ctx loc efun |> fargs ctx loc eargs
1✔
1196
    | _ -> fail loc "pexp_apply"
×
1197
  in
1198
  T helper
1199
;;
1200

1201
let tstr_docattr on_str =
1202
  tstr_attribute
40✔
1203
    (attribute
40✔
1204
       drop
1205
       (payload_stru (pstr_eval (pexp_constant (pconst_string on_str)) ^:: nil)))
40✔
1206
;;
1207

1208
let tsig_docattr on_str =
1209
  tsig_attribute
3✔
1210
    (attribute
3✔
1211
       drop
1212
       (payload_stru (pstr_eval (pexp_constant (pconst_string on_str)) ^:: nil)))
3✔
1213
;;
1214

1215
type context = Ast_pattern0.context
1216

1217
let of_func f = T f
×
1218
let to_func (T f) = f
×
1219
let fail = fail
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc