1use crate::emit::Token;
2
3use super::token::*;
4use std::{fmt::Debug, iter::Peekable};
5
6#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
7pub struct Span(pub usize, pub usize);
13
14impl Span {
15 pub fn len(&self) -> usize {
16 self.1.saturating_sub(self.0)
17 }
18
19 pub fn is_empty(&self) -> bool {
20 self.1 <= self.0
21 }
22}
23
24pub trait Spanned {
25 fn span(&self) -> Span;
26}
27
28impl std::ops::Add for Span {
29 type Output = Self;
30 fn add(self, rhs: Self) -> Self {
31 Self(self.0.min(rhs.0), self.1.max(rhs.1))
32 }
33}
34impl std::ops::AddAssign for Span {
35 fn add_assign(&mut self, rhs: Self) {
36 *self = Self(self.0.min(rhs.0), self.1.max(rhs.1))
37 }
38}
39
40impl From<Span> for std::ops::Range<usize> {
41 fn from(span: Span) -> Self {
42 span.0..span.1
43 }
44}
45
46impl<T: Spanned> Spanned for &T {
47 fn span(&self) -> Span {
48 <T as Spanned>::span(*self)
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct File<'input> {
56 pub(crate) percents: Vec<Percent>,
57 pub(crate) lines: Vec<(Line<'input>, Newline)>,
58 pub(crate) last_line: Option<Line<'input>>,
59 pub(crate) span: Span,
60}
61
62impl<'input> File<'input> {
63 pub fn iter(&self) -> impl Iterator<Item = &Line<'input>> {
66 self.lines
67 .iter()
68 .map(|(line, _)| line)
69 .chain(self.last_line.iter())
70 }
71
72 pub fn iter_fields(&self) -> impl Iterator<Item = &Field<'input>> {
74 self.iter().flat_map(Line::iter_fields)
75 }
76
77 pub fn iter_flags(&self) -> impl Iterator<Item = &Flag<'input>> {
79 self.iter().flat_map(Line::iter_flags)
80 }
81
82 pub fn iter_inline_comments(&self) -> impl Iterator<Item = &InlineComment<'input>> {
84 self.iter().flat_map(Line::iter_inline_comments)
85 }
86
87 pub fn iter_whitespace(&self) -> impl Iterator<Item = &Whitespace<'input>> {
89 self.iter().flat_map(Line::iter_whitespace)
90 }
91
92 pub fn iter_comments(&self) -> impl Iterator<Item = &Comment<'input>> {
94 self.iter().filter_map(|l| l.comment.as_ref())
95 }
96
97 pub fn iter_checksums(&self) -> impl Iterator<Item = &Checksum> {
99 self.iter().filter_map(|l| l.checksum.as_ref())
100 }
101
102 pub fn iter_bytes(&self) -> impl Iterator<Item = &u8> {
104 self.iter().flat_map(|line| line.iter_bytes())
105 }
106
107 pub fn iter_emit_tokens<'a>(&'a self) -> impl Iterator<Item = Token<'input>> + 'a {
109 TokenizingIterator {
110 field_iterator: self.iter_fields().peekable(),
111 flag_iterator: self.iter_flags().peekable(),
112 inline_comment_iterator: self.iter_inline_comments().peekable(),
113 comment_iterator: self.iter_comments().peekable(),
114 }
115 }
116}
117
118impl<'input> Spanned for File<'input> {
119 fn span(&self) -> Span {
120 self.span
121 }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub struct Snippet<'input> {
130 pub(crate) lines: Vec<(Line<'input>, Newline)>,
131 pub(crate) last_line: Option<Line<'input>>,
132 pub(crate) span: Span,
133}
134
135impl<'input> Snippet<'input> {
136 pub fn iter(&self) -> impl Iterator<Item = &Line<'input>> {
139 self.lines
140 .iter()
141 .map(|(line, _)| line)
142 .chain(self.last_line.iter())
143 }
144
145 pub fn iter_fields(&self) -> impl Iterator<Item = &Field<'input>> {
147 self.iter().flat_map(Line::iter_fields)
148 }
149
150 pub fn iter_flags(&self) -> impl Iterator<Item = &Flag<'input>> {
152 self.iter().flat_map(Line::iter_flags)
153 }
154
155 pub fn iter_inline_comments(&self) -> impl Iterator<Item = &InlineComment<'input>> {
157 self.iter().flat_map(Line::iter_inline_comments)
158 }
159
160 pub fn iter_whitespace(&self) -> impl Iterator<Item = &Whitespace<'input>> {
162 self.iter().flat_map(Line::iter_whitespace)
163 }
164
165 pub fn iter_bytes(&self) -> impl Iterator<Item = &u8> {
167 self.iter().flat_map(|line| line.iter_bytes())
168 }
169
170 pub fn iter_comments(&self) -> impl Iterator<Item = &Comment<'input>> {
172 self.iter().filter_map(|l| l.comment.as_ref())
173 }
174
175 pub fn iter_checksums(&self) -> impl Iterator<Item = &Checksum> {
177 self.iter().filter_map(|l| l.checksum.as_ref())
178 }
179
180 pub fn iter_emit_tokens<'a>(&'a self) -> impl Iterator<Item = Token<'input>> + 'a {
182 TokenizingIterator {
183 field_iterator: self.iter_fields().peekable(),
184 flag_iterator: self.iter_flags().peekable(),
185 inline_comment_iterator: self.iter_inline_comments().peekable(),
186 comment_iterator: self.iter_comments().peekable(),
187 }
188 }
189}
190
191impl<'input> Spanned for Snippet<'input> {
192 fn span(&self) -> Span {
193 self.span
194 }
195}
196#[derive(Debug, Clone, PartialEq, Eq)]
197pub struct Line<'input> {
199 pub(crate) line_components: Vec<LineComponent<'input>>,
200 pub(crate) checksum: Option<Checksum>,
201 pub(crate) comment: Option<Comment<'input>>,
202 pub(crate) span: Span,
203}
204
205impl<'input> Spanned for Line<'input> {
206 fn span(&self) -> Span {
207 self.span
208 }
209}
210
211impl<'input> Line<'input> {
212 pub fn iter_fields(&self) -> impl Iterator<Item = &Field<'input>> {
214 self.line_components.iter().filter_map(|c| c.field.as_ref())
215 }
216
217 pub fn iter_flags(&self) -> impl Iterator<Item = &Flag<'input>> {
219 self.line_components.iter().filter_map(|c| c.flag.as_ref())
220 }
221
222 pub fn iter_inline_comments(&self) -> impl Iterator<Item = &InlineComment<'input>> {
224 self.line_components
225 .iter()
226 .filter_map(|c| c.inline_comment.as_ref())
227 }
228
229 pub fn iter_whitespace(&self) -> impl Iterator<Item = &Whitespace<'input>> {
231 self.line_components
232 .iter()
233 .filter_map(|c| c.whitespace.as_ref())
234 }
235
236 pub fn iter_emit_tokens<'a>(&'a self) -> impl Iterator<Item = Token<'input>> + 'a {
238 TokenizingIterator {
239 field_iterator: self.iter_fields().peekable(),
240 flag_iterator: self.iter_flags().peekable(),
241 inline_comment_iterator: self.iter_inline_comments().peekable(),
242 comment_iterator: self.comment.iter().peekable(),
243 }
244 }
245
246 pub fn validate_checksum(&self) -> Option<Result<(), u8>> {
253 if let Some(Checksum {
254 inner: checksum, ..
255 }) = self.checksum.as_ref()
256 {
257 let computed_checksum = self.compute_checksum();
258 if computed_checksum != *checksum {
259 return Some(Err(computed_checksum));
260 } else {
261 return Some(Ok(()));
262 }
263 }
264 None
265 }
266
267 pub fn iter_bytes(&self) -> impl Iterator<Item = &u8> {
269 self.line_components.iter().flat_map(|c| c.iter_bytes())
270 }
271
272 pub fn compute_checksum(&self) -> u8 {
274 let take = if let Some(checksum) = &self.checksum {
275 checksum.span.0
276 } else if let Some(comment) = &self.comment {
277 comment.pos
278 } else {
279 self.span.1
280 } - self.span.0;
281 self.iter_bytes().take(take).fold(0u8, |acc, b| acc ^ b)
282 }
283}
284
285struct TokenizingIterator<'a, 'input: 'a, F, FL, IC, C>
286where
287 F: Iterator<Item = &'a Field<'input>>,
288 FL: Iterator<Item = &'a Flag<'input>>,
289 IC: Iterator<Item = &'a InlineComment<'input>>,
290 C: Iterator<Item = &'a Comment<'input>>,
291{
292 field_iterator: Peekable<F>,
293 flag_iterator: Peekable<FL>,
294 inline_comment_iterator: Peekable<IC>,
295 comment_iterator: Peekable<C>,
296}
297
298impl<'a, 'input: 'a, F, FL, IC, C> Iterator for TokenizingIterator<'a, 'input, F, FL, IC, C>
299where
300 F: Iterator<Item = &'a Field<'input>>,
301 FL: Iterator<Item = &'a Flag<'input>>,
302 IC: Iterator<Item = &'a InlineComment<'input>>,
303 C: Iterator<Item = &'a Comment<'input>>,
304{
305 type Item = Token<'input>;
306
307 fn next(&mut self) -> Option<Self::Item> {
308 let spans = [
309 self.field_iterator.peek().map(Spanned::span),
310 self.flag_iterator.peek().map(Spanned::span),
311 self.inline_comment_iterator.peek().map(Spanned::span),
312 self.comment_iterator.peek().map(Spanned::span),
313 ];
314 if let Some((i, _)) = spans
315 .iter()
316 .enumerate()
317 .filter(|(_, span)| span.is_some())
318 .min_by_key(|(_, span)| span.unwrap().0)
319 {
320 match i {
321 0 => Some(Token::from(self.field_iterator.next().unwrap())),
322 1 => Some(Token::from(self.flag_iterator.next().unwrap())),
323 2 => Some(Token::from(self.inline_comment_iterator.next().unwrap())),
324 3 => Some(Token::from(self.comment_iterator.next().unwrap())),
325 _ => unreachable!(),
326 }
327 } else {
328 None
329 }
330 }
331}