Skip to main content

veryl_migrator/
parser_error.rs

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}