-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathspans.rs
134 lines (114 loc) · 3.52 KB
/
spans.rs
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
use std::collections::{HashMap, HashSet};
use std::error;
use std::fmt;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Span(usize);
pub type Spanned<T> = (T, Span);
#[derive(Debug, Default)]
pub struct SpanManager {
sources: Vec<String>,
spans: Vec<(usize, usize, usize)>,
}
impl SpanManager {
pub fn add_source(&mut self, source: String) -> SpanMaker {
let i = self.sources.len();
self.sources.push(source);
SpanMaker {
parent: self,
source_ind: i,
pool: Default::default(),
}
}
pub fn print(&self, span: Span) -> String {
let (source_ind, l, r) = self.spans[span.0];
let source = &self.sources[source_ind];
let mut out = String::new();
assert!(l <= r);
let (before, source) = source.split_at(l);
// The matched span may contain newlines, so cut it off at the first newline if applicable
let tok = source.split_at(r - l).0.split('\n').next().unwrap();
let after = source.split_at(tok.len()).1;
// let (source, after) = source.split_at(r);
let mut b_iter = before.rsplit('\n');
let line_before = b_iter.next().unwrap();
let mut a_iter = after.split('\n');
let line_after = a_iter.next().unwrap();
// Lines before the span
if let Some(line) = b_iter.next() {
if let Some(line) = b_iter.next() {
out += line;
out += "\n";
}
out += line;
out += "\n";
}
// Line of the span
out += line_before;
out += tok;
out += line_after;
out += "\n";
// highlight line
out += &" ".repeat(line_before.len());
out += "^";
out += &"~".repeat(std::cmp::max(1, tok.len()) - 1);
out += &" ".repeat(line_after.len());
out += "\n";
// Lines after the span
for _ in 0..2 {
if let Some(line) = a_iter.next() {
out += line;
out += "\n";
}
}
out
}
fn new_span(&mut self, source_ind: usize, l: usize, r: usize) -> Span {
let i = self.spans.len();
self.spans.push((source_ind, l, r));
Span(i)
}
}
#[derive(Debug)]
pub struct SpanMaker<'a> {
parent: &'a mut SpanManager,
source_ind: usize,
pool: HashMap<(usize, usize), Span>,
}
impl<'a> SpanMaker<'a> {
pub fn span(&mut self, l: usize, r: usize) -> Span {
// Make the borrow checker happy
let source_ind = self.source_ind;
let parent = &mut self.parent;
*self.pool.entry((l, r)).or_insert_with(|| parent.new_span(source_ind, l, r))
}
}
#[derive(Debug)]
pub struct SpannedError {
pairs: Vec<(String, Span)>,
}
impl SpannedError {
pub fn new1(s1: impl Into<String>, s2: Span) -> Self {
let p1 = (s1.into(), s2);
SpannedError { pairs: vec![p1] }
}
pub fn new2(s1: impl Into<String>, s2: Span, s3: impl Into<String>, s4: Span) -> Self {
let p1 = (s1.into(), s2);
let p2 = (s3.into(), s4);
SpannedError { pairs: vec![p1, p2] }
}
pub fn print(&self, sm: &SpanManager) -> String {
let mut out = String::new();
for (msg, span) in self.pairs.iter() {
out += &msg;
out += "\n";
out += &sm.print(*span);
}
out
}
}
impl fmt::Display for SpannedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl error::Error for SpannedError {}