OCaml parser combinator that compiles to direct recursive descent
1.5 kB
55 lines
1module type INPUT = sig
2 type t
3 type token
4 val peek : t -> token option
5 val advance : t -> t
6 val position : t -> int
7 val show_token : token -> string
8end
9
10type error = {
11 pos : int;
12 expected : string list;
13}
14
15let merge_errors e1 e2 =
16 if e1.pos > e2.pos then e1
17 else if e2.pos > e1.pos then e2
18 else { pos = e1.pos; expected = e1.expected @ e2.expected }
19
20let pure x _input = Ok (x, _input)
21
22let fail msg _input = Error { pos = 0; expected = [msg] }
23
24module Char_input : sig
25 include INPUT with type token = char
26 val of_string : string -> t
27end = struct
28 type token = char
29 type t = { data : string; pos : int }
30
31 let of_string s = { data = s; pos = 0 }
32
33 let peek { data; pos } =
34 if pos >= String.length data then None
35 else Some (String.get data pos)
36
37 let advance t = { t with pos = t.pos + 1 }
38 let position t = t.pos
39 let show_token c = Printf.sprintf "'%c'" c
40end
41
42let parse_string parser s =
43 let input = Char_input.of_string s in
44 parser (module Char_input : INPUT with type t = Char_input.t and type token = char) input
45
46let format_error ?(input = "") e =
47 let context =
48 if String.length input > 0 && e.pos < String.length input then
49 let start = max 0 (e.pos - 10) in
50 let len = min 20 (String.length input - start) in
51 Printf.sprintf " near '%s'" (String.sub input start len)
52 else ""
53 in
54 Printf.sprintf "parse error at position %d%s: expected %s"
55 e.pos context (String.concat " or " e.expected)