1use crate::lexer;
2use crate::lexer::locations::Position;
3use crate::lexer::{locations::GetSpan, Token, TokenKind};
4
5use crate::error_meta::ContextualError;
6
7use super::{Parser, Result, TokenCheck};
8
9impl<'source> std::fmt::Display for lexer::Token<'source> {
10 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11 use TokenKind::*;
12 match self.kind {
13 Url | Linecomment | IllegalToken => {
14 write!(f, "{}<{}>", self.kind, self.text)
15 }
16 kind => write!(f, "{kind}"),
17 }
18 }
19}
20
21#[derive(Debug, Clone, PartialEq, serde::Serialize)]
22pub enum ParseError<'source> {
23 ExpectedToken {
24 found: lexer::Token<'source>,
25 expected: TokenKind,
26 },
27 ExpectedEitherOfTokens {
28 found: lexer::Token<'source>,
29 expected: Box<[TokenKind]>,
30 },
31}
32
33impl<'source> std::error::Error for ParseError<'source> {}
34
35impl<'source> std::fmt::Display for ParseError<'source> {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 let formatted_error = match self {
38 ParseError::ExpectedToken {
39 expected, found, ..
40 } => {
41 format!("expected '{}' but got {}", expected, found)
42 }
43 ParseError::ExpectedEitherOfTokens {
44 found, expected, ..
45 } => {
46 let expected = expected
47 .iter()
48 .map(|kind| format!("'{}'", kind))
49 .collect::<Vec<String>>()
50 .join(",");
51 format!("expected either one of {} but got {}", expected, found)
52 }
53 };
54
55 f.write_str(&formatted_error)
56 }
57}
58
59#[derive(Debug)]
60pub struct ParserErrors<'source> {
61 pub errors: Box<[ContextualError<ParseError<'source>>]>,
62}
63
64impl<'source> ParserErrors<'source> {
65 pub fn new(errors: Vec<ContextualError<ParseError<'source>>>) -> Self {
66 Self {
67 errors: errors.into(),
68 }
69 }
70}
71
72impl<'source> std::error::Error for ParserErrors<'source> {}
73
74impl<'source> std::fmt::Display for ParserErrors<'source> {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 for err in self.errors.iter() {
77 write!(f, "{err}")?
78 }
79 Ok(())
80 }
81}
82
83#[derive(Debug)]
84pub struct Expectations<'i> {
85 source_code: &'i str,
86 pub start: Position,
87}
88
89impl<'i> Expectations<'i> {
90 pub fn new(parser: &Parser<'i>) -> Self {
91 Self {
92 source_code: parser.lexer.input(),
93 start: parser.curr_token().start,
94 }
95 }
96
97 pub fn expect_peek<'p>(
98 &self,
99 parser: &'p mut Parser<'i>,
100 expected_kind: TokenKind,
101 ) -> Result<'i, &'p Token<'i>> {
102 if parser.peek_token().is(expected_kind) {
103 return Ok(parser.next_token());
104 }
105
106 let error = self.expected_token(parser.next_token(), expected_kind);
107
108 Err(error.into())
109 }
110
111 pub fn expect_peek_ahead<'p>(
113 &self,
114 parser: &'p mut Parser<'i>,
115 expected_kind: TokenKind,
116 ) -> Result<'i, &'p Token<'i>> {
117 let peeked = parser.peek_token();
118 if peeked.is(expected_kind) {
119 return Ok(peeked);
120 }
121
122 let error = self.expected_token(peeked, expected_kind);
123
124 Err(error.into())
125 }
126
127 pub fn expect_peek_one_of(
128 &self,
129 parser: &mut Parser<'i>,
130 expected_kinds: &[TokenKind],
131 ) -> Result<'i, ()> {
132 if parser.peek_token().is_one_of(expected_kinds) {
133 return Ok(());
134 }
135
136 let error = self.expected_one_of_tokens(parser.next_token(), expected_kinds);
137
138 Err(error.into())
139 }
140
141 pub fn expected_token(
142 &self,
143 token: &Token<'i>,
144 expected: TokenKind,
145 ) -> ContextualError<ParseError<'i>> {
146 ContextualError::new(
147 ParseError::ExpectedToken {
148 found: token.clone(),
149 expected,
150 },
151 self.start.to_end_of(token.span()),
152 self.source_code,
153 )
154 }
155
156 pub fn expected_one_of_tokens(
157 &self,
158 token: &Token<'i>,
159 expected_kinds: &[TokenKind],
160 ) -> ContextualError<ParseError<'i>> {
161 let mut expected_dedpuded: Vec<TokenKind> = vec![];
162
163 for kind in expected_kinds {
164 if !expected_dedpuded.contains(kind) {
165 expected_dedpuded.push(*kind)
166 }
167 }
168
169 ContextualError::new(
170 ParseError::ExpectedEitherOfTokens {
171 found: token.clone(),
172 expected: expected_dedpuded.into(),
173 },
174 self.start.to_end_of(token.span()),
175 self.source_code,
176 )
177 }
178}
179
180pub struct ErrorsCollector<'source> {
181 pub list: Vec<ContextualError<ParseError<'source>>>,
182}
183
184impl<'source> crate::parser::ast_visit::Visitor<'source> for ErrorsCollector<'source> {
185 fn visit_error(&mut self, err: &ContextualError<ParseError<'source>>) {
186 self.list.push(err.clone());
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use crate::parser::Parser;
193
194 use insta::assert_ron_snapshot;
195
196 macro_rules! assert_ast {
197 ($input:literal) => {
198 let mut parser = Parser::new($input);
199 let ast = parser.parse();
200
201 insta::with_settings!({
202 description => $input
203 }, {
204 assert_ron_snapshot!(ast)
205 });
206
207 assert!(!ast.errors().is_empty())
208 };
209 }
210
211 #[test]
212 fn expected_url_after_method() {
213 assert_ast!("get");
214 assert_ast!("post");
215 }
216
217 #[test]
218 fn expected_name_after_header_keyword() {
219 assert_ast!("post http://localhost {header}");
220 }
221
222 #[test]
223 fn expecting_identifier_or_string_lit_after_header_name() {
224 assert_ast!(r#"get http://localhost { header "name" }"#);
225 }
226
227 #[test]
228 fn expecting_request_or_other_attribute_after_attributes() {
229 assert_ast!(
230 r#"
231 @skip
232 @dbg
233 let k = "v"
234 get http://localhost { header "name" k }"#
235 );
236 }
237
238 #[test]
239 fn expecting_commas_between_certain_json_items() {
240 assert_ast!(
241 r#"let o = {
242 yo: "joe"
243 hello: "world"
244 }"#
245 );
246 assert_ast!(r#" let o = ["joe" "world"] "#);
247 }
248
249 #[test]
250 fn expecting_partial_block_with_error() {
251 assert_ast!(r#"get /hello { header "test" "value" header }"#);
252 }
253
254 #[test]
255 fn expecting_partial_block_with_missing_body_expr() {
256 assert_ast!(
257 r#"
258get /sdf {
259 header "" s
260 body }
261"#
262 );
263 }
264
265 #[test]
266 fn expecting_partial_block_with_errors() {
267 assert_ast!(
268 r#"
269get /adsf {
270 header
271 body a
272}
273"#
274 );
275 }
276
277 #[test]
278 fn expecting_partial_object_literal_with_errors() {
279 assert_ast!(
280 r#"
281let b = {
282 "key": value,
283 "key2":
284}
285"#
286 );
287 }
288
289 #[test]
290 fn expecting_expression_error_for_parameter_of_unfinished_string() {
291 assert_ast!(
292 r#"
293let a = env(")
294"#
295 );
296
297 assert_ast!(
298 r#"
299let b = [env(")]
300"#
301 );
302
303 assert_ast!(
304 r#"
305let b = {
306 key: env(")
307}
308"#
309 );
310 }
311
312 #[test]
313 fn expected_comma_before_more_parameters() {
314 assert_ast!(r#"env("base" "url")"#);
315 assert_ast!(r#"env("", false 12)"#);
316 }
317
318 #[test]
319 fn expected_closing_curly_after_expression_part_in_template_string() {
320 assert_ast!(r#"`wowee ${"hello"} error ahead ${env("base")`"#);
321 assert_ast!(r#"`wowee ${"hello"} error ahead ${variable_name`"#);
322 assert_ast!(r#"`error ahead ${variable_name `"#);
323 }
324}