package sexp

  1. Overview
  2. Docs

Source file query.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
open! Core

module Set_kind = struct
  type t =
    { optional : bool
    ; first_only : bool
    }
  [@@deriving sexp]
end

type t =
  | Capture_unlabeled of t
  | Capture_to_number of int * t
  | Capture_to_name of string * t
  | Any
  | Atom of string
  | Atom_regex of string
  | Sequence of t list
  | Star of t
  | Star_greedy of t
  | Plus of t
  | Plus_greedy of t
  | Maybe of t
  | Maybe_greedy of t
  | List of t
  | Set of (t * Set_kind.t) list
  | Subsearch of t
  | And of t list
  | Or_shortcircuiting of t list
  | Or_all of t list
  | First_match_only of t
[@@deriving sexp]

let rec iter t ~f =
  f t;
  match t with
  | Any | Atom _ | Atom_regex _ -> ()
  | Capture_unlabeled sub
  | Capture_to_number (_, sub)
  | Capture_to_name (_, sub)
  | Subsearch sub
  | First_match_only sub
  | Star sub
  | Star_greedy sub
  | Plus sub
  | Plus_greedy sub
  | Maybe sub
  | Maybe_greedy sub
  | List sub -> iter sub ~f
  | Sequence subs | And subs | Or_shortcircuiting subs | Or_all subs ->
    List.iter subs ~f:(fun sub -> iter sub ~f)
  | Set subs -> List.iter subs ~f:(fun (sub, _) -> iter sub ~f)
;;

module Capture_count = struct
  type t =
    { num_number_captures : int
    ; num_named_captures : int
    ; num_unlabeled_captures : int
    }
end

let count_captures t =
  let num_number_captures = ref 0 in
  let num_named_captures = ref 0 in
  let num_unlabeled_captures = ref 0 in
  iter t ~f:(function
    | Capture_unlabeled _ -> incr num_unlabeled_captures
    | Capture_to_number _ -> incr num_number_captures
    | Capture_to_name _ -> incr num_named_captures
    | Any
    | Atom _
    | Atom_regex _
    | Subsearch _
    | First_match_only _
    | Star _
    | Star_greedy _
    | Plus _
    | Plus_greedy _
    | Maybe _
    | Maybe_greedy _
    | List _
    | Sequence _
    | And _
    | Or_shortcircuiting _
    | Or_all _
    | Set _ -> ());
  { Capture_count.num_number_captures = !num_number_captures
  ; num_named_captures = !num_named_captures
  ; num_unlabeled_captures = !num_unlabeled_captures
  }
;;

let validate_all_captures_labeled_or_all_unlabeled_exn t =
  let { Capture_count.num_number_captures; num_named_captures; num_unlabeled_captures } =
    count_captures t
  in
  if num_unlabeled_captures > 0 && (num_number_captures > 0 || num_named_captures > 0)
  then
    failwith
      "Cannot mix unlabeled captures with named or numbered captures in the same pattern"
;;
OCaml

Innovation. Community. Security.