Skip to main content

parol_runtime/errors/
types.rs

1use crate::lexer::token_stream::TokenStream;
2use crate::lexer::{Location, Token};
3use std::fmt::{Display, Formatter};
4use std::path::PathBuf;
5use std::sync::Arc;
6use thiserror::Error;
7
8pub type Result<T> = std::result::Result<T, ParolError>;
9
10#[derive(Error, Debug)]
11pub enum ParserError {
12    #[error(transparent)]
13    TreeError { source: syntree::Error },
14
15    #[error("Error in generated source: {0}")]
16    DataError(&'static str),
17
18    #[error("Error in input: {cause}")]
19    PredictionError { cause: String },
20
21    #[error("Syntax error(s)")]
22    SyntaxErrors { entries: Vec<SyntaxError> },
23
24    #[error("Unprocessed input is left after parsing has finished")]
25    UnprocessedInput {
26        input: Box<FileSource>,
27        last_token: Box<Location>,
28    },
29
30    #[error("Unsupported language feature: {context}")]
31    Unsupported {
32        context: String,
33        error_location: Box<Location>,
34    },
35
36    #[error("Too many errors: {count}")]
37    TooManyErrors { count: usize },
38
39    #[error("Error recovery failed")]
40    RecoveryFailed,
41
42    #[error("{0}")]
43    InternalError(String),
44}
45
46#[derive(Error, Debug)]
47pub enum LexerError {
48    #[error("No valid token read")]
49    TokenBufferEmptyError,
50
51    #[error("{0}")]
52    InternalError(String),
53
54    #[error("Lookahead exceeds its maximum")]
55    LookaheadExceedsMaximum,
56
57    #[error("Lookahead exceeds token buffer length")]
58    LookaheadExceedsTokenBufferLength,
59
60    #[error("pop_scanner: Tried to pop from an empty scanner stack!")]
61    ScannerStackEmptyError,
62
63    #[error("{0}")]
64    RecoveryError(String),
65}
66
67#[derive(Error, Debug)]
68pub enum ParolError {
69    #[error(transparent)]
70    ParserError(#[from] ParserError),
71    #[error(transparent)]
72    LexerError(#[from] LexerError),
73    #[error(transparent)]
74    UserError(#[from] anyhow::Error),
75}
76
77impl AsRef<ParolError> for ParolError {
78    fn as_ref(&self) -> &ParolError {
79        self
80    }
81}
82
83#[derive(Error, Debug, Default)]
84#[error("{cause}")]
85pub struct SyntaxError {
86    pub cause: String,
87    pub input: Option<Box<FileSource>>,
88    pub error_location: Box<Location>,
89    pub unexpected_tokens: Vec<UnexpectedToken>,
90    pub expected_tokens: TokenVec,
91    pub source: Option<Box<ParolError>>,
92}
93
94impl SyntaxError {
95    pub fn with_cause(mut self, cause: &str) -> Self {
96        cause.clone_into(&mut self.cause);
97        self
98    }
99
100    pub fn with_location(mut self, location: Location) -> Self {
101        self.error_location = Box::new(location);
102        self
103    }
104
105    pub(crate) fn with_source(mut self, e: Box<ParolError>) -> SyntaxError {
106        self.source = Some(e);
107        self
108    }
109}
110
111#[derive(Debug)]
112pub struct UnexpectedToken {
113    pub name: String,
114    pub token_type: String,
115    pub token: Location,
116}
117
118impl UnexpectedToken {
119    pub fn new(name: String, token_type: String, token: &Token<'_>) -> Self {
120        let token = token.into();
121        Self {
122            name,
123            token_type,
124            token,
125        }
126    }
127}
128
129impl Display for UnexpectedToken {
130    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
131        write!(f, "{} {}: {}", self.name, self.token_type, self.token)
132    }
133}
134
135/// A vector of tokens in a string representation
136#[derive(Debug, Default)]
137pub struct TokenVec(Vec<String>);
138
139impl TokenVec {
140    /// Creates a new token vector
141    pub fn new() -> Self {
142        Self(Vec::new())
143    }
144
145    /// Pushes a token to the vector
146    pub fn push(&mut self, token: String) {
147        self.0.push(token);
148    }
149
150    /// Returns an iterator over the tokens
151    pub fn iter(&self) -> std::slice::Iter<'_, String> {
152        self.0.iter()
153    }
154
155    /// Returns a token at the given index
156    pub fn get(&self, index: usize) -> Option<&String> {
157        self.0.get(index)
158    }
159
160    /// Returns true if the vector is empty
161    pub fn is_empty(&self) -> bool {
162        self.0.is_empty()
163    }
164}
165
166impl Display for TokenVec {
167    fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
168        write!(
169            f,
170            "{}",
171            self.0.iter().fold(String::new(), |mut acc, e| {
172                if !acc.is_empty() {
173                    acc.push_str(", ");
174                }
175                acc.push_str(e.to_string().as_str());
176                acc
177            })
178        )
179    }
180}
181
182#[derive(Debug)]
183pub struct FileSource {
184    pub file_name: Arc<PathBuf>,
185    pub input: String,
186}
187
188impl FileSource {
189    pub fn try_new(file_name: Arc<PathBuf>) -> std::result::Result<Self, std::io::Error> {
190        let file_name = file_name.clone();
191        let input = std::fs::read_to_string(&*file_name)?;
192        Ok(Self { file_name, input })
193    }
194
195    pub fn from_stream<F: Fn(char) -> Option<usize> + Clone>(
196        token_stream: &TokenStream<'_, F>,
197    ) -> Self {
198        let file_name = token_stream.file_name.clone();
199        let input = token_stream.input.to_string();
200        Self { file_name, input }
201    }
202}