aldrin_parser/
span.rs

1use crate::grammar::Rule;
2use pest::iterators::Pair;
3use std::iter::Skip;
4use std::str::Lines;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct LineCol {
8    pub line: usize,
9    pub column: usize,
10}
11
12impl LineCol {
13    fn from_pest(pos: &pest::Position) -> Self {
14        let (line, column) = pos.line_col();
15        Self { line, column }
16    }
17}
18
19#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct Position {
21    pub index: usize,
22    pub line_col: LineCol,
23}
24
25impl Position {
26    pub(crate) fn from_pest(pos: &pest::Position) -> Self {
27        Self {
28            index: pos.pos(),
29            line_col: LineCol::from_pest(pos),
30        }
31    }
32
33    pub(crate) fn from_pest_error<R>(err: &pest::error::Error<R>) -> Self {
34        use pest::error::{InputLocation, LineColLocation};
35
36        let index = match err.location {
37            InputLocation::Pos(index) => index,
38            InputLocation::Span((from, _)) => from,
39        };
40
41        let line_col = match err.line_col {
42            LineColLocation::Pos((line, column)) => LineCol { line, column },
43            LineColLocation::Span((line, column), _) => LineCol { line, column },
44        };
45
46        Self { index, line_col }
47    }
48}
49
50#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub struct Span {
52    pub from: Position,
53    pub to: Position,
54}
55
56impl Span {
57    pub(crate) fn from_pair(pair: &Pair<Rule>) -> Self {
58        let span = pair.as_span();
59        Self {
60            from: Position::from_pest(&span.start_pos()),
61            to: Position::from_pest(&span.end_pos()),
62        }
63    }
64
65    pub fn lines(self, text: &str) -> SpanLines {
66        SpanLines {
67            span: self,
68            lines: text.lines().skip(self.from.line_col.line - 1),
69        }
70    }
71}
72
73#[derive(Debug)]
74pub struct SpanLines<'a> {
75    span: Span,
76    lines: Skip<Lines<'a>>,
77}
78
79impl<'a> Iterator for SpanLines<'a> {
80    type Item = (&'a str, Span);
81
82    fn next(&mut self) -> Option<Self::Item> {
83        if self.span.from == self.span.to {
84            None
85        } else if self.span.from.line_col.line < self.span.to.line_col.line {
86            let line = self.lines.next()?;
87
88            let span = Span {
89                from: self.span.from,
90                to: Position {
91                    index: self.span.from.index + line.len(),
92                    line_col: LineCol {
93                        line: self.span.from.line_col.line,
94                        column: line.len() + 1,
95                    },
96                },
97            };
98
99            self.span.from.index = 0;
100            self.span.from.line_col.line += 1;
101            self.span.from.line_col.column = 1;
102
103            Some((line, span))
104        } else {
105            let line = self.lines.next()?;
106            let span = self.span;
107            self.span.from = self.span.to;
108            Some((line, span))
109        }
110    }
111}