Skip to main content

litcheck_filecheck/expr/
error.rs

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