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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
let compare_int = Int.compare
module Comparable = struct
let lift cmp ~f x y = cmp (f x) (f y)
let lexicographic cmps x y =
let rec loop = function
| cmp :: cmps ->
let res = cmp x y in
if res = 0 then loop cmps else res
| [] -> 0
in
loop cmps
;;
end
module Fn = struct
let id = Fun.id
end
module Char = struct
include Char
let is_whitespace = function
| '\t' | '\n' | '\011' | '\012' | '\r' | ' ' ->
true
| _ -> false
;;
let ( = ) : char -> char -> bool = equal
let ( <> ) l r = not (l = r)
end
module List = struct
include ListLabels
let take_while ~f:p l =
let[@tail_mod_cons] rec aux = function
| x :: l when p x -> x :: aux l
| _rest -> []
in
aux l
;;
let rec drop_while ~f:p = function
| x :: l when p x -> drop_while ~f:p l
| rest -> rest
;;
let is_empty = function
| [] -> true
| _ -> false
;;
let min_elt ~compare = function
| [] -> None
| h :: tl ->
Some
(fold_left
~f:(fun acc x ->
match compare acc x with
| -1 | 0 -> acc
| _ -> x)
~init:h
tl)
;;
let fold_map t ~init ~f =
let acc = ref init in
let result =
map t ~f:(fun x ->
let new_acc, y = f !acc x in
acc := new_acc;
y)
in
!acc, result
;;
let remove_consecutive_duplicates ?(which_to_keep = `Last) list ~equal =
let rec loop to_keep accum = function
| [] -> to_keep :: accum
| hd :: tl ->
if equal hd to_keep
then (
let to_keep =
match which_to_keep with
| `First -> to_keep
| `Last -> hd
in
loop to_keep accum tl)
else loop hd (to_keep :: accum) tl
in
match list with
| [] -> []
| hd :: tl -> rev (loop hd [] tl)
;;
(** returns sorted version of list with duplicates removed *)
let dedup_and_sort list ~compare =
match list with
| [] | [ _ ] -> list
| _ ->
let equal x x' = compare x x' = 0 in
let sorted = sort ~cmp:compare list in
(remove_consecutive_duplicates ~equal sorted [@nontail])
;;
let sort l ~compare = Stdlib.ListLabels.sort l ~cmp:compare
end
module String = struct
include StringLabels
let chop_prefix_if_exists path ~prefix =
if starts_with ~prefix path
then StringLabels.sub path ~pos:(length prefix) ~len:(length path - length prefix)
else path
;;
let rfindi ?pos t ~f =
let rec loop i = if i < 0 then None else if f i t.[i] then Some i else loop (i - 1) in
let pos =
match pos with
| Some pos -> pos
| None -> String.length t - 1
in
loop pos
;;
let prefix s n = String.sub s 0 n
let last_non_drop ~drop t = rfindi t ~f:(fun _ c -> not (drop c))
let is_whitespace = function
| '\t' | '\n' | '\011' | '\012' | '\r' | ' ' ->
true
| _ -> false
;;
let rstrip ?(drop = is_whitespace) t =
match last_non_drop t ~drop with
| None -> ""
| Some i -> if i = String.length t - 1 then t else prefix t (i + 1)
;;
let is_empty = ( = ) ""
let to_list s =
let rec loop acc i = if i < 0 then acc else loop (s.[i] :: acc) (i - 1) in
loop [] (length s - 1)
;;
let split_lines =
let back_up_at_newline ~t ~pos ~eol =
pos := !pos - if !pos > 0 && Char.equal t.[!pos - 1] '\r' then 2 else 1;
eol := !pos + 1
in
fun t ->
let n = length t in
if n = 0
then []
else (
let pos = ref (n - 1) in
let eol = ref n in
let ac = ref [] in
if Char.equal t.[!pos] '\n' then back_up_at_newline ~t ~pos ~eol;
while !pos >= 0 do
if Char.( <> ) t.[!pos] '\n'
then decr pos
else (
let start = !pos + 1 in
ac := sub t ~pos:start ~len:(!eol - start) :: !ac;
back_up_at_newline ~t ~pos ~eol)
done;
sub t ~pos:0 ~len:!eol :: !ac)
;;
let split_on_char ~on s = String.split_on_char on s
let strip = Stdlib.String.trim
let concat ?(sep = "") xs = String.concat sep xs
let sub = StringLabels.sub
let subo ?(pos = 0) ?len src =
sub
src
~pos
~len:
(match len with
| Some i -> i
| None -> length src - pos)
;;
include (
struct
let substr_index_gen ~case_sensitive ?pos t ~pattern =
Search_patternW.index ?pos (Search_patternW.create ~case_sensitive pattern) ~in_:t
;;
let is_substring_gen ~case_sensitive t ~substring =
Option.is_some (substr_index_gen t ~pattern:substring ~case_sensitive)
;;
let is_substring = is_substring_gen ~case_sensitive:true
end :
sig
val is_substring : t -> substring:t -> bool
end)
let count s ~f:is_good =
String.fold_left (fun acc c -> if is_good c then acc + 1 else acc) 0 s
;;
end
module Option = struct
include Option
let to_list = function
| Some x -> [ x ]
| None -> []
;;
let bind x ~f = Option.bind x f
let value x ~default =
match x with
| Some x -> x
| None -> default
;;
let map x ~f =
match x with
| None -> None
| Some x -> Some (f x)
;;
let value_exn = Option.get
let iter ~f = function
| Some x -> f x
| None -> ()
;;
end
module Staged = struct
type 'a t = 'a
let stage = Fn.id
let unstage = Fn.id
end
module Source_code_position = struct
type t = Lexing.position
let make_location_string ~pos_fname ~pos_lnum ~pos_cnum ~pos_bol =
String.concat
~sep:""
[ pos_fname; ":"; Int.to_string pos_lnum; ":"; Int.to_string (pos_cnum - pos_bol) ]
;;
let to_string { Stdlib.Lexing.pos_fname; pos_lnum; pos_cnum; pos_bol } =
make_location_string ~pos_fname ~pos_lnum ~pos_cnum ~pos_bol
;;
end
module Queue = struct
include Queue
let enqueue q x = add x q
let to_list t =
let acc = ref [] in
Queue.iter (fun x -> acc := x :: !acc) t;
List.rev !acc
;;
end