-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathnice_parser.ml
95 lines (82 loc) · 2.65 KB
/
nice_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
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
let reraise exn =
Printexc.(raise_with_backtrace exn (get_raw_backtrace ()))
module type RAW_PARSER = sig
type token
type result
exception LexError of string
exception ParseError
val next_token : Lexing.lexbuf -> token
val parse : (Lexing.lexbuf -> token) -> Lexing.lexbuf -> result
end
module type NICE_PARSER = sig
type token
type result
exception LexError of { msg: string; loc: Location.t }
exception ParseError of { token: token; loc: Location.t }
val pp_exceptions : unit -> unit
val parse_string : ?pos:Lexing.position -> string -> result
val parse_chan : ?pos:Lexing.position -> in_channel -> result
val parse_file : string -> result
end
module Make (P : RAW_PARSER) : NICE_PARSER with
type token = P.token and
type result = P.result
= struct
type token = P.token
type result = P.result
exception LexError of { msg: string; loc: Location.t }
exception ParseError of { token: token; loc:Location.t }
let pp_exceptions () = begin
Location.register_error_of_exn (function
| LexError {msg; loc} ->
Some (Location.error ~loc msg)
| ParseError {loc; _} ->
Some (Location.error ~loc "[parser] unexpected token")
| _ ->
None
);
Printexc.register_printer (function exn ->
try
ignore (Format.flush_str_formatter ());
Location.report_exception Format.str_formatter exn;
Some (Format.flush_str_formatter ());
with _ ->
None
);
end
let curr_token : token option ref =
ref None
let next_token lexbuf =
let token = P.next_token lexbuf in
curr_token := Some token;
token
let parse ?(file="") lexbuf =
Location.input_name := file;
Location.input_lexbuf := Some lexbuf;
try
P.parse next_token lexbuf
with
| P.LexError msg ->
reraise (LexError { msg; loc = Location.curr lexbuf })
| P.ParseError ->
let[@warning "-8"] (Some token) = !curr_token in
reraise (ParseError { token; loc = Location.curr lexbuf })
let parse_string ?(pos : Lexing.position option) s =
match pos with
| None ->
parse (Lexing.from_string s)
| Some ({pos_fname=file; _} as p) ->
parse ~file Lexing.{(from_string s) with lex_start_p=p; lex_curr_p=p}
let parse_chan ?(pos : Lexing.position option) chan =
match pos with
| None ->
parse (Lexing.from_channel chan)
| Some ({pos_fname=file; _} as p) ->
parse ~file Lexing.{(from_channel chan) with lex_start_p=p; lex_curr_p=p}
let parse_file file =
Stdio.In_channel.with_file file ~f:(fun chan ->
let lexbuf = Lexing.from_channel chan in
Location.init lexbuf file;
parse ~file lexbuf
)
end