1use miette::{self, Diagnostic, NamedSource, SourceSpan};
2use parol_runtime::{ParolError, TokenVec};
3use thiserror::Error;
4
5#[derive(Error, Diagnostic, Debug)]
6pub enum ParserError {
7 #[error(transparent)]
8 #[diagnostic(transparent)]
9 SyntaxError(Box<SyntaxError>),
10
11 #[error(transparent)]
12 ParserError(#[from] parol_runtime::ParserError),
13
14 #[error(transparent)]
15 LexerError(#[from] parol_runtime::LexerError),
16
17 #[error(transparent)]
18 UserError(#[from] anyhow::Error),
19}
20
21#[derive(Error, Diagnostic, Debug)]
22#[diagnostic(help(""), code(ParserError::SyntaxError))]
23pub struct SyntaxError {
24 pub cause: String,
25 #[source_code]
26 input: NamedSource<FileSource>,
27 #[label("Error location")]
28 pub error_location: SourceSpan,
29 pub unexpected_tokens: Vec<UnexpectedToken>,
30 pub expected_tokens: TokenVec,
31}
32
33impl std::fmt::Display for SyntaxError {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 if !self.unexpected_tokens.is_empty() {
36 let token = self.unexpected_tokens[0].token_type;
37 if token == TokenType::LAngle {
38 f.write_str(&format!(
39 "Unexpected token: '{token}', do you mean \"less than operator '<:'\" ?"
40 ))
41 } else if token == TokenType::RAngle {
42 f.write_str(&format!(
43 "Unexpected token: '{token}', do you mean \"greater than operator '>:'\" ?"
44 ))
45 } else {
46 f.write_str(&format!("Unexpected token: '{token}'"))
47 }
48 } else {
49 f.write_str("Syntax Error")
50 }
51 }
52}
53
54impl From<parol_runtime::SyntaxError> for SyntaxError {
55 fn from(value: parol_runtime::SyntaxError) -> Self {
56 Self {
57 cause: value.cause,
58 input: value.input.map(|e| FileSource(*e).into()).unwrap(),
59 error_location: Location(*value.error_location).into(),
60 unexpected_tokens: UnexpectedTokens(value.unexpected_tokens).into(),
61 expected_tokens: value.expected_tokens,
62 }
63 }
64}
65
66#[derive(Error, Diagnostic, Debug)]
67#[error("Unexpected token: {name} ({token_type})")]
68#[diagnostic(help("Unexpected token"), code(parol_runtime::unexpected_token))]
69pub struct UnexpectedToken {
70 name: String,
71 token_type: TokenType,
72 #[label("Unexpected token")]
73 pub(crate) token: SourceSpan,
74}
75
76#[derive(Clone, Copy, Debug, PartialEq, Eq)]
77pub enum TokenType {
78 Comments,
79 StringLiteral,
80 Exponent,
81 FixedPoint,
82 Based,
83 AllBit,
84 BaseLess,
85 MinusColon,
86 MinusGT,
87 PlusColon,
88 AssignmentOperator,
89 Operator11,
90 Operator10,
91 Operator09,
92 Operator08,
93 Operator07,
94 Operator06,
95 Operator02,
96 Operator01,
97 Operator05,
98 Operator04,
99 Operator03,
100 UnaryOperator,
101 ColonColon,
102 Colon,
103 Comma,
104 Dollar,
105 DotDotEqu,
106 DotDot,
107 Dot,
108 Equ,
109 Hash,
110 LAngle,
111 LBrace,
112 LBracket,
113 LParen,
114 RAngle,
115 RBrace,
116 RBracket,
117 RParen,
118 Semicolon,
119 Star,
120 AlwaysComb,
121 AlwaysFf,
122 Assign,
123 AsyncHigh,
124 AsyncLow,
125 As,
126 Bit,
127 Case,
128 Default,
129 Else,
130 Enum,
131 Export,
132 F32,
133 F64,
134 Final,
135 For,
136 Function,
137 I32,
138 I64,
139 IfReset,
140 If,
141 Import,
142 Initial,
143 Inout,
144 Input,
145 Inside,
146 Inst,
147 Interface,
148 In,
149 Let,
150 Local,
151 Logic,
152 Lsb,
153 Modport,
154 Module,
155 Msb,
156 Negedge,
157 Output,
158 Outside,
159 Package,
160 Param,
161 Posedge,
162 Pub,
163 Ref,
164 Repeat,
165 Return,
166 Signed,
167 Step,
168 String,
169 Struct,
170 SyncHigh,
171 SyncLow,
172 Tri,
173 Type,
174 U32,
175 U64,
176 Union,
177 Var,
178 Identifier,
179 Error,
180}
181
182impl From<&str> for TokenType {
183 fn from(value: &str) -> Self {
184 match value {
185 "CommentsTerm" => TokenType::Comments,
186 "StringLiteralTerm" => TokenType::StringLiteral,
187 "ExponentTerm" => TokenType::Exponent,
188 "FixedPointTerm" => TokenType::FixedPoint,
189 "BasedTerm" => TokenType::Based,
190 "AllBitTerm" => TokenType::AllBit,
191 "BaseLessTerm" => TokenType::BaseLess,
192 "MinusColonTerm" => TokenType::MinusColon,
193 "MinusGTTerm" => TokenType::MinusGT,
194 "PlusColonTerm" => TokenType::PlusColon,
195 "AssignmentOperatorTerm" => TokenType::AssignmentOperator,
196 "Operator11Term" => TokenType::Operator11,
197 "Operator10Term" => TokenType::Operator10,
198 "Operator09Term" => TokenType::Operator09,
199 "Operator08Term" => TokenType::Operator08,
200 "Operator07Term" => TokenType::Operator07,
201 "Operator06Term" => TokenType::Operator06,
202 "Operator02Term" => TokenType::Operator02,
203 "Operator01Term" => TokenType::Operator01,
204 "Operator05Term" => TokenType::Operator05,
205 "Operator04Term" => TokenType::Operator04,
206 "Operator03Term" => TokenType::Operator03,
207 "UnaryOperatorTerm" => TokenType::UnaryOperator,
208 "ColonColonTerm" => TokenType::ColonColon,
209 "ColonTerm" => TokenType::Colon,
210 "CommaTerm" => TokenType::Comma,
211 "DollarTerm" => TokenType::Dollar,
212 "DotDotEquTerm" => TokenType::DotDotEqu,
213 "DotDotTerm" => TokenType::DotDot,
214 "DotTerm" => TokenType::Dot,
215 "EquTerm" => TokenType::Equ,
216 "HashTerm" => TokenType::Hash,
217 "LAngleTerm" => TokenType::LAngle,
218 "LBraceTerm" => TokenType::LBrace,
219 "LBracketTerm" => TokenType::LBracket,
220 "LParenTerm" => TokenType::LParen,
221 "RAngleTerm" => TokenType::RAngle,
222 "RBraceTerm" => TokenType::RBrace,
223 "RBracketTerm" => TokenType::RBracket,
224 "RParenTerm" => TokenType::RParen,
225 "SemicolonTerm" => TokenType::Semicolon,
226 "StarTerm" => TokenType::Star,
227 "AlwaysCombTerm" => TokenType::AlwaysComb,
228 "AlwaysFfTerm" => TokenType::AlwaysFf,
229 "AssignTerm" => TokenType::Assign,
230 "AsyncHighTerm" => TokenType::AsyncHigh,
231 "AsyncLowTerm" => TokenType::AsyncLow,
232 "AsTerm" => TokenType::As,
233 "BitTerm" => TokenType::Bit,
234 "CaseTerm" => TokenType::Case,
235 "DefaultTerm" => TokenType::Default,
236 "ElseTerm" => TokenType::Else,
237 "EnumTerm" => TokenType::Enum,
238 "ExportTerm" => TokenType::Export,
239 "F32Term" => TokenType::F32,
240 "F64Term" => TokenType::F64,
241 "FinalTerm" => TokenType::Final,
242 "ForTerm" => TokenType::For,
243 "FunctionTerm" => TokenType::Function,
244 "I32Term" => TokenType::I32,
245 "I64Term" => TokenType::I64,
246 "IfResetTerm" => TokenType::IfReset,
247 "IfTerm" => TokenType::If,
248 "ImportTerm" => TokenType::Import,
249 "InitialTerm" => TokenType::Initial,
250 "InoutTerm" => TokenType::Inout,
251 "InputTerm" => TokenType::Input,
252 "InsideTerm" => TokenType::Inside,
253 "InstTerm" => TokenType::Inst,
254 "InterfaceTerm" => TokenType::Interface,
255 "InTerm" => TokenType::In,
256 "LetTerm" => TokenType::Let,
257 "LocalTerm" => TokenType::Local,
258 "LogicTerm" => TokenType::Logic,
259 "LsbTerm" => TokenType::Lsb,
260 "ModportTerm" => TokenType::Modport,
261 "ModuleTerm" => TokenType::Module,
262 "MsbTerm" => TokenType::Msb,
263 "NegedgeTerm" => TokenType::Negedge,
264 "OutputTerm" => TokenType::Output,
265 "OutsideTerm" => TokenType::Outside,
266 "PackageTerm" => TokenType::Package,
267 "ParamTerm" => TokenType::Param,
268 "PosedgeTerm" => TokenType::Posedge,
269 "PubTerm" => TokenType::Pub,
270 "RefTerm" => TokenType::Ref,
271 "RepeatTerm" => TokenType::Repeat,
272 "ReturnTerm" => TokenType::Return,
273 "SignedTerm" => TokenType::Signed,
274 "StepTerm" => TokenType::Step,
275 "StringTerm" => TokenType::String,
276 "StructTerm" => TokenType::Struct,
277 "SyncHighTerm" => TokenType::SyncHigh,
278 "SyncLowTerm" => TokenType::SyncLow,
279 "TriTerm" => TokenType::Tri,
280 "TypeTerm" => TokenType::Type,
281 "U32Term" => TokenType::U32,
282 "U64Term" => TokenType::U64,
283 "UnionTerm" => TokenType::Union,
284 "VarTerm" => TokenType::Var,
285 "IdentifierTerm" => TokenType::Identifier,
286 _ => TokenType::Error,
287 }
288 }
289}
290
291impl std::fmt::Display for TokenType {
292 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293 let text = match self {
294 TokenType::Comments => "comment",
295 TokenType::StringLiteral => "string literal",
296 TokenType::Exponent => "number",
297 TokenType::FixedPoint => "number",
298 TokenType::Based => "number",
299 TokenType::AllBit => "number",
300 TokenType::BaseLess => "number",
301 TokenType::MinusColon => "-:",
302 TokenType::MinusGT => "->",
303 TokenType::PlusColon => "+:",
304 TokenType::AssignmentOperator => "assignment operator",
305 TokenType::Operator11 => "operator",
306 TokenType::Operator10 => "operator",
307 TokenType::Operator09 => "operator",
308 TokenType::Operator08 => "operator",
309 TokenType::Operator07 => "operator",
310 TokenType::Operator06 => "operator",
311 TokenType::Operator02 => "operator",
312 TokenType::Operator01 => "operator",
313 TokenType::Operator05 => "operator",
314 TokenType::Operator04 => "operator",
315 TokenType::Operator03 => "operator",
316 TokenType::UnaryOperator => "operator",
317 TokenType::ColonColon => "::",
318 TokenType::Colon => ":",
319 TokenType::Comma => ",",
320 TokenType::Dollar => "$",
321 TokenType::DotDotEqu => "..=",
322 TokenType::DotDot => "..",
323 TokenType::Dot => ".",
324 TokenType::Equ => "=",
325 TokenType::Hash => "#",
326 TokenType::LAngle => "<",
327 TokenType::LBrace => "{",
328 TokenType::LBracket => "[",
329 TokenType::LParen => "(",
330 TokenType::RAngle => ">",
331 TokenType::RBrace => "}",
332 TokenType::RBracket => "]",
333 TokenType::RParen => ")",
334 TokenType::Semicolon => ";",
335 TokenType::Star => "*",
336 TokenType::AlwaysComb => "always_comb",
337 TokenType::AlwaysFf => "always_ff",
338 TokenType::Assign => "assign",
339 TokenType::AsyncHigh => "async_high",
340 TokenType::AsyncLow => "async_low",
341 TokenType::As => "as",
342 TokenType::Bit => "bit",
343 TokenType::Case => "case",
344 TokenType::Default => "default",
345 TokenType::Else => "else",
346 TokenType::Enum => "enum",
347 TokenType::Export => "export",
348 TokenType::F32 => "f32",
349 TokenType::F64 => "f64",
350 TokenType::Final => "final",
351 TokenType::For => "for",
352 TokenType::Function => "function",
353 TokenType::I32 => "i32",
354 TokenType::I64 => "i64",
355 TokenType::IfReset => "if_reset",
356 TokenType::If => "if",
357 TokenType::Import => "import",
358 TokenType::Initial => "initial",
359 TokenType::Inout => "inout",
360 TokenType::Input => "input",
361 TokenType::Inside => "inside",
362 TokenType::Inst => "inst",
363 TokenType::Interface => "interface",
364 TokenType::In => "in",
365 TokenType::Let => "let",
366 TokenType::Local => "local",
367 TokenType::Logic => "logic",
368 TokenType::Lsb => "lsb",
369 TokenType::Modport => "modport",
370 TokenType::Module => "module",
371 TokenType::Msb => "msb",
372 TokenType::Negedge => "negedge",
373 TokenType::Output => "output",
374 TokenType::Outside => "outside",
375 TokenType::Package => "package",
376 TokenType::Param => "param",
377 TokenType::Posedge => "posedge",
378 TokenType::Pub => "pub",
379 TokenType::Ref => "ref",
380 TokenType::Repeat => "repeat",
381 TokenType::Return => "return",
382 TokenType::Signed => "signed",
383 TokenType::Step => "step",
384 TokenType::String => "string",
385 TokenType::Struct => "struct",
386 TokenType::SyncHigh => "sync_high",
387 TokenType::SyncLow => "sync_low",
388 TokenType::Tri => "tri",
389 TokenType::Type => "type",
390 TokenType::U32 => "u32",
391 TokenType::U64 => "u64",
392 TokenType::Union => "union",
393 TokenType::Var => "var",
394 TokenType::Identifier => "identifier",
395 TokenType::Error => "error",
396 };
397 text.fmt(f)
398 }
399}
400
401impl From<ParolError> for ParserError {
402 fn from(x: ParolError) -> ParserError {
403 match x {
404 ParolError::ParserError(x) => match x {
405 parol_runtime::ParserError::SyntaxErrors { mut entries } if !entries.is_empty() => {
406 ParserError::SyntaxError(Box::new(entries.remove(0).into()))
407 }
408 _ => ParserError::ParserError(x),
409 },
410 ParolError::LexerError(x) => ParserError::LexerError(x),
411 ParolError::UserError(x) => ParserError::UserError(x),
412 }
413 }
414}
415
416struct FileSource(parol_runtime::FileSource);
417
418impl miette::SourceCode for FileSource {
419 fn read_span<'a>(
420 &'a self,
421 span: &SourceSpan,
422 context_lines_before: usize,
423 context_lines_after: usize,
424 ) -> Result<Box<dyn miette::SpanContents<'a> + 'a>, miette::MietteError> {
425 <str as miette::SourceCode>::read_span(
426 &self.0.input,
427 span,
428 context_lines_before,
429 context_lines_after,
430 )
431 }
432}
433
434impl From<FileSource> for NamedSource<FileSource> {
435 fn from(file_source: FileSource) -> Self {
436 let file_name = file_source.0.file_name.clone();
437 let file_name = file_name.to_str().unwrap_or("<Bad file name>");
438 Self::new(file_name, file_source)
439 }
440}
441
442struct Location(parol_runtime::Location);
443
444impl From<Location> for SourceSpan {
445 fn from(location: Location) -> Self {
446 SourceSpan::new((location.0.start as usize).into(), location.0.len())
447 }
448}
449
450struct UnexpectedTokens(Vec<parol_runtime::UnexpectedToken>);
451
452impl From<UnexpectedTokens> for Vec<UnexpectedToken> {
453 fn from(value: UnexpectedTokens) -> Self {
454 value
455 .0
456 .into_iter()
457 .map(|v| UnexpectedToken {
458 name: v.name,
459 token_type: v.token_type.as_str().into(),
460 token: Location(v.token).into(),
461 })
462 .collect::<Vec<UnexpectedToken>>()
463 }
464}