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
use crate::errors::parser_error::ParserError;
pub struct ParseSpan<'a, 's, 'f> {
filename: &'f str,
global_span: (usize, usize),
source_span: &'a [&'s str],
}
pub struct LineSpan<'s, 'f> {
filename: &'f str,
line: &'s str,
global_at: usize,
}
impl<'s, 'f> LineSpan<'s, 'f> {
pub fn get_line(&self) -> &'s str {
self.line
}
pub fn get_filename(&self) -> &'f str {
self.filename
}
pub fn get_global_at(&self) -> usize {
self.global_at
}
}
impl<'a, 's, 'f> ParseSpan<'a, 's, 'f> {
pub fn from_source(source_span: &'a [&'s str], filename: &'f str) -> Self {
Self {
filename,
source_span,
global_span: (0, source_span.len() - 1),
}
}
pub fn non_empty_or(&self) -> Result<(), ParserError> {
if self.source_span.len() == 0 {
Err(ParserError::Internal(
"Expected a non empty span.".to_string(),
))
} else {
Ok(())
}
}
pub fn len(&self) -> usize {
self.source_span.len()
}
pub fn get_with_start_at(&self, at: usize) -> Self {
Self {
filename: self.filename,
source_span: &self.source_span[at..],
global_span: (self.global_span.0 + at, self.global_span.1),
}
}
pub fn get_with_end_at(&self, at: usize) -> Self {
Self {
filename: self.filename,
source_span: &self.source_span[..=at],
global_span: (self.global_span.0, self.global_span.0 + at),
}
}
pub fn get_with_bounds(&self, from: usize, to: usize) -> Self {
Self {
filename: self.filename,
source_span: &self.source_span[from..=to],
global_span: (self.global_span.0 + from, self.global_span.0 + to),
}
}
pub fn get_source_span(&self) -> &'a [&'s str] {
self.source_span
}
pub fn get_filename(&self) -> &'f str {
self.filename
}
pub fn get_global_span(&self) -> (usize, usize) {
self.global_span
}
pub fn get_line_span_at(&self, offset: usize) -> LineSpan<'s, 'f> {
LineSpan {
filename: self.filename,
line: self.source_span[offset],
global_at: self.global_span.0 + offset,
}
}
}
#[cfg(test)]
mod test {
use crate::parser::utils::parse_span::ParseSpan;
#[test]
fn happy_path_offseting_works() {
let source_code = "hello\n\
world\n\
you\n\
people";
let lines = source_code.lines().collect::<Vec<&str>>();
let full_span = ParseSpan::from_source(&lines[..], "test.kconfig");
assert_eq!(full_span.get_global_span(), (0, 3));
assert_eq!(full_span.get_filename(), "test.kconfig");
let hello_world = full_span.get_with_end_at(1);
assert_eq!(hello_world.get_global_span(), (0, 1));
assert_eq!(hello_world.get_source_span()[1], "world");
assert_eq!(hello_world.get_source_span()[0], "hello");
let you = full_span.get_with_bounds(2, 2);
assert_eq!(you.get_global_span(), (2, 2));
assert_eq!(you.get_source_span()[0], "you");
}
}