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