teleparse/syntax/
error.rs1use itertools::Itertools;
2use teleparse_macros::ToSpan;
3
4use crate::{Lexicon, Span};
5
6use super::FirstSet;
7
8#[derive(Debug, Clone, ToSpan, PartialEq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize))]
11pub struct Error<L: Lexicon> {
12 pub span: Span,
13 pub data: ErrorKind<L>,
14}
15
16impl<L: Lexicon> Error<L> {
17 pub fn new<S: Into<Span>>(span: S, data: ErrorKind<L>) -> Self {
18 Self {
19 span: span.into(),
20 data,
21 }
22 }
23
24 pub fn message(&self, input: &str) -> String {
25 match &self.data {
26 ErrorKind::Custom(msg) => msg.clone(),
27 ErrorKind::UnexpectedCharacters => {
28 format!("Unexpected: {}", self.span.get(input))
29 },
30 ErrorKind::UnexpectedTokens => {
31 format!("Unexpected token(s): {}", self.span.get(input))
32 },
33 ErrorKind::Expecting(set) => {
34 let set = set.as_terminal_set().to_repr().into_iter().join(", ");
35 format!("Expecting one of {set}")
36 },
37 ErrorKind::UnexpectedEof => "Unexpected end of file".to_string(),
38 ErrorKind::UnexpectedNoAdvanceInLoop => "Unexpected: Parser did not advance in a loop. The grammar is probably not LL(1), and this is a bug since the parser should catch that before parsing.".to_string(),
39 }
40 }
41}
42
43#[derive(Debug, Clone, PartialEq)]
44#[cfg_attr(feature = "serde", derive(serde::Serialize))]
45pub enum ErrorKind<L: Lexicon> {
46 Custom(String),
47 UnexpectedCharacters,
48 UnexpectedTokens,
49 Expecting(FirstSet<L>),
50 UnexpectedEof,
51 UnexpectedNoAdvanceInLoop,
52}
53
54pub enum Result<T, L: Lexicon> {
56 Success(T),
58 Recovered(T, Vec<Error<L>>),
61 Panic(Vec<Error<L>>),
64}
65
66impl<T, L: Lexicon> From<(T, Vec<Error<L>>)> for Result<T, L> {
67 #[inline]
68 fn from((value, errors): (T, Vec<Error<L>>)) -> Self {
69 if errors.is_empty() {
70 Result::Success(value)
71 } else {
72 Result::Recovered(value, errors)
73 }
74 }
75}
76
77impl<T, L: Lexicon> Result<T, L> {
78 #[inline]
79 pub fn map<T2, F: FnOnce(T) -> T2>(self, f: F) -> Result<T2, L> {
80 match self {
81 Self::Success(obj) => Result::Success(f(obj)),
82 Self::Recovered(obj, errors) => Result::Recovered(f(obj), errors),
83 Self::Panic(errors) => Result::Panic(errors),
84 }
85 }
86}
87
88#[macro_export]
89#[doc(hidden)]
90macro_rules! handle_result {
91 ($errors:ident, $parse:expr) => {{
92 let result = $parse;
93 match result {
94 $crate::syntax::Result::Success(x) => x,
95 $crate::syntax::Result::Recovered(x, e) => {
96 $errors.extend(e);
97 x
98 }
99 $crate::syntax::Result::Panic(e) => {
100 $errors.extend(e);
101 return $crate::syntax::Result::Panic($errors);
102 }
103 }
104 }};
105}