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    /// This is only used for the default implementation required by logos
59    #[default]
60    #[error("an unknown error occurred")]
61    #[diagnostic()]
62    Unknown,
63}
64impl PartialEq for ExprError {
65    fn eq(&self, other: &Self) -> bool {
66        match (self, other) {
67            (Self::InvalidToken { .. }, Self::InvalidToken { .. }) => true,
68            (
69                Self::UnrecognizedToken {
70                    token: at,
71                    expected: a,
72                    ..
73                },
74                Self::UnrecognizedToken {
75                    token: bt,
76                    expected: b,
77                    ..
78                },
79            ) => at == bt && a == b,
80            (Self::ExtraToken { token: a, .. }, Self::ExtraToken { token: b, .. }) => a == b,
81            (
82                Self::UnrecognizedEof { expected: a, .. },
83                Self::UnrecognizedEof { expected: b, .. },
84            ) => a == b,
85            (Self::InvalidCall(a), Self::InvalidCall(b)) => a == b,
86            (Self::Number { .. }, Self::Number { .. }) => true,
87            (Self::InvalidFormatSpecifier { .. }, Self::InvalidFormatSpecifier { .. }) => true,
88            (Self::InvalidNumericPrecision { .. }, Self::InvalidNumericPrecision { .. }) => true,
89            (Self::Unknown, Self::Unknown) => true,
90            _ => false,
91        }
92    }
93}
94impl Spanned for ExprError {
95    fn span(&self) -> SourceSpan {
96        match self {
97            Self::InvalidCall(err) => err.span(),
98            Self::InvalidToken { span, .. }
99            | Self::UnrecognizedToken { span, .. }
100            | Self::ExtraToken { span, .. }
101            | Self::UnrecognizedEof { span, .. }
102            | Self::Number { span, .. }
103            | Self::InvalidFormatSpecifier { span, .. }
104            | Self::InvalidNumericPrecision { span, .. } => *span,
105            Self::Unknown => SourceSpan::from(0..0),
106        }
107    }
108}
109
110#[derive(Debug, Clone, Diagnostic, thiserror::Error)]
111pub enum InvalidCallExprError {
112    #[error("undefined function")]
113    #[diagnostic()]
114    Undefined {
115        #[label("no such function defined in this context")]
116        span: SourceSpan,
117        callee: String,
118    },
119    #[error("function '{callee}' expects {expected} arguments, but was given {given}")]
120    #[diagnostic()]
121    InvalidArity {
122        #[label("this function only takes {expected} arguments")]
123        span: SourceSpan,
124        callee: String,
125        expected: u8,
126        given: u8,
127    },
128}
129impl Spanned for InvalidCallExprError {
130    fn span(&self) -> SourceSpan {
131        match self {
132            Self::Undefined { span, .. } | Self::InvalidArity { span, .. } => *span,
133        }
134    }
135}
136impl PartialEq for InvalidCallExprError {
137    fn eq(&self, other: &Self) -> bool {
138        match (self, other) {
139            (Self::Undefined { callee: a, .. }, Self::Undefined { callee: b, .. }) => a == b,
140            (
141                Self::InvalidArity {
142                    callee: a,
143                    expected: ae,
144                    given: ag,
145                    ..
146                },
147                Self::InvalidArity {
148                    callee: b,
149                    expected: be,
150                    given: bg,
151                    ..
152                },
153            ) => a == b && ae == be && ag == bg,
154            _ => false,
155        }
156    }
157}