1#[cfg(feature = "report")]
2mod report;
3
4use std::fmt;
5
6#[cfg(feature = "report")]
7pub use report::Report;
8
9use crate::{
10 Span, lexer,
11 parser::AdditionalErrors,
12 type_system::{DirectiveLocation, MalformedDirectiveLocation},
13};
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub enum Error {
17 InvalidToken { location: usize },
20
21 UnrecognizedEof {
23 location: usize,
25
26 expected: Vec<String>,
30 },
31
32 UnrecognizedToken {
34 token: (usize, String, usize),
36
37 expected: Vec<String>,
41 },
42
43 ExtraToken { token: (usize, String, usize) },
45
46 Lexical(lexer::LexicalError),
48
49 MalformedStringLiteral(crate::common::MalformedStringError),
51
52 MalformedDirectiveLocation(usize, String, usize),
54
55 VariableInConstPosition(usize, String, usize),
57
58 EmptyTypeSystemDocument,
60
61 EmptyExecutableDocument,
63
64 EmptySchemaCoordinate,
66}
67
68impl Error {
69 pub fn span(&self) -> Option<Span> {
70 match self {
71 Error::InvalidToken { location } => Span::new(*location, *location).into(),
72 Error::UnrecognizedEof { location, .. } => Span::new(*location, *location).into(),
73 Error::UnrecognizedToken {
74 token: (start, _, end),
75 ..
76 } => Span::new(*start, *end).into(),
77 Error::ExtraToken {
78 token: (start, _, end),
79 ..
80 } => Span::new(*start, *end).into(),
81 Error::Lexical(error) => error.span().into(),
82 Error::MalformedStringLiteral(error) => error.span().into(),
83 Error::MalformedDirectiveLocation(lhs, _, rhs) => Span::new(*lhs, *rhs).into(),
84 Error::VariableInConstPosition(lhs, _, rhs) => Span::new(*lhs, *rhs).into(),
85 Error::EmptyExecutableDocument
86 | Error::EmptyTypeSystemDocument
87 | Error::EmptySchemaCoordinate => None,
88 }
89 }
90}
91
92impl std::error::Error for Error {
93 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
94 match self {
95 Error::InvalidToken { .. }
96 | Error::UnrecognizedEof { .. }
97 | Error::UnrecognizedToken { .. }
98 | Error::ExtraToken { .. }
99 | Error::MalformedStringLiteral(..)
100 | Error::MalformedDirectiveLocation(..)
101 | Error::VariableInConstPosition(..)
102 | Error::EmptyTypeSystemDocument
103 | Error::EmptyExecutableDocument => None,
104 Error::Lexical(error) => Some(error),
105 Error::EmptySchemaCoordinate => todo!(),
106 }
107 }
108}
109
110impl fmt::Display for Error {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 match self {
113 Error::InvalidToken { location: _ } => {
114 write!(f, "invalid token")
115 }
116 Error::UnrecognizedEof {
117 location: _,
118 expected,
119 } => {
120 write!(f, "unexpected end of file (expected one of ")?;
121 for (i, item) in expected.iter().enumerate() {
122 if i != 1 {
123 write!(f, ", ")?;
124 }
125 write!(f, "{item}")?;
126 }
127 write!(f, ")")
128 }
129 Error::UnrecognizedToken {
130 token: (_, token, _),
131 expected,
132 } => {
133 write!(f, "unexpected {token} token (expected one of ")?;
134 for (i, item) in expected.iter().enumerate() {
135 if i != 1 {
136 write!(f, ", ")?;
137 }
138 write!(f, "{item}")?;
139 }
140 write!(f, ")")
141 }
142 Error::ExtraToken {
143 token: (_, token, _),
144 } => {
145 write!(f, "found a {token} after the expected end of the document")
146 }
147 Error::Lexical(error) => {
148 write!(f, "{error}")
149 }
150 Error::MalformedStringLiteral(error) => {
151 write!(f, "malformed string literal: {error}")
152 }
153 Error::MalformedDirectiveLocation(_, location, _) => {
154 write!(
155 f,
156 "unknown directive location: {location}. expected one of "
157 )?;
158
159 for (i, location) in DirectiveLocation::all_locations().iter().enumerate() {
160 if i != 0 {
161 write!(f, ", ")?;
162 }
163 write!(f, "{location}")?;
164 }
165 Ok(())
166 }
167 Error::VariableInConstPosition(_, name, _) => {
168 write!(
169 f,
170 "the variable ${name} was found in a position that does not allow variables"
171 )?;
172 Ok(())
173 }
174 Error::EmptyExecutableDocument => {
175 write!(
176 f,
177 "the graphql document was empty, please provide an operation"
178 )
179 }
180 Error::EmptyTypeSystemDocument => {
181 write!(
182 f,
183 "the graphql document was empty, please provide at least one definition"
184 )
185 }
186 Error::EmptySchemaCoordinate => {
187 write!(f, "the schema coordinate was empty")
188 }
189 }
190 }
191}
192
193impl From<lalrpop_util::ParseError<usize, lexer::Token<'_>, AdditionalErrors>> for Error {
194 fn from(value: lalrpop_util::ParseError<usize, lexer::Token<'_>, AdditionalErrors>) -> Self {
195 use lalrpop_util::ParseError;
196 match value {
197 ParseError::InvalidToken { location } => Error::InvalidToken { location },
198 ParseError::UnrecognizedEof { location, expected } => {
199 Error::UnrecognizedEof { location, expected }
200 }
201 ParseError::UnrecognizedToken {
202 token: (lspan, token, rspan),
203 expected,
204 } => Error::UnrecognizedToken {
205 token: (lspan, token.to_string(), rspan),
206 expected,
207 },
208 ParseError::ExtraToken {
209 token: (lspan, token, rspan),
210 } => Error::ExtraToken {
211 token: (lspan, token.to_string(), rspan),
212 },
213 ParseError::User {
214 error: AdditionalErrors::Lexical(error),
215 } => Error::Lexical(error),
216 ParseError::User {
217 error: AdditionalErrors::MalformedString(error),
218 } => Error::MalformedStringLiteral(error),
219 ParseError::User {
220 error: AdditionalErrors::MalformedDirectiveLocation(lhs, location, rhs),
221 } => Error::MalformedDirectiveLocation(lhs, location, rhs),
222 ParseError::User {
223 error: AdditionalErrors::VariableInConstPosition(lhs, name, rhs),
224 } => Error::MalformedDirectiveLocation(lhs, name, rhs),
225 }
226 }
227}
228
229impl MalformedDirectiveLocation {
230 pub(crate) fn into_lalrpop_error<'a>(
231 self,
232 (lhs, rhs): (usize, usize),
233 ) -> lalrpop_util::ParseError<usize, lexer::Token<'a>, AdditionalErrors> {
234 lalrpop_util::ParseError::User {
235 error: AdditionalErrors::MalformedDirectiveLocation(lhs, self.0, rhs),
236 }
237 }
238}