Skip to main content

litcheck_filecheck/expr/
error.rs

1use crate::common::*;
2
3#[derive(Default, Diagnostic, Clone, Debug, thiserror::Error)]
4pub enum ExprError {
5    #[error("invalid token")]
6    #[diagnostic()]
7    InvalidToken {
8        #[label("occurs here")]
9        span: SourceSpan,
10    },
11    #[error("unrecognized token")]
12    #[diagnostic(help("expected one of: {}", expected.as_slice().join(", ")))]
13    UnrecognizedToken {
14        #[label("lexed a {token} here")]
15        span: SourceSpan,
16        token: String,
17        expected: Vec<String>,
18    },
19    #[error("unexpected trailing tokens")]
20    #[diagnostic()]
21    ExtraToken {
22        #[label("{token} was found here, but was not expected")]
23        span: SourceSpan,
24        token: String,
25    },
26    #[error("unexpected end of file")]
27    #[diagnostic(help("expected one of: {}", expected.as_slice().join(", ")))]
28    UnrecognizedEof {
29        #[label("reached end of file here")]
30        span: SourceSpan,
31        expected: Vec<String>,
32    },
33    #[error(transparent)]
34    #[diagnostic(transparent)]
35    InvalidCall(#[from] InvalidCallExprError),
36    #[error("invalid numeric expression")]
37    #[diagnostic(help("make sure the value is parseable as a 64-bit signed integer"))]
38    Number {
39        #[label("{error}")]
40        span: SourceSpan,
41        #[source]
42        error: core::num::ParseIntError,
43    },
44    #[error("invalid format specifier")]
45    #[diagnostic()]
46    InvalidFormatSpecifier {
47        #[label("this numeric format specifier is not recognized")]
48        span: SourceSpan,
49    },
50    #[error("invalid numeric precision")]
51    #[diagnostic()]
52    InvalidNumericPrecision {
53        #[label("the precision value here is too large")]
54        span: SourceSpan,
55    },
56    #[error("invalid format specifier")]
57    #[diagnostic()]
58    InvalidAlternateForm {
59        #[label("alternate form only supported for hex values")]
60        span: SourceSpan,
61    },
62    /// This is only used for the default implementation required by logos
63    #[default]
64    #[error("an unknown error occurred")]
65    #[diagnostic()]
66    Unknown,
67}
68impl PartialEq for ExprError {
69    fn eq(&self, other: &Self) -> bool {
70        match (self, other) {
71            (Self::InvalidToken { .. }, Self::InvalidToken { .. }) => true,
72            (
73                Self::UnrecognizedToken {
74                    token: at,
75                    expected: a,
76                    ..
77                },
78                Self::UnrecognizedToken {
79                    token: bt,
80                    expected: b,
81                    ..
82                },
83            ) => at == bt && a == b,
84            (Self::ExtraToken { token: a, .. }, Self::ExtraToken { token: b, .. }) => a == b,
85            (
86                Self::UnrecognizedEof { expected: a, .. },
87                Self::UnrecognizedEof { expected: b, .. },
88            ) => a == b,
89            (Self::InvalidCall(a), Self::InvalidCall(b)) => a == b,
90            (Self::Number { .. }, Self::Number { .. }) => true,
91            (Self::InvalidFormatSpecifier { .. }, Self::InvalidFormatSpecifier { .. }) => true,
92            (Self::InvalidNumericPrecision { .. }, Self::InvalidNumericPrecision { .. }) => true,
93            (Self::InvalidAlternateForm { .. }, Self::InvalidAlternateForm { .. }) => true,
94            (Self::Unknown, Self::Unknown) => true,
95            _ => false,
96        }
97    }
98}
99impl Spanned for ExprError {
100    fn span(&self) -> SourceSpan {
101        match self {
102            Self::InvalidCall(err) => err.span(),
103            Self::InvalidToken { span, .. }
104            | Self::UnrecognizedToken { span, .. }
105            | Self::ExtraToken { span, .. }
106            | Self::UnrecognizedEof { span, .. }
107            | Self::Number { span, .. }
108            | Self::InvalidFormatSpecifier { span, .. }
109            | Self::InvalidNumericPrecision { span, .. }
110            | Self::InvalidAlternateForm { span, .. } => *span,
111            Self::Unknown => SourceSpan::UNKNOWN,
112        }
113    }
114}
115
116#[derive(Debug, Clone, Diagnostic, thiserror::Error)]
117pub enum InvalidCallExprError {
118    #[error("undefined function")]
119    #[diagnostic()]
120    Undefined {
121        #[label("no such function defined in this context")]
122        span: SourceSpan,
123        callee: String,
124    },
125    #[error("function '{callee}' expects {expected} arguments, but was given {given}")]
126    #[diagnostic()]
127    InvalidArity {
128        #[label("this function only takes {expected} arguments")]
129        span: SourceSpan,
130        callee: String,
131        expected: u8,
132        given: u8,
133    },
134}
135impl Spanned for InvalidCallExprError {
136    fn span(&self) -> SourceSpan {
137        match self {
138            Self::Undefined { span, .. } | Self::InvalidArity { span, .. } => *span,
139        }
140    }
141}
142impl PartialEq for InvalidCallExprError {
143    fn eq(&self, other: &Self) -> bool {
144        match (self, other) {
145            (Self::Undefined { callee: a, .. }, Self::Undefined { callee: b, .. }) => a == b,
146            (
147                Self::InvalidArity {
148                    callee: a,
149                    expected: ae,
150                    given: ag,
151                    ..
152                },
153                Self::InvalidArity {
154                    callee: b,
155                    expected: be,
156                    given: bg,
157                    ..
158                },
159            ) => a == b && ae == be && ag == bg,
160            _ => false,
161        }
162    }
163}