Source file parser_error_runtime.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
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
module type ENGINE = sig
type 'a env
type element
val get : int -> 'a env -> element option
val positions : element -> Lexing.position * Lexing.position
end
module Make (E : ENGINE) = struct
type label = {
loc_start : Lexing.position;
loc_end : Lexing.position;
text : string;
}
module R = MenhirLib.ErrorReports
let show source positions =
R.extract source positions |> R.sanitize |> R.compress |> R.shorten 20
let resolve ~source ~env message =
let get_slice i =
match E.get i env with
| Some el -> show source (E.positions el)
| None -> "???"
in
let message = R.expand get_slice message in
let lines = String.split_on_char '\n' message in
let related = ref [] in
let main_message = ref [] in
List.iter
(fun line ->
let len = String.length line in
if len > 2 && line.[0] = '<' then
try
let i = String.index line '>' in
let tag = String.sub line 1 (i - 1) in
let msg = String.trim (String.sub line (i + 1) (len - i - 1)) in
let is_subject = String.length tag > 0 && tag.[0] = '^' in
let depth =
int_of_string
(if is_subject then String.sub tag 1 (String.length tag - 1)
else tag)
in
match E.get (depth - 1) env with
| Some el ->
let pos1, pos2 = E.positions el in
if is_subject then
if
pos1.Lexing.pos_cnum >= pos2.Lexing.pos_cnum
then ()
else
related :=
{ loc_start = pos1; loc_end = pos2; text = msg }
:: !related
else
let cnum = pos1.Lexing.pos_cnum in
let is_delim c = c = '(' || c = '[' || c = '{' in
let blank c = c = ' ' || c = '\t' in
let dcnum =
if cnum < String.length source && is_delim source.[cnum]
then cnum
else
let rec back i =
if i < 0 || not (blank source.[i]) then
if i >= 0 && is_delim source.[i] then i else cnum
else back (i - 1)
in
back (cnum - 1)
in
let width =
match String.index_opt msg '\'' with
| Some i -> (
match String.index_from_opt msg (i + 1) '\'' with
| Some j -> max 1 (j - i - 1)
| None -> 1)
| None -> 1
in
let start = { pos1 with Lexing.pos_cnum = dcnum } in
related :=
{
loc_start = start;
loc_end = { start with Lexing.pos_cnum = dcnum + width };
text = msg;
}
:: !related
| None -> main_message := line :: !main_message
with _ -> main_message := line :: !main_message
else main_message := line :: !main_message)
lines;
let main_message = List.rev !main_message in
let related_labels = List.rev !related in
let main_message =
match List.rev main_message with
| "" :: rest when related_labels <> [] -> List.rev rest
| _ -> main_message
in
(String.concat "\n" main_message, related_labels)
end