-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.ml
56 lines (44 loc) · 1.38 KB
/
parse.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
open Std
type error =
| Lexing of Lexing.lexbuf
| Parsing of Lexing.lexbuf
let positions (lexbuf: Lexing.lexbuf) =
let start = lexbuf.lex_start_p in
let curr = lexbuf.lex_curr_p in
start.pos_lnum,
start.pos_cnum - start.pos_bol,
curr.pos_cnum - curr.pos_bol
let error_to_string error =
let buf = Buffer.create 100 in
let append = Buffer.add_string buf in
let sprintf = Printf.sprintf in
let lexbuf, kind = match error with
| Lexing lexbuf -> lexbuf, "syntax"
| Parsing lexbuf -> lexbuf, "parse"
in
let line, s_col, c_col = positions lexbuf in
let carrots = c_col - s_col in
if carrots = 0 then
append @@ sprintf "%s error: unexpected EOF\n" kind
else begin
append @@ sprintf "%s error:\n\n" kind;
let lines = lexbuf.lex_buffer |> Bytes.to_string |> String.split_lines in
for n = line - 3 to line - 1 do
match List.nth lines n with
| Some line -> append @@ sprintf "%4d: %s\n" (n + 1) line
| None -> ()
done;
append @@ sprintf "%s%s%s\n"
(String.make 6 ' ')
(String.make s_col '~')
(String.make carrots '^')
end;
Buffer.contents buf
let lexbuf lexbuf =
try Ok (Parser.main Lexer.token lexbuf) with
| Lexer.Error _ -> Error (Lexing lexbuf)
| Parser.Error -> Error (Parsing lexbuf)
let stdin () =
Lexing.from_channel Stdio.stdin |> lexbuf
let string string =
Lexing.from_string string |> lexbuf