-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathimap_parser.ml
59 lines (52 loc) · 1.54 KB
/
imap_parser.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
(** Copyright (c) 2008,2009 Anil Madhavapeddy <anil@recoil.org>
** See the COPYING file included in this distribution for licensing details *)
open Printf
type t = {
buf: string;
pos: int;
}
let t buf = { buf=buf; pos=0 }
(* Apply a function to a parser state *)
let apply fn t =
fn t.buf.[t.pos]
(* Move the parser forward *)
let advance p n =
eprintf "advance: %d (%s) by %d\n" p.pos p.buf n;
{ p with pos=p.pos+n }
(* Consume one terminal and advance parser *)
let one testfn charfn p =
if apply testfn p then begin
let c = apply charfn p in
Some (advance p 1, c)
end
else None
(* Keep grabbing from the fn until the test fails,
and return the list *)
exception Repeat_failed
exception Repeat_done
let repeat ~min ~max fn p =
let p = ref p in
let ret = ref [] in
try
for i = 0 to min do
match fn !p with
|Some (p',x) -> ret := x :: !ret; p := p'
|None -> raise Repeat_failed
done;
begin match max with
|0 (* continue until it fails *) ->
while true do
match fn !p with
|Some (p',x) -> ret := x :: !ret; p := p'
|None -> raise Repeat_done
done
|max -> (* maximum number *)
for i = min to max do
match fn !p with
|Some (p',x) -> ret := x :: !ret; p := p'
|None -> raise Repeat_done
done
end; None
with
|Repeat_failed -> None
|Repeat_done -> Some (!p, List.rev !ret)