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
use range::Range;
use std::io::{ self, stderr, Write };
use ParseError;
pub fn stderr_unwrap<T>(source: &str, res: Result<T, (Range, ParseError)>) -> T {
match res {
Err((range, err)) => {
ParseErrorHandler::new(source).error(range, err);
panic!();
}
Ok(val) => val,
}
}
pub struct ParseErrorHandler<'a> {
lines: Vec<(Range, &'a str)>,
}
impl<'a> ParseErrorHandler<'a> {
pub fn new(text: &'a str) -> ParseErrorHandler<'a> {
let mut start = 0;
let mut lines = vec![];
for line in text.split('\n') {
let length = line.chars().count();
lines.push((Range::new(start, length), line));
start += length + 1;
}
ParseErrorHandler {
lines: lines,
}
}
pub fn write<W: Write>(
&mut self,
w: &mut W,
range: Range,
error: ParseError
) -> Result<(), io::Error> {
fn first_line(
err_handler: &ParseErrorHandler,
range: Range
) -> Option<(usize, Range)> {
let mut first_line = None;
for (i, &(r, _)) in err_handler.lines.iter().enumerate() {
if let Some(intersect) = range.ends_intersect(&r) {
first_line = Some((i, intersect));
break;
}
}
first_line
}
try!(writeln!(w, "Error {}", error));
if let &ParseError::ExpectedToken(_, _) = &error {
if let Some(first_line) = first_line(self, range) {
let mut prev_line = 0;
for (i, &(_, text)) in
self.lines[..first_line.0].iter().enumerate().rev() {
prev_line = i;
if !text.chars()
.all(|c| { c.is_whitespace() }) { break; }
}
for (i, &(_, text)) in
self.lines[prev_line .. first_line.0].iter().enumerate() {
try!(writeln!(w, "{}: {}",
i + prev_line + 1, text));
}
}
}
for (i, &(r, text)) in self.lines.iter().enumerate() {
if let Some(intersect) = range.ends_intersect(&r) {
if intersect.offset >= r.offset {
let j = intersect.offset - r.offset;
let s = if j > 75 { j - 50 } else { 0 };
let e = ::std::cmp::min(s + 100, r.length);
try!(write!(w, "{},{}: ", i + 1, j + 1));
for c in text.chars().skip(s).take(e - s) {
try!(write!(w, "{}", c));
}
try!(writeln!(w, ""));
try!(write!(w, "{},{}: ", i + 1, j + 1));
for c in text.chars().skip(s).take(j - s) {
match c {
'\t' => {
try!(write!(w, "\t"));
}
_ => {
try!(write!(w, " "));
}
}
}
try!(writeln!(w, "^"));
}
}
}
Ok(())
}
pub fn error(&mut self, range: Range, error: ParseError) {
self.write(&mut stderr(), range, error).unwrap()
}
}