parol_runtime/errors/
types.rs1use 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#[derive(Debug, Default)]
137pub struct TokenVec(Vec<String>);
138
139impl TokenVec {
140 pub fn new() -> Self {
142 Self(Vec::new())
143 }
144
145 pub fn push(&mut self, token: String) {
147 self.0.push(token);
148 }
149
150 pub fn iter(&self) -> std::slice::Iter<'_, String> {
152 self.0.iter()
153 }
154
155 pub fn get(&self, index: usize) -> Option<&String> {
157 self.0.get(index)
158 }
159
160 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}