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}