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
use crate::grammar::Rule;
use pest::iterators::Pair;
use std::iter::Skip;
use std::str::Lines;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LineCol {
    pub line: usize,
    pub column: usize,
}

impl LineCol {
    fn from_pest(pos: &pest::Position) -> Self {
        let (line, column) = pos.line_col();
        LineCol { line, column }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Position {
    pub index: usize,
    pub line_col: LineCol,
}

impl Position {
    pub(crate) fn from_pest(pos: &pest::Position) -> Self {
        Position {
            index: pos.pos(),
            line_col: LineCol::from_pest(pos),
        }
    }

    pub(crate) fn from_pest_error<R>(err: &pest::error::Error<R>) -> Self {
        use pest::error::{InputLocation, LineColLocation};

        let index = match err.location {
            InputLocation::Pos(index) => index,
            InputLocation::Span((from, _)) => from,
        };

        let line_col = match err.line_col {
            LineColLocation::Pos((line, column)) => LineCol { line, column },
            LineColLocation::Span((line, column), _) => LineCol { line, column },
        };

        Position { index, line_col }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Span {
    pub from: Position,
    pub to: Position,
}

impl Span {
    pub(crate) fn from_pair(pair: &Pair<Rule>) -> Self {
        let span = pair.as_span();
        Span {
            from: Position::from_pest(&span.start_pos()),
            to: Position::from_pest(&span.end_pos()),
        }
    }

    pub fn lines(self, text: &str) -> SpanLines {
        SpanLines {
            span: self,
            lines: text.lines().skip(self.from.line_col.line - 1),
        }
    }
}

#[derive(Debug)]
pub struct SpanLines<'a> {
    span: Span,
    lines: Skip<Lines<'a>>,
}

impl<'a> Iterator for SpanLines<'a> {
    type Item = (&'a str, Span);

    fn next(&mut self) -> Option<Self::Item> {
        if self.span.from == self.span.to {
            None
        } else if self.span.from.line_col.line < self.span.to.line_col.line {
            let line = self.lines.next()?;

            let span = Span {
                from: self.span.from,
                to: Position {
                    index: self.span.from.index + line.len(),
                    line_col: LineCol {
                        line: self.span.from.line_col.line,
                        column: line.len() + 1,
                    },
                },
            };

            self.span.from.index = 0;
            self.span.from.line_col.line += 1;
            self.span.from.line_col.column = 1;

            Some((line, span))
        } else {
            let line = self.lines.next()?;
            let span = self.span;
            self.span.from = self.span.to;
            Some((line, span))
        }
    }
}