1use crate::{
3 core::{
4 capture, exact, fragment_exact, get_and, get_end, get_hash, get_question, get_slash,
5 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).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(field_naming_scheme), get_end))(i)
392 }
393 RouteParserToken::Exact(_) => alt((capture(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 #[test]
424 fn empty() {
425 let x = parse("").expect("Should parse");
426 assert_eq!(x, vec![RouteParserToken::Nothing])
427 }
428
429 #[test]
430 fn slash() {
431 parse("/").expect("should parse");
432 }
433
434 #[test]
435 fn slash_exact() {
436 parse("/hello").expect("should parse");
437 }
438
439 #[test]
440 fn multiple_exact() {
441 parse("/lorem/ipsum").expect("should parse");
442 }
443
444 #[test]
445 fn capture_in_path() {
446 parse("/lorem/{ipsum}").expect("should parse");
447 }
448
449 #[test]
450 fn capture_rest_in_path() {
451 parse("/lorem/{*:ipsum}").expect("should parse");
452 }
453
454 #[test]
455 fn capture_numbered_in_path() {
456 parse("/lorem/{5:ipsum}").expect("should parse");
457 }
458
459 #[test]
460 fn exact_query_after_path() {
461 parse("/lorem?ipsum=dolor").expect("should parse");
462 }
463
464 #[test]
465 fn leading_query_separator() {
466 parse("&lorem=ipsum").expect("Should parse");
467 }
468
469 #[test]
470 fn exact_query() {
471 parse("?lorem=ipsum").expect("should parse");
472 }
473
474 #[test]
475 fn capture_query() {
476 parse("?lorem={ipsum}").expect("should parse");
477 }
478
479 #[test]
480 fn multiple_queries() {
481 parse("?lorem=ipsum&dolor=sit").expect("should parse");
482 }
483
484 #[test]
485 fn query_and_exact_fragment() {
486 parse("?lorem=ipsum#dolor").expect("should parse");
487 }
488
489 #[test]
490 fn query_with_exact_and_capture_fragment() {
491 parse("?lorem=ipsum#dolor{sit}").expect("should parse");
492 }
493
494 #[test]
495 fn query_with_capture_fragment() {
496 parse("?lorem=ipsum#{dolor}").expect("should parse");
497 }
498
499 #[test]
500 fn escaped_backslash() {
501 let tokens = parse(r#"/escaped\\backslash"#).expect("should parse");
502 let expected = vec![
503 RouteParserToken::Separator,
504 RouteParserToken::Exact(r#"escaped\\backslash"#),
505 ];
506 assert_eq!(tokens, expected);
507 }
508
509 #[test]
510 fn escaped_exclamation() {
511 let tokens = parse(r#"/escaped!!exclamation"#).expect("should parse");
512 let expected = vec![
513 RouteParserToken::Separator,
514 RouteParserToken::Exact(r#"escaped"#),
515 RouteParserToken::Exact(r#"!"#),
516 RouteParserToken::Exact(r#"exclamation"#),
517 ];
518 assert_eq!(tokens, expected);
519 }
520
521 #[test]
522 fn escaped_open_bracket() {
523 let tokens = parse(r#"/escaped{{bracket"#).expect("should parse");
524 let expected = vec![
525 RouteParserToken::Separator,
526 RouteParserToken::Exact(r#"escaped"#),
527 RouteParserToken::Exact(r#"{"#),
528 RouteParserToken::Exact(r#"bracket"#),
529 ];
530 assert_eq!(tokens, expected);
531 }
532
533 #[test]
534 fn escaped_close_bracket() {
535 let tokens = parse(r#"/escaped}}bracket"#).expect("should parse");
536 let expected = vec![
537 RouteParserToken::Separator,
538 RouteParserToken::Exact(r#"escaped"#),
539 RouteParserToken::Exact(r#"}"#),
540 RouteParserToken::Exact(r#"bracket"#),
541 ];
542 assert_eq!(tokens, expected);
543 }
544 }
545
546 mod does_not_parse {
547 use super::*;
548 use crate::error::{ExpectedToken, ParserErrorReason};
549
550 #[test]
551 fn double_slash() {
552 let x = parse("//").expect_err("Should not parse");
553 assert_eq!(x.error.reason, Some(ParserErrorReason::DoubleSlash))
554 }
555
556 #[test]
557 fn slash_ampersand() {
558 let x = parse("/&lorem=ipsum").expect_err("Should not parse");
559 assert_eq!(x.error.reason, Some(ParserErrorReason::AndBeforeQuestion))
560 }
561
562 #[test]
563 fn non_ident_capture() {
564 let x = parse("/{lor#m}").expect_err("Should not parse");
565 assert_eq!(x.error.reason, Some(ParserErrorReason::BadRustIdent('#')));
566 assert_eq!(
567 x.error.expected,
568 vec![ExpectedToken::CloseBracket, ExpectedToken::Ident]
569 )
570 }
571
572 #[test]
573 fn after_end() {
574 let x = parse("/lorem/ipsum!/dolor").expect_err("Should not parse");
575 assert_eq!(x.error.reason, Some(ParserErrorReason::TokensAfterEndToken));
576 }
577 }
578
579 mod correct_parse {
580 use super::*;
581 use crate::parser::{CaptureOrExact, RefCaptureVariant};
582
583 #[test]
584 fn starting_literal() {
585 let parsed = parse("lorem").unwrap();
586 let expected = vec![RouteParserToken::Exact("lorem")];
587 assert_eq!(parsed, expected);
588 }
589
590 #[test]
591 fn minimal_path() {
592 let parsed = parse("/lorem").unwrap();
593 let expected = vec![
594 RouteParserToken::Separator,
595 RouteParserToken::Exact("lorem"),
596 ];
597 assert_eq!(parsed, expected);
598 }
599
600 #[test]
601 fn multiple_path() {
602 let parsed = parse("/lorem/ipsum/dolor/sit").unwrap();
603 let expected = vec![
604 RouteParserToken::Separator,
605 RouteParserToken::Exact("lorem"),
606 RouteParserToken::Separator,
607 RouteParserToken::Exact("ipsum"),
608 RouteParserToken::Separator,
609 RouteParserToken::Exact("dolor"),
610 RouteParserToken::Separator,
611 RouteParserToken::Exact("sit"),
612 ];
613 assert_eq!(parsed, expected);
614 }
615
616 #[test]
617 fn capture_path() {
618 let parsed = parse("/{lorem}/{ipsum}").unwrap();
619 let expected = vec![
620 RouteParserToken::Separator,
621 RouteParserToken::Capture(RefCaptureVariant::Named("lorem")),
622 RouteParserToken::Separator,
623 RouteParserToken::Capture(RefCaptureVariant::Named("ipsum")),
624 ];
625 assert_eq!(parsed, expected);
626 }
627
628 #[test]
629 fn query() {
630 let parsed = parse("?query=this").unwrap();
631 let expected = vec![
632 RouteParserToken::QueryBegin,
633 RouteParserToken::Query {
634 ident: "query",
635 capture_or_exact: CaptureOrExact::Exact("this"),
636 },
637 ];
638 assert_eq!(parsed, expected);
639 }
640
641 #[test]
642 fn query_2_part() {
643 let parsed = parse("?lorem=ipsum&dolor=sit").unwrap();
644 let expected = vec![
645 RouteParserToken::QueryBegin,
646 RouteParserToken::Query {
647 ident: "lorem",
648 capture_or_exact: CaptureOrExact::Exact("ipsum"),
649 },
650 RouteParserToken::QuerySeparator,
651 RouteParserToken::Query {
652 ident: "dolor",
653 capture_or_exact: CaptureOrExact::Exact("sit"),
654 },
655 ];
656 assert_eq!(parsed, expected);
657 }
658
659 #[test]
660 fn query_3_part() {
661 let parsed = parse("?lorem=ipsum&dolor=sit&amet=consectetur").unwrap();
662 let expected = vec![
663 RouteParserToken::QueryBegin,
664 RouteParserToken::Query {
665 ident: "lorem",
666 capture_or_exact: CaptureOrExact::Exact("ipsum"),
667 },
668 RouteParserToken::QuerySeparator,
669 RouteParserToken::Query {
670 ident: "dolor",
671 capture_or_exact: CaptureOrExact::Exact("sit"),
672 },
673 RouteParserToken::QuerySeparator,
674 RouteParserToken::Query {
675 ident: "amet",
676 capture_or_exact: CaptureOrExact::Exact("consectetur"),
677 },
678 ];
679 assert_eq!(parsed, expected);
680 }
681
682 #[test]
683 fn exact_fragment() {
684 let parsed = parse("#lorem").unwrap();
685 let expected = vec![
686 RouteParserToken::FragmentBegin,
687 RouteParserToken::Exact("lorem"),
688 ];
689 assert_eq!(parsed, expected);
690 }
691
692 #[test]
693 fn capture_fragment() {
694 let parsed = parse("#{lorem}").unwrap();
695 let expected = vec![
696 RouteParserToken::FragmentBegin,
697 RouteParserToken::Capture(RefCaptureVariant::Named("lorem")),
698 ];
699 assert_eq!(parsed, expected);
700 }
701
702 #[test]
703 fn mixed_fragment() {
704 let parsed = parse("#{lorem}ipsum{dolor}").unwrap();
705 let expected = vec![
706 RouteParserToken::FragmentBegin,
707 RouteParserToken::Capture(RefCaptureVariant::Named("lorem")),
708 RouteParserToken::Exact("ipsum"),
709 RouteParserToken::Capture(RefCaptureVariant::Named("dolor")),
710 ];
711 assert_eq!(parsed, expected);
712 }
713
714 #[test]
715 fn end_after_path() {
716 let parsed = parse("/lorem!").unwrap();
717 let expected = vec![
718 RouteParserToken::Separator,
719 RouteParserToken::Exact("lorem"),
720 RouteParserToken::End,
721 ];
722 assert_eq!(parsed, expected);
723 }
724
725 #[test]
726 fn end_after_path_separator() {
727 let parsed = parse("/lorem/!").unwrap();
728 let expected = vec![
729 RouteParserToken::Separator,
730 RouteParserToken::Exact("lorem"),
731 RouteParserToken::Separator,
732 RouteParserToken::End,
733 ];
734 assert_eq!(parsed, expected);
735 }
736
737 #[test]
738 fn end_after_path_capture() {
739 let parsed = parse("/lorem/{cap}!").unwrap();
740 let expected = vec![
741 RouteParserToken::Separator,
742 RouteParserToken::Exact("lorem"),
743 RouteParserToken::Separator,
744 RouteParserToken::Capture(RefCaptureVariant::Named("cap")),
745 RouteParserToken::End,
746 ];
747 assert_eq!(parsed, expected);
748 }
749
750 #[test]
751 fn end_after_query_capture() {
752 let parsed = parse("?lorem={cap}!").unwrap();
753 let expected = vec![
754 RouteParserToken::QueryBegin,
755 RouteParserToken::Query {
756 ident: "lorem",
757 capture_or_exact: CaptureOrExact::Capture(RefCaptureVariant::Named("cap")),
758 },
759 RouteParserToken::End,
760 ];
761 assert_eq!(parsed, expected);
762 }
763
764 #[test]
765 fn end_after_frag_capture() {
766 let parsed = parse("#{cap}!").unwrap();
767 let expected = vec![
768 RouteParserToken::FragmentBegin,
769 RouteParserToken::Capture(RefCaptureVariant::Named("cap")),
770 RouteParserToken::End,
771 ];
772 assert_eq!(parsed, expected);
773 }
774
775 #[test]
776 fn just_end() {
777 let parsed = parse("!").unwrap();
778 assert_eq!(parsed, vec![RouteParserToken::End]);
779 }
780 }
781}