1use crate::{
3 core::{
4 capture, capture_single, exact, fragment_exact, get_and, get_end, get_hash, get_question,
5 get_slash, nothing, query,
6 },
7 error::{get_reason, ParseError, ParserErrorReason, PrettyParseError},
8 FieldNamingScheme,
9};
10use nom::{branch::alt, IResult};
11#[derive(Debug, Clone, Copy, PartialEq)]
16pub enum RouteParserToken<'a> {
17 Nothing,
19 Separator,
21 Exact(&'a str),
23 Capture(RefCaptureVariant<'a>),
25 QueryBegin,
27 QuerySeparator,
29 Query {
31 ident: &'a str,
33 capture_or_exact: CaptureOrExact<'a>,
35 },
36 FragmentBegin,
38 End,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq)]
50pub enum RefCaptureVariant<'a> {
51 Unnamed,
53 ManyUnnamed,
55 NumberedUnnamed {
57 sections: usize,
59 },
60 Named(&'a str),
62 ManyNamed(&'a str),
64 NumberedNamed {
66 sections: usize,
68 name: &'a str,
70 },
71}
72
73#[derive(Debug, Clone, Copy, PartialEq)]
75pub enum CaptureOrExact<'a> {
76 Exact(&'a str),
78 Capture(RefCaptureVariant<'a>),
80}
81
82#[derive(Clone, PartialEq)]
84enum ParserState<'a> {
85 None,
86 Path { prev_token: RouteParserToken<'a> },
87 FirstQuery { prev_token: RouteParserToken<'a> },
88 NthQuery { prev_token: RouteParserToken<'a> },
89 Fragment { prev_token: RouteParserToken<'a> },
90 End,
91}
92impl<'a> ParserState<'a> {
93 fn transition(self, token: RouteParserToken<'a>) -> Result<Self, ParserErrorReason> {
100 match self {
101 ParserState::None => match token {
102 RouteParserToken::Separator
103 | RouteParserToken::Exact(_)
104 | RouteParserToken::Capture(_) => Ok(ParserState::Path { prev_token: token }),
105 RouteParserToken::QueryBegin => Ok(ParserState::FirstQuery { prev_token: token }),
106 RouteParserToken::QuerySeparator => Ok(ParserState::NthQuery { prev_token: token }),
107 RouteParserToken::Query { .. } => Err(ParserErrorReason::NotAllowedStateTransition),
108 RouteParserToken::FragmentBegin => Ok(ParserState::Fragment { prev_token: token }),
109 RouteParserToken::Nothing | RouteParserToken::End => Ok(ParserState::End),
110 },
111 ParserState::Path { prev_token } => {
112 match prev_token {
113 RouteParserToken::Separator => match token {
114 RouteParserToken::Exact(_) | RouteParserToken::Capture(_) => {
115 Ok(ParserState::Path { prev_token: token })
116 }
117 RouteParserToken::QueryBegin => {
118 Ok(ParserState::FirstQuery { prev_token: token })
119 }
120 RouteParserToken::FragmentBegin => {
121 Ok(ParserState::Fragment { prev_token: token })
122 }
123 RouteParserToken::End => Ok(ParserState::End),
124 _ => Err(ParserErrorReason::NotAllowedStateTransition),
125 },
126 RouteParserToken::Exact(_) => match token {
127 RouteParserToken::Exact(_)
128 | RouteParserToken::Separator
129 | RouteParserToken::Capture(_) => {
130 Ok(ParserState::Path { prev_token: token })
131 }
132 RouteParserToken::QueryBegin => {
133 Ok(ParserState::FirstQuery { prev_token: token })
134 }
135 RouteParserToken::FragmentBegin => {
136 Ok(ParserState::Fragment { prev_token: token })
137 }
138 RouteParserToken::End => Ok(ParserState::End),
139 _ => Err(ParserErrorReason::NotAllowedStateTransition),
140 },
141 RouteParserToken::Capture(_) => match token {
142 RouteParserToken::Separator | RouteParserToken::Exact(_) => {
143 Ok(ParserState::Path { prev_token: token })
144 }
145 RouteParserToken::QueryBegin => {
146 Ok(ParserState::FirstQuery { prev_token: token })
147 }
148 RouteParserToken::FragmentBegin => {
149 Ok(ParserState::Fragment { prev_token: token })
150 }
151 RouteParserToken::End => Ok(ParserState::End),
152 _ => Err(ParserErrorReason::NotAllowedStateTransition),
153 },
154 _ => Err(ParserErrorReason::InvalidState), }
157 }
158 ParserState::FirstQuery { prev_token } => match prev_token {
159 RouteParserToken::QueryBegin => match token {
160 RouteParserToken::Query { .. } => {
161 Ok(ParserState::FirstQuery { prev_token: token })
162 }
163 _ => Err(ParserErrorReason::NotAllowedStateTransition),
164 },
165 RouteParserToken::Query { .. } => match token {
166 RouteParserToken::QuerySeparator => {
167 Ok(ParserState::NthQuery { prev_token: token })
168 }
169 RouteParserToken::FragmentBegin => {
170 Ok(ParserState::Fragment { prev_token: token })
171 }
172 RouteParserToken::End => Ok(ParserState::End),
173 _ => Err(ParserErrorReason::NotAllowedStateTransition),
174 },
175 _ => Err(ParserErrorReason::InvalidState),
176 },
177 ParserState::NthQuery { prev_token } => match prev_token {
178 RouteParserToken::QuerySeparator => match token {
179 RouteParserToken::Query { .. } => {
180 Ok(ParserState::NthQuery { prev_token: token })
181 }
182 _ => Err(ParserErrorReason::NotAllowedStateTransition),
183 },
184 RouteParserToken::Query { .. } => match token {
185 RouteParserToken::QuerySeparator => {
186 Ok(ParserState::NthQuery { prev_token: token })
187 }
188 RouteParserToken::FragmentBegin => {
189 Ok(ParserState::Fragment { prev_token: token })
190 }
191 RouteParserToken::End => Ok(ParserState::End),
192 _ => Err(ParserErrorReason::NotAllowedStateTransition),
193 },
194 _ => Err(ParserErrorReason::InvalidState),
195 },
196 ParserState::Fragment { prev_token } => match prev_token {
197 RouteParserToken::FragmentBegin
198 | RouteParserToken::Exact(_)
199 | RouteParserToken::Capture(_) => Ok(ParserState::Fragment { prev_token: token }),
200 RouteParserToken::End => Ok(ParserState::End),
201 _ => Err(ParserErrorReason::InvalidState),
202 },
203 ParserState::End => Err(ParserErrorReason::TokensAfterEndToken),
204 }
205 }
206}
207
208pub fn parse(
217 mut i: &str,
218 field_naming_scheme: FieldNamingScheme,
219) -> Result<Vec<RouteParserToken>, PrettyParseError> {
220 let input = i;
221 let mut tokens: Vec<RouteParserToken> = vec![];
222 let mut state = ParserState::None;
223
224 loop {
225 let (ii, token) = parse_impl(i, &state, field_naming_scheme).map_err(|e| match e {
226 nom::Err::Error(e) | nom::Err::Failure(e) => PrettyParseError {
227 error: e,
228 input,
229 remaining: i,
230 },
231 _ => panic!("parser should not be incomplete"),
232 })?;
233 i = ii;
234 state = state.transition(token.clone()).map_err(|reason| {
235 let error = ParseError {
236 reason: Some(reason),
237 expected: vec![],
238 offset: 0,
239 };
240 PrettyParseError {
241 error,
242 input,
243 remaining: i,
244 }
245 })?;
246 tokens.push(token);
247
248 if i.is_empty() {
250 break;
251 }
252 }
253 Ok(tokens)
254}
255
256fn parse_impl<'a>(
257 i: &'a str,
258 state: &ParserState,
259 field_naming_scheme: FieldNamingScheme,
260) -> IResult<&'a str, RouteParserToken<'a>, ParseError> {
261 match state {
262 ParserState::None => alt((
263 get_slash,
264 get_question,
265 get_and,
266 get_hash,
267 capture(field_naming_scheme),
268 exact,
269 get_end,
270 nothing,
271 ))(i),
272 ParserState::Path { prev_token } => match prev_token {
273 RouteParserToken::Separator => {
274 alt((
275 exact,
276 capture(field_naming_scheme),
277 get_question,
278 get_hash,
279 get_end,
280 ))(i)
281 .map_err(|mut e: nom::Err<ParseError>| {
282 let reason: &mut Option<ParserErrorReason> = get_reason(&mut e);
284 *reason = get_slash(i)
285 .map(|_| ParserErrorReason::DoubleSlash)
286 .or_else(|_| get_and(i).map(|_| ParserErrorReason::AndBeforeQuestion))
287 .ok()
288 .or(*reason);
289 e
290 })
291 }
292 RouteParserToken::Exact(_) => {
293 alt((
294 get_slash,
295 exact, capture(field_naming_scheme),
297 get_question,
298 get_hash,
299 get_end,
300 ))(i)
301 .map_err(|mut e: nom::Err<ParseError>| {
302 let reason: &mut Option<ParserErrorReason> = get_reason(&mut e);
304 *reason = get_and(i)
305 .map(|_| ParserErrorReason::AndBeforeQuestion)
306 .ok()
307 .or(*reason);
308 e
309 })
310 }
311 RouteParserToken::Capture(_) => {
312 alt((get_slash, exact, get_question, get_hash, get_end))(i).map_err(
313 |mut e: nom::Err<ParseError>| {
314 let reason: &mut Option<ParserErrorReason> = get_reason(&mut e);
316 *reason = capture(field_naming_scheme)(i)
317 .map(|_| ParserErrorReason::AdjacentCaptures)
318 .or_else(|_| get_and(i).map(|_| ParserErrorReason::AndBeforeQuestion))
319 .ok()
320 .or(*reason);
321 e
322 },
323 )
324 }
325 _ => Err(nom::Err::Failure(ParseError {
326 reason: Some(ParserErrorReason::InvalidState),
327 expected: vec![],
328 offset: 0,
329 })),
330 },
331 ParserState::FirstQuery { prev_token } => match prev_token {
332 RouteParserToken::QueryBegin => {
333 query(field_naming_scheme)(i).map_err(|mut e: nom::Err<ParseError>| {
334 let reason: &mut Option<ParserErrorReason> = get_reason(&mut e);
336 *reason = get_question(i)
337 .map(|_| ParserErrorReason::MultipleQuestions)
338 .ok()
339 .or(*reason);
340 e
341 })
342 }
343 RouteParserToken::Query { .. } => {
344 alt((get_and, get_hash, get_end))(i).map_err(|mut e: nom::Err<ParseError>| {
345 let reason: &mut Option<ParserErrorReason> = get_reason(&mut e);
347 *reason = get_question(i)
348 .map(|_| ParserErrorReason::MultipleQuestions)
349 .ok()
350 .or(*reason);
351 e
352 })
353 }
354 _ => Err(nom::Err::Failure(ParseError {
355 reason: Some(ParserErrorReason::InvalidState),
356 expected: vec![],
357 offset: 0,
358 })),
359 },
360 ParserState::NthQuery { prev_token } => match prev_token {
361 RouteParserToken::QuerySeparator => {
362 query(field_naming_scheme)(i).map_err(|mut e: nom::Err<ParseError>| {
363 let reason: &mut Option<ParserErrorReason> = get_reason(&mut e);
365 *reason = get_question(i)
366 .map(|_| ParserErrorReason::MultipleQuestions)
367 .ok()
368 .or(*reason);
369 e
370 })
371 }
372 RouteParserToken::Query { .. } => {
373 alt((get_and, get_hash, get_end))(i).map_err(|mut e: nom::Err<ParseError>| {
374 let reason: &mut Option<ParserErrorReason> = get_reason(&mut e);
376 *reason = get_question(i)
377 .map(|_| ParserErrorReason::MultipleQuestions)
378 .ok()
379 .or(*reason);
380 e
381 })
382 }
383 _ => Err(nom::Err::Failure(ParseError {
384 reason: Some(ParserErrorReason::InvalidState),
385 expected: vec![],
386 offset: 0,
387 })),
388 },
389 ParserState::Fragment { prev_token } => match prev_token {
390 RouteParserToken::FragmentBegin => {
391 alt((fragment_exact, capture_single(field_naming_scheme), get_end))(i)
392 }
393 RouteParserToken::Exact(_) => alt((capture_single(field_naming_scheme), get_end))(i),
394 RouteParserToken::Capture(_) => alt((fragment_exact, get_end))(i),
395 _ => Err(nom::Err::Failure(ParseError {
396 reason: Some(ParserErrorReason::InvalidState),
397 expected: vec![],
398 offset: 0,
399 })),
400 },
401 ParserState::End => Err(nom::Err::Failure(ParseError {
402 reason: Some(ParserErrorReason::TokensAfterEndToken),
403 expected: vec![],
404 offset: 0,
405 })),
406 }
407}
408
409#[cfg(test)]
410mod test {
411 use super::parse as actual_parse;
413 use crate::{parser::RouteParserToken, FieldNamingScheme, PrettyParseError};
414
415 fn parse(i: &str) -> Result<Vec<RouteParserToken>, PrettyParseError> {
417 actual_parse(i, FieldNamingScheme::Unnamed)
418 }
419
420 mod does_parse {
421 use super::*;
422
423
424 #[test]
425 fn empty() {
426 let x = parse("").expect("Should parse");
427 assert_eq!(x, vec![RouteParserToken::Nothing])
428 }
429
430 #[test]
431 fn slash() {
432 parse("/").expect("should parse");
433 }
434
435 #[test]
436 fn slash_exact() {
437 parse("/hello").expect("should parse");
438 }
439
440 #[test]
441 fn multiple_exact() {
442 parse("/lorem/ipsum").expect("should parse");
443 }
444
445 #[test]
446 fn capture_in_path() {
447 parse("/lorem/{ipsum}").expect("should parse");
448 }
449
450 #[test]
451 fn capture_rest_in_path() {
452 parse("/lorem/{*:ipsum}").expect("should parse");
453 }
454
455 #[test]
456 fn capture_numbered_in_path() {
457 parse("/lorem/{5:ipsum}").expect("should parse");
458 }
459
460 #[test]
461 fn exact_query_after_path() {
462 parse("/lorem?ipsum=dolor").expect("should parse");
463 }
464
465 #[test]
466 fn leading_query_separator() {
467 parse("&lorem=ipsum").expect("Should parse");
468 }
469
470 #[test]
471 fn exact_query() {
472 parse("?lorem=ipsum").expect("should parse");
473 }
474
475 #[test]
476 fn capture_query() {
477 parse("?lorem={ipsum}").expect("should parse");
478 }
479
480 #[test]
481 fn multiple_queries() {
482 parse("?lorem=ipsum&dolor=sit").expect("should parse");
483 }
484
485 #[test]
486 fn query_and_exact_fragment() {
487 parse("?lorem=ipsum#dolor").expect("should parse");
488 }
489
490 #[test]
491 fn query_with_exact_and_capture_fragment() {
492 parse("?lorem=ipsum#dolor{sit}").expect("should parse");
493 }
494
495 #[test]
496 fn query_with_capture_fragment() {
497 parse("?lorem=ipsum#{dolor}").expect("should parse");
498 }
499
500 #[test]
501 fn escaped_backslash() {
502 let tokens = parse(r#"/escaped\\backslash"#).expect("should parse");
503 let expected = vec![
504 RouteParserToken::Separator,
505 RouteParserToken::Exact(r#"escaped\\backslash"#),
506 ];
507 assert_eq!(tokens, expected);
508 }
509
510 #[test]
511 fn escaped_exclamation() {
512 let tokens = parse(r#"/escaped!!exclamation"#).expect("should parse");
513 let expected = vec![
514 RouteParserToken::Separator,
515 RouteParserToken::Exact(r#"escaped"#),
516 RouteParserToken::Exact(r#"!"#),
517 RouteParserToken::Exact(r#"exclamation"#),
518 ];
519 assert_eq!(tokens, expected);
520 }
521
522 #[test]
523 fn escaped_open_bracket() {
524 let tokens = parse(r#"/escaped{{bracket"#).expect("should parse");
525 let expected = vec![
526 RouteParserToken::Separator,
527 RouteParserToken::Exact(r#"escaped"#),
528 RouteParserToken::Exact(r#"{"#),
529 RouteParserToken::Exact(r#"bracket"#),
530 ];
531 assert_eq!(tokens, expected);
532 }
533
534 #[test]
535 fn escaped_close_bracket() {
536 let tokens = parse(r#"/escaped}}bracket"#).expect("should parse");
537 let expected = vec![
538 RouteParserToken::Separator,
539 RouteParserToken::Exact(r#"escaped"#),
540 RouteParserToken::Exact(r#"}"#),
541 RouteParserToken::Exact(r#"bracket"#),
542 ];
543 assert_eq!(tokens, expected);
544 }
545 }
546
547 mod does_not_parse {
548 use super::*;
549 use crate::error::{ExpectedToken, ParserErrorReason};
550
551
552 #[test]
553 fn double_slash() {
554 let x = parse("//").expect_err("Should not parse");
555 assert_eq!(x.error.reason, Some(ParserErrorReason::DoubleSlash))
556 }
557
558 #[test]
559 fn slash_ampersand() {
560 let x = parse("/&lorem=ipsum").expect_err("Should not parse");
561 assert_eq!(x.error.reason, Some(ParserErrorReason::AndBeforeQuestion))
562 }
563
564 #[test]
565 fn non_ident_capture() {
566 let x = parse("/{lor#m}").expect_err("Should not parse");
567 assert_eq!(x.error.reason, Some(ParserErrorReason::BadRustIdent('#')));
568 assert_eq!(
569 x.error.expected,
570 vec![ExpectedToken::CloseBracket, ExpectedToken::Ident]
571 )
572 }
573
574
575 #[test]
576 fn after_end() {
577 let x = parse("/lorem/ipsum!/dolor").expect_err("Should not parse");
578 assert_eq!(x.error.reason, Some(ParserErrorReason::TokensAfterEndToken));
579 }
580 }
581
582 mod correct_parse {
583 use super::*;
584 use crate::parser::{CaptureOrExact, RefCaptureVariant};
585
586 #[test]
587 fn starting_literal() {
588 let parsed = parse("lorem").unwrap();
589 let expected = vec![RouteParserToken::Exact("lorem")];
590 assert_eq!(parsed, expected);
591 }
592
593 #[test]
594 fn minimal_path() {
595 let parsed = parse("/lorem").unwrap();
596 let expected = vec![
597 RouteParserToken::Separator,
598 RouteParserToken::Exact("lorem"),
599 ];
600 assert_eq!(parsed, expected);
601 }
602
603 #[test]
604 fn multiple_path() {
605 let parsed = parse("/lorem/ipsum/dolor/sit").unwrap();
606 let expected = vec![
607 RouteParserToken::Separator,
608 RouteParserToken::Exact("lorem"),
609 RouteParserToken::Separator,
610 RouteParserToken::Exact("ipsum"),
611 RouteParserToken::Separator,
612 RouteParserToken::Exact("dolor"),
613 RouteParserToken::Separator,
614 RouteParserToken::Exact("sit"),
615 ];
616 assert_eq!(parsed, expected);
617 }
618
619 #[test]
620 fn capture_path() {
621 let parsed = parse("/{lorem}/{ipsum}").unwrap();
622 let expected = vec![
623 RouteParserToken::Separator,
624 RouteParserToken::Capture(RefCaptureVariant::Named("lorem")),
625 RouteParserToken::Separator,
626 RouteParserToken::Capture(RefCaptureVariant::Named("ipsum")),
627 ];
628 assert_eq!(parsed, expected);
629 }
630
631 #[test]
632 fn query() {
633 let parsed = parse("?query=this").unwrap();
634 let expected = vec![
635 RouteParserToken::QueryBegin,
636 RouteParserToken::Query {
637 ident: "query",
638 capture_or_exact: CaptureOrExact::Exact("this"),
639 },
640 ];
641 assert_eq!(parsed, expected);
642 }
643
644 #[test]
645 fn query_2_part() {
646 let parsed = parse("?lorem=ipsum&dolor=sit").unwrap();
647 let expected = vec![
648 RouteParserToken::QueryBegin,
649 RouteParserToken::Query {
650 ident: "lorem",
651 capture_or_exact: CaptureOrExact::Exact("ipsum"),
652 },
653 RouteParserToken::QuerySeparator,
654 RouteParserToken::Query {
655 ident: "dolor",
656 capture_or_exact: CaptureOrExact::Exact("sit"),
657 },
658 ];
659 assert_eq!(parsed, expected);
660 }
661
662 #[test]
663 fn query_3_part() {
664 let parsed = parse("?lorem=ipsum&dolor=sit&amet=consectetur").unwrap();
665 let expected = vec![
666 RouteParserToken::QueryBegin,
667 RouteParserToken::Query {
668 ident: "lorem",
669 capture_or_exact: CaptureOrExact::Exact("ipsum"),
670 },
671 RouteParserToken::QuerySeparator,
672 RouteParserToken::Query {
673 ident: "dolor",
674 capture_or_exact: CaptureOrExact::Exact("sit"),
675 },
676 RouteParserToken::QuerySeparator,
677 RouteParserToken::Query {
678 ident: "amet",
679 capture_or_exact: CaptureOrExact::Exact("consectetur"),
680 },
681 ];
682 assert_eq!(parsed, expected);
683 }
684
685 #[test]
686 fn exact_fragment() {
687 let parsed = parse("#lorem").unwrap();
688 let expected = vec![
689 RouteParserToken::FragmentBegin,
690 RouteParserToken::Exact("lorem"),
691 ];
692 assert_eq!(parsed, expected);
693 }
694
695 #[test]
696 fn capture_fragment() {
697 let parsed = parse("#{lorem}").unwrap();
698 let expected = vec![
699 RouteParserToken::FragmentBegin,
700 RouteParserToken::Capture(RefCaptureVariant::Named("lorem")),
701 ];
702 assert_eq!(parsed, expected);
703 }
704
705 #[test]
706 fn mixed_fragment() {
707 let parsed = parse("#{lorem}ipsum{dolor}").unwrap();
708 let expected = vec![
709 RouteParserToken::FragmentBegin,
710 RouteParserToken::Capture(RefCaptureVariant::Named("lorem")),
711 RouteParserToken::Exact("ipsum"),
712 RouteParserToken::Capture(RefCaptureVariant::Named("dolor")),
713 ];
714 assert_eq!(parsed, expected);
715 }
716
717 #[test]
718 fn end_after_path() {
719 let parsed = parse("/lorem!").unwrap();
720 let expected = vec![
721 RouteParserToken::Separator,
722 RouteParserToken::Exact("lorem"),
723 RouteParserToken::End,
724 ];
725 assert_eq!(parsed, expected);
726 }
727
728 #[test]
729 fn end_after_path_separator() {
730 let parsed = parse("/lorem/!").unwrap();
731 let expected = vec![
732 RouteParserToken::Separator,
733 RouteParserToken::Exact("lorem"),
734 RouteParserToken::Separator,
735 RouteParserToken::End,
736 ];
737 assert_eq!(parsed, expected);
738 }
739
740 #[test]
741 fn end_after_path_capture() {
742 let parsed = parse("/lorem/{cap}!").unwrap();
743 let expected = vec![
744 RouteParserToken::Separator,
745 RouteParserToken::Exact("lorem"),
746 RouteParserToken::Separator,
747 RouteParserToken::Capture(RefCaptureVariant::Named("cap")),
748 RouteParserToken::End,
749 ];
750 assert_eq!(parsed, expected);
751 }
752
753 #[test]
754 fn end_after_query_capture() {
755 let parsed = parse("?lorem={cap}!").unwrap();
756 let expected = vec![
757 RouteParserToken::QueryBegin,
758 RouteParserToken::Query {
759 ident: "lorem",
760 capture_or_exact: CaptureOrExact::Capture(RefCaptureVariant::Named("cap")),
761 },
762 RouteParserToken::End,
763 ];
764 assert_eq!(parsed, expected);
765 }
766
767 #[test]
768 fn end_after_frag_capture() {
769 let parsed = parse("#{cap}!").unwrap();
770 let expected = vec![
771 RouteParserToken::FragmentBegin,
772 RouteParserToken::Capture(RefCaptureVariant::Named("cap")),
773 RouteParserToken::End,
774 ];
775 assert_eq!(parsed, expected);
776 }
777
778 #[test]
779 fn just_end() {
780 let parsed = parse("!").unwrap();
781 assert_eq!(parsed, vec![RouteParserToken::End]);
782 }
783 }
784}