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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
use std::{
    fmt,
    cmp::Ord,
    ops::Range,
};

/// A trait representing a span over elements of a token stream
pub trait Span {
    /// A position that can be used to demarcate the bounds of this span.
    type Position: Ord;

    /// Get the start position of this span.
    fn start(&self) -> Self::Position;
    /// Get the (exclusive) end position of this span.
    fn end(&self) -> Self::Position;
    /// Find the span that is the closest fit around two spans as possible.
    ///
    /// # Panics
    ///
    /// This function is permitted to panic if the first comes after the last.
    fn union(self, other: Self) -> Self;
    /// Find the span that fits between two spans but does not intersect with either.
    ///
    /// # Panics
    ///
    /// This function is permitted to panic if the spans intersect or the first comes after the last.
    fn inner(self, other: Self) -> Self;

    /// Return a value that allows displaying this span.
    ///
    /// Note that this function exists to work around certain implementation details and is highly likely to be removed
    /// in the future. If possible, implement [`std::fmt::Display`] for your span type too.
    fn display(&self) -> Box<dyn fmt::Display + '_>;
}

impl<T: Ord + Clone + fmt::Display> Span for Range<T> {
    type Position = T;

    fn start(&self) -> Self::Position { self.start.clone() }
    fn end(&self) -> Self::Position { self.end.clone() }
    fn union(self, other: Self) -> Self {
        self.start.min(other.start)..self.end.max(other.end)
    }
    fn inner(self, other: Self) -> Self {
        if self.end <= other.start {
            self.end.clone()..other.start.clone()
        } else {
            panic!("Spans intersect of are incorrectly ordered");
        }
    }
    fn display(&self) -> Box<dyn fmt::Display + '_> { Box::new(format!("{}..{}", self.start, self.end)) }
}

/// A trait that describes parser error types.
pub trait Error<I>: Sized {
    /// The type of spans to be used in the error.
    type Span: Span; // TODO: Default to = Range<usize>;

    /// The label used to describe tokens or a token pattern in error messages.
    ///
    /// Commonly, this type has a way to represent both *specific* tokens and groups of tokens like 'expressions' or
    /// 'statements'.
    type Pattern; // TODO: Default to = I;

    /// The primary span that the error originated at, if one exists.
    fn span(&self) -> Option<Self::Span>;

    /// Create a new error describing a conflict between expected tokens and that which was actually found.
    ///
    /// Using a `None` as `found` indicates that the end of input was reached, but was not expected.
    fn expected_token_found(span: Option<Self::Span>, expected: Vec<I>, found: Option<I>) -> Self;

    /// Create a new error describing a conflict between an expected label and that the token that was actually found.
    ///
    /// Using a `None` as `found` indicates that the end of input was reached, but was not expected.
    fn expected_label_found<L: Into<Self::Pattern>>(span: Option<Self::Span>, expected: L, found: Option<I>) -> Self {
        Self::expected_token_found(span, Vec::new(), found).into_labelled(expected)
    }

    /// Alter the error message to indicate that the given labelled pattern was expected.
    fn into_labelled<L: Into<Self::Pattern>>(self, label: L) -> Self;

    /// Merge two errors together, combining their elements.
    ///
    /// Note that when the errors originate from two different locations in the token stream (i.e: their span
    /// [`Span::end`] differs), the error error with the latest position should be preferred. When merging errors,
    /// unresolvable differences should favour `self`.
    fn merge(self, other: Self) -> Self {
        if let Some((a, b)) = self.span().zip(other.span()) {
            if a.end() < b.end() {
                other
            } else {
                self
            }
        } else {
            self
        }
    }
}

/// A simple default token pattern that allows describing tokens and token patterns in error messages.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SimplePattern<I> {
    /// A pattern with the given name was expected.
    Labelled(&'static str),
    /// A specific token was expected.
    Token(I),
}

impl<I> From<&'static str> for SimplePattern<I> {
    fn from(s: &'static str) -> Self { Self::Labelled(s) }
}

impl<I: fmt::Display> fmt::Display for SimplePattern<I> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::Labelled(s) => write!(f, "{}", s),
            Self::Token(x) => write!(f, "'{}'", x),
        }
    }
}

/// A simple default error type that provides minimal functionality.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Simple<I, S = Range<usize>> {
    span: Option<S>,
    expected: Vec<SimplePattern<I>>,
    found: Option<I>,
}

impl<I, S> Simple<I, S> {
    /// Returns an iterator over possible expected patterns.
    pub fn expected(&self) -> impl ExactSizeIterator<Item = &SimplePattern<I>> + '_ { self.expected.iter() }

    /// Returns the token, if any, that was found instead of an expected pattern.
    pub fn found(&self) -> Option<&I> { self.found.as_ref() }
}

impl<I, S: Span + Clone + From<Range<usize>>> Error<I> for Simple<I, S> {
    type Span = S;
    type Pattern = SimplePattern<I>;

    fn span(&self) -> Option<Self::Span> { self.span.clone() }

    fn expected_token_found(span: Option<Self::Span>, expected: Vec<I>, found: Option<I>) -> Self {
        Self {
            span,
            expected: expected
                .into_iter()
                .map(SimplePattern::Token)
                .collect(),
            found,
        }
    }

    fn into_labelled<L: Into<Self::Pattern>>(mut self, label: L) -> Self {
        self.expected = vec![label.into()];
        self
    }

    fn merge(mut self, mut other: Self) -> Self {
        if let Some((a, b)) = self.span().zip(other.span()) {
            if a.end() < b.end() {
                other
            } else if a.end() > b.end() {
                self
            } else {
                self.expected.append(&mut other.expected);
                self
            }
        } else {
            self
        }
    }
}

impl<I: fmt::Display, S: Span> fmt::Display for Simple<I, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(found) = &self.found {
            write!(f, "found '{}' ", found)?;
        } else {
            write!(f, "the input ended ")?;
        }

        if let Some(span) = &self.span {
            write!(f, "at {} ", span.display())?;
        }

        match self.expected.as_slice() {
            [] => write!(f, "but end of input was expected")?,
            [expected] => write!(f, "but {} was expected", expected)?,
            [_, ..] => write!(f, "but one of {} was expected", self.expected
                .iter()
                .map(|expected| expected.to_string())
                .collect::<Vec<_>>()
                .join(", "))?,
        }

        Ok(())
    }
}
impl<I: fmt::Debug + fmt::Display, S: Span + fmt::Debug> std::error::Error for Simple<I, S> {}