1use super::error::Error;
23use super::error::SyntaxError;
24use super::lex::Keyword;
25use super::lex::Lexer;
26use super::lex::Token;
27use super::lex::TokenId::*;
28use crate::alias::Glossary;
29use crate::parser::lex::is_blank;
30use crate::syntax::HereDoc;
31use crate::syntax::MaybeLiteral;
32use std::rc::Rc;
33
34pub type Result<T> = std::result::Result<T, Error>;
36
37#[derive(Copy, Clone, Debug, Eq, PartialEq)]
56pub enum Rec<T> {
57 AliasSubstituted,
59 Parsed(T),
61}
62
63impl<T> Rec<T> {
64 pub fn is_alias_substituted(&self) -> bool {
66 match self {
67 Rec::AliasSubstituted => true,
68 Rec::Parsed(_) => false,
69 }
70 }
71
72 pub fn unwrap(self) -> T {
78 match self {
79 Rec::AliasSubstituted => panic!("Rec::AliasSubstituted cannot be unwrapped"),
80 Rec::Parsed(v) => v,
81 }
82 }
83
84 pub fn map<U, F>(self, f: F) -> Result<Rec<U>>
86 where
87 F: FnOnce(T) -> Result<U>,
88 {
89 match self {
90 Rec::AliasSubstituted => Ok(Rec::AliasSubstituted),
91 Rec::Parsed(t) => Ok(Rec::Parsed(f(t)?)),
92 }
93 }
94}
95
96#[derive(Debug)]
114pub struct Parser<'a, 'b> {
115 lexer: &'a mut Lexer<'b>,
117
118 glossary: &'a dyn Glossary,
120
121 token: Option<Result<Token>>,
126
127 unread_here_docs: Vec<Rc<HereDoc>>,
133}
134
135impl<'a, 'b> Parser<'a, 'b> {
136 pub fn new(lexer: &'a mut Lexer<'b>, glossary: &'a dyn Glossary) -> Parser<'a, 'b> {
140 Parser {
141 lexer,
142 glossary,
143 token: None,
144 unread_here_docs: vec![],
145 }
146 }
147
148 async fn require_token(&mut self) {
150 #[allow(clippy::question_mark)] if self.token.is_none() {
152 self.token = Some(if let Err(e) = self.lexer.skip_blanks_and_comment().await {
153 Err(e)
154 } else {
155 self.lexer.token().await
156 });
157 }
158 }
159
160 pub async fn peek_token(&mut self) -> Result<&Token> {
164 self.require_token().await;
165 self.token.as_ref().unwrap().as_ref().map_err(|e| e.clone())
166 }
167
168 pub async fn take_token_raw(&mut self) -> Result<Token> {
177 self.require_token().await;
178 self.token.take().unwrap()
179 }
180
181 fn substitute_alias(&mut self, token: Token, is_command_name: bool) -> Rec<Token> {
184 if !self.glossary.is_empty() {
186 if let Token(_) = token.id {
187 if let Some(name) = token.word.to_string_if_literal() {
188 if !token.word.location.code.source.is_alias_for(&name) {
189 if let Some(alias) = self.glossary.look_up(&name) {
190 if is_command_name
191 || alias.global
192 || self.lexer.is_after_blank_ending_alias(token.index)
193 {
194 self.lexer.substitute_alias(token.index, &alias);
195 return Rec::AliasSubstituted;
196 }
197 }
198 }
199 }
200 }
201 }
202
203 Rec::Parsed(token)
204 }
205
206 pub async fn take_token_manual(&mut self, is_command_name: bool) -> Result<Rec<Token>> {
231 let token = self.take_token_raw().await?;
232 Ok(self.substitute_alias(token, is_command_name))
233 }
234
235 pub async fn take_token_auto(&mut self, keywords: &[Keyword]) -> Result<Token> {
248 loop {
249 let token = self.take_token_raw().await?;
250 if let Token(Some(keyword)) = token.id {
251 if keywords.contains(&keyword) {
252 return Ok(token);
253 }
254 }
255 if let Rec::Parsed(token) = self.substitute_alias(token, false) {
256 return Ok(token);
257 }
258 }
259 }
260
261 pub async fn has_blank(&mut self) -> Result<bool> {
277 assert!(self.token.is_none(), "There should be no pending token");
278 let c = self.lexer.peek_char().await?;
279 Ok(c.map_or(false, is_blank))
280 }
281
282 pub fn memorize_unread_here_doc(&mut self, here_doc: Rc<HereDoc>) {
287 self.unread_here_docs.push(here_doc)
288 }
289
290 pub async fn here_doc_contents(&mut self) -> Result<()> {
304 assert!(
305 self.token.is_none(),
306 "No token must be peeked before reading here-doc contents"
307 );
308
309 for here_doc in self.unread_here_docs.drain(..) {
310 self.lexer.here_doc_content(&here_doc).await?;
311 }
312
313 Ok(())
314 }
315
316 pub fn ensure_no_unread_here_doc(&self) -> Result<()> {
320 match self.unread_here_docs.first() {
321 None => Ok(()),
322 Some(here_doc) => Err(Error {
323 cause: SyntaxError::MissingHereDocContent.into(),
324 location: here_doc.delimiter.location.clone(),
325 }),
326 }
327 }
328}
329
330#[allow(clippy::bool_assert_comparison)]
331#[cfg(test)]
332mod tests {
333 use super::*;
334 use crate::alias::AliasSet;
335 use crate::alias::HashEntry;
336 use crate::source::Location;
337 use crate::source::Source;
338 use assert_matches::assert_matches;
339 use futures_util::FutureExt;
340 use std::cell::OnceCell;
341
342 #[test]
343 fn parser_take_token_manual_successful_substitution() {
344 let mut lexer = Lexer::from_memory("X", Source::Unknown);
345 #[allow(clippy::mutable_key_type)]
346 let mut aliases = AliasSet::new();
347 aliases.insert(HashEntry::new(
348 "X".to_string(),
349 "x".to_string(),
350 false,
351 Location::dummy("?"),
352 ));
353 let mut parser = Parser::new(&mut lexer, &aliases);
354
355 let result = parser.take_token_manual(true).now_or_never().unwrap();
356 assert_matches!(result, Ok(Rec::AliasSubstituted));
357
358 let result = parser.take_token_manual(true).now_or_never().unwrap();
359 let token = result.unwrap().unwrap();
360 assert_eq!(token.to_string(), "x");
361 }
362
363 #[test]
364 fn parser_take_token_manual_not_command_name() {
365 let mut lexer = Lexer::from_memory("X", Source::Unknown);
366 #[allow(clippy::mutable_key_type)]
367 let mut aliases = AliasSet::new();
368 aliases.insert(HashEntry::new(
369 "X".to_string(),
370 "x".to_string(),
371 false,
372 Location::dummy("?"),
373 ));
374 let mut parser = Parser::new(&mut lexer, &aliases);
375
376 let result = parser.take_token_manual(false).now_or_never().unwrap();
377 let token = result.unwrap().unwrap();
378 assert_eq!(token.to_string(), "X");
379 }
380
381 #[test]
382 fn parser_take_token_manual_not_literal() {
383 let mut lexer = Lexer::from_memory(r"\X", Source::Unknown);
384 #[allow(clippy::mutable_key_type)]
385 let mut aliases = AliasSet::new();
386 aliases.insert(HashEntry::new(
387 "X".to_string(),
388 "x".to_string(),
389 false,
390 Location::dummy("?"),
391 ));
392 aliases.insert(HashEntry::new(
393 r"\X".to_string(),
394 "quoted".to_string(),
395 false,
396 Location::dummy("?"),
397 ));
398 let mut parser = Parser::new(&mut lexer, &aliases);
399
400 let result = parser.take_token_manual(true).now_or_never().unwrap();
401 let token = result.unwrap().unwrap();
402 assert_eq!(token.to_string(), r"\X");
403 }
404
405 #[test]
406 fn parser_take_token_manual_operator() {
407 let mut lexer = Lexer::from_memory(";", Source::Unknown);
408 #[allow(clippy::mutable_key_type)]
409 let mut aliases = AliasSet::new();
410 aliases.insert(HashEntry::new(
411 ";".to_string(),
412 "x".to_string(),
413 false,
414 Location::dummy("?"),
415 ));
416 let mut parser = Parser::new(&mut lexer, &aliases);
417
418 let result = parser.take_token_manual(true).now_or_never().unwrap();
419 let token = result.unwrap().unwrap();
420 assert_eq!(token.id, Operator(super::super::lex::Operator::Semicolon));
421 assert_eq!(token.word.to_string_if_literal().unwrap(), ";");
422 }
423
424 #[test]
425 fn parser_take_token_manual_no_match() {
426 let mut lexer = Lexer::from_memory("X", Source::Unknown);
427 #[allow(clippy::mutable_key_type)]
428 let aliases = AliasSet::new();
429 let mut parser = Parser::new(&mut lexer, &aliases);
430
431 let result = parser.take_token_manual(true).now_or_never().unwrap();
432 let token = result.unwrap().unwrap();
433 assert_eq!(token.to_string(), "X");
434 }
435
436 #[test]
437 fn parser_take_token_manual_recursive_substitution() {
438 let mut lexer = Lexer::from_memory("X", Source::Unknown);
439 #[allow(clippy::mutable_key_type)]
440 let mut aliases = AliasSet::new();
441 aliases.insert(HashEntry::new(
442 "X".to_string(),
443 "Y x".to_string(),
444 false,
445 Location::dummy("?"),
446 ));
447 aliases.insert(HashEntry::new(
448 "Y".to_string(),
449 "X y".to_string(),
450 false,
451 Location::dummy("?"),
452 ));
453 let mut parser = Parser::new(&mut lexer, &aliases);
454
455 let result = parser.take_token_manual(true).now_or_never().unwrap();
456 assert_matches!(result, Ok(Rec::AliasSubstituted));
457
458 let result = parser.take_token_manual(true).now_or_never().unwrap();
459 assert_matches!(result, Ok(Rec::AliasSubstituted));
460
461 let result = parser.take_token_manual(true).now_or_never().unwrap();
462 let token = result.unwrap().unwrap();
463 assert_eq!(token.to_string(), "X");
464
465 let result = parser.take_token_manual(true).now_or_never().unwrap();
466 let token = result.unwrap().unwrap();
467 assert_eq!(token.to_string(), "y");
468
469 let rec = parser.take_token_manual(true).now_or_never().unwrap();
470 let token = rec.unwrap().unwrap();
471 assert_eq!(token.to_string(), "x");
472 }
473
474 #[test]
475 fn parser_take_token_manual_after_blank_ending_substitution() {
476 let mut lexer = Lexer::from_memory("X\tY", Source::Unknown);
477 #[allow(clippy::mutable_key_type)]
478 let mut aliases = AliasSet::new();
479 aliases.insert(HashEntry::new(
480 "X".to_string(),
481 " X ".to_string(),
482 false,
483 Location::dummy("?"),
484 ));
485 aliases.insert(HashEntry::new(
486 "Y".to_string(),
487 "y".to_string(),
488 false,
489 Location::dummy("?"),
490 ));
491 let mut parser = Parser::new(&mut lexer, &aliases);
492
493 let result = parser.take_token_manual(true).now_or_never().unwrap();
494 assert_matches!(result, Ok(Rec::AliasSubstituted));
495
496 let result = parser.take_token_manual(true).now_or_never().unwrap();
497 let token = result.unwrap().unwrap();
498 assert_eq!(token.to_string(), "X");
499
500 let result = parser.take_token_manual(false).now_or_never().unwrap();
501 assert_matches!(result, Ok(Rec::AliasSubstituted));
502
503 let result = parser.take_token_manual(false).now_or_never().unwrap();
504 let token = result.unwrap().unwrap();
505 assert_eq!(token.to_string(), "y");
506 }
507
508 #[test]
509 fn parser_take_token_manual_not_after_blank_ending_substitution() {
510 let mut lexer = Lexer::from_memory("X\tY", Source::Unknown);
511 #[allow(clippy::mutable_key_type)]
512 let mut aliases = AliasSet::new();
513 aliases.insert(HashEntry::new(
514 "X".to_string(),
515 " X".to_string(),
516 false,
517 Location::dummy("?"),
518 ));
519 aliases.insert(HashEntry::new(
520 "Y".to_string(),
521 "y".to_string(),
522 false,
523 Location::dummy("?"),
524 ));
525 let mut parser = Parser::new(&mut lexer, &aliases);
526
527 let result = parser.take_token_manual(true).now_or_never().unwrap();
528 assert_matches!(result, Ok(Rec::AliasSubstituted));
529
530 let result = parser.take_token_manual(true).now_or_never().unwrap();
531 let token = result.unwrap().unwrap();
532 assert_eq!(token.to_string(), "X");
533
534 let result = parser.take_token_manual(false).now_or_never().unwrap();
535 let token = result.unwrap().unwrap();
536 assert_eq!(token.to_string(), "Y");
537 }
538
539 #[test]
540 fn parser_take_token_manual_global() {
541 let mut lexer = Lexer::from_memory("X", Source::Unknown);
542 #[allow(clippy::mutable_key_type)]
543 let mut aliases = AliasSet::new();
544 aliases.insert(HashEntry::new(
545 "X".to_string(),
546 "x".to_string(),
547 true,
548 Location::dummy("?"),
549 ));
550 let mut parser = Parser::new(&mut lexer, &aliases);
551
552 let result = parser.take_token_manual(false).now_or_never().unwrap();
553 assert_matches!(result, Ok(Rec::AliasSubstituted));
554
555 let result = parser.take_token_manual(false).now_or_never().unwrap();
556 let token = result.unwrap().unwrap();
557 assert_eq!(token.to_string(), "x");
558 }
559
560 #[test]
561 fn parser_take_token_auto_non_keyword() {
562 let mut lexer = Lexer::from_memory("X", Source::Unknown);
563 #[allow(clippy::mutable_key_type)]
564 let mut aliases = AliasSet::new();
565 aliases.insert(HashEntry::new(
566 "X".to_string(),
567 "x".to_string(),
568 true,
569 Location::dummy("?"),
570 ));
571 let mut parser = Parser::new(&mut lexer, &aliases);
572
573 let token = parser.take_token_auto(&[]).now_or_never().unwrap().unwrap();
574 assert_eq!(token.to_string(), "x");
575 }
576
577 #[test]
578 fn parser_take_token_auto_keyword_matched() {
579 let mut lexer = Lexer::from_memory("if", Source::Unknown);
580 #[allow(clippy::mutable_key_type)]
581 let mut aliases = AliasSet::new();
582 aliases.insert(HashEntry::new(
583 "if".to_string(),
584 "x".to_string(),
585 true,
586 Location::dummy("?"),
587 ));
588 let mut parser = Parser::new(&mut lexer, &aliases);
589
590 let token = parser
591 .take_token_auto(&[Keyword::If])
592 .now_or_never()
593 .unwrap()
594 .unwrap();
595 assert_eq!(token.to_string(), "if");
596 }
597
598 #[test]
599 fn parser_take_token_auto_keyword_unmatched() {
600 let mut lexer = Lexer::from_memory("if", Source::Unknown);
601 #[allow(clippy::mutable_key_type)]
602 let mut aliases = AliasSet::new();
603 aliases.insert(HashEntry::new(
604 "if".to_string(),
605 "x".to_string(),
606 true,
607 Location::dummy("?"),
608 ));
609 let mut parser = Parser::new(&mut lexer, &aliases);
610
611 let token = parser.take_token_auto(&[]).now_or_never().unwrap().unwrap();
612 assert_eq!(token.to_string(), "x");
613 }
614
615 #[test]
616 fn parser_take_token_auto_alias_substitution_to_keyword_matched() {
617 let mut lexer = Lexer::from_memory("X", Source::Unknown);
618 #[allow(clippy::mutable_key_type)]
619 let mut aliases = AliasSet::new();
620 aliases.insert(HashEntry::new(
621 "X".to_string(),
622 "if".to_string(),
623 true,
624 Location::dummy("?"),
625 ));
626 aliases.insert(HashEntry::new(
627 "if".to_string(),
628 "x".to_string(),
629 true,
630 Location::dummy("?"),
631 ));
632 let mut parser = Parser::new(&mut lexer, &aliases);
633
634 let token = parser
635 .take_token_auto(&[Keyword::If])
636 .now_or_never()
637 .unwrap()
638 .unwrap();
639 assert_eq!(token.to_string(), "if");
640 }
641
642 #[test]
643 fn parser_has_blank_true() {
644 let mut lexer = Lexer::from_memory(" ", Source::Unknown);
645 #[allow(clippy::mutable_key_type)]
646 let aliases = AliasSet::new();
647 let mut parser = Parser::new(&mut lexer, &aliases);
648 let result = parser.has_blank().now_or_never().unwrap();
649 assert_eq!(result, Ok(true));
650 }
651
652 #[test]
653 fn parser_has_blank_false() {
654 let mut lexer = Lexer::from_memory("(", Source::Unknown);
655 #[allow(clippy::mutable_key_type)]
656 let aliases = AliasSet::new();
657 let mut parser = Parser::new(&mut lexer, &aliases);
658 let result = parser.has_blank().now_or_never().unwrap();
659 assert_eq!(result, Ok(false));
660 }
661
662 #[test]
663 fn parser_has_blank_eof() {
664 let mut lexer = Lexer::from_memory("", Source::Unknown);
665 #[allow(clippy::mutable_key_type)]
666 let aliases = AliasSet::new();
667 let mut parser = Parser::new(&mut lexer, &aliases);
668 let result = parser.has_blank().now_or_never().unwrap();
669 assert_eq!(result, Ok(false));
670 }
671
672 #[test]
673 fn parser_has_blank_true_with_line_continuations() {
674 let mut lexer = Lexer::from_memory("\\\n\\\n ", Source::Unknown);
675 #[allow(clippy::mutable_key_type)]
676 let aliases = AliasSet::new();
677 let mut parser = Parser::new(&mut lexer, &aliases);
678 let result = parser.has_blank().now_or_never().unwrap();
679 assert_eq!(result, Ok(true));
680 }
681
682 #[test]
683 fn parser_has_blank_false_with_line_continuations() {
684 let mut lexer = Lexer::from_memory("\\\n\\\n\\\n(", Source::Unknown);
685 #[allow(clippy::mutable_key_type)]
686 let aliases = AliasSet::new();
687 let mut parser = Parser::new(&mut lexer, &aliases);
688 let result = parser.has_blank().now_or_never().unwrap();
689 assert_eq!(result, Ok(false));
690 }
691
692 #[test]
693 #[should_panic(expected = "There should be no pending token")]
694 fn parser_has_blank_with_pending_token() {
695 let mut lexer = Lexer::from_memory("foo", Source::Unknown);
696 #[allow(clippy::mutable_key_type)]
697 let aliases = AliasSet::new();
698 let mut parser = Parser::new(&mut lexer, &aliases);
699 parser.peek_token().now_or_never().unwrap().unwrap();
700 let _ = parser.has_blank().now_or_never().unwrap();
701 }
702
703 #[test]
704 fn parser_reading_no_here_doc_contents() {
705 let mut lexer = Lexer::from_memory("X", Source::Unknown);
706 #[allow(clippy::mutable_key_type)]
707 let aliases = AliasSet::new();
708 let mut parser = Parser::new(&mut lexer, &aliases);
709 parser.here_doc_contents().now_or_never().unwrap().unwrap();
710
711 let location = lexer.location().now_or_never().unwrap().unwrap();
712 assert_eq!(location.code.start_line_number.get(), 1);
713 assert_eq!(location.range, 0..1);
714 }
715
716 #[test]
717 fn parser_reading_one_here_doc_content() {
718 let delimiter = "END".parse().unwrap();
719
720 let mut lexer = Lexer::from_memory("END\nX", Source::Unknown);
721 #[allow(clippy::mutable_key_type)]
722 let aliases = AliasSet::new();
723 let mut parser = Parser::new(&mut lexer, &aliases);
724 let remove_tabs = false;
725 let here_doc = Rc::new(HereDoc {
726 delimiter,
727 remove_tabs,
728 content: OnceCell::new(),
729 });
730 parser.memorize_unread_here_doc(Rc::clone(&here_doc));
731 parser.here_doc_contents().now_or_never().unwrap().unwrap();
732 assert_eq!(here_doc.delimiter.to_string(), "END");
733 assert_eq!(here_doc.remove_tabs, remove_tabs);
734 assert_eq!(here_doc.content.get().unwrap().0, []);
735
736 let location = lexer.location().now_or_never().unwrap().unwrap();
737 assert_eq!(location.code.start_line_number.get(), 1);
738 assert_eq!(location.range, 4..5);
739 }
740
741 #[test]
742 fn parser_reading_many_here_doc_contents() {
743 let delimiter1 = "ONE".parse().unwrap();
744 let delimiter2 = "TWO".parse().unwrap();
745 let delimiter3 = "THREE".parse().unwrap();
746
747 let mut lexer = Lexer::from_memory("1\nONE\nTWO\n3\nTHREE\nX", Source::Unknown);
748 #[allow(clippy::mutable_key_type)]
749 let aliases = AliasSet::new();
750 let mut parser = Parser::new(&mut lexer, &aliases);
751 let here_doc1 = Rc::new(HereDoc {
752 delimiter: delimiter1,
753 remove_tabs: false,
754 content: OnceCell::new(),
755 });
756 parser.memorize_unread_here_doc(Rc::clone(&here_doc1));
757 let here_doc2 = Rc::new(HereDoc {
758 delimiter: delimiter2,
759 remove_tabs: true,
760 content: OnceCell::new(),
761 });
762 parser.memorize_unread_here_doc(Rc::clone(&here_doc2));
763 let here_doc3 = Rc::new(HereDoc {
764 delimiter: delimiter3,
765 remove_tabs: false,
766 content: OnceCell::new(),
767 });
768 parser.memorize_unread_here_doc(Rc::clone(&here_doc3));
769 parser.here_doc_contents().now_or_never().unwrap().unwrap();
770 assert_eq!(here_doc1.delimiter.to_string(), "ONE");
771 assert_eq!(here_doc1.remove_tabs, false);
772 assert_eq!(here_doc1.content.get().unwrap().to_string(), "1\n");
773 assert_eq!(here_doc2.delimiter.to_string(), "TWO");
774 assert_eq!(here_doc2.remove_tabs, true);
775 assert_eq!(here_doc2.content.get().unwrap().to_string(), "");
776 assert_eq!(here_doc3.delimiter.to_string(), "THREE");
777 assert_eq!(here_doc3.remove_tabs, false);
778 assert_eq!(here_doc3.content.get().unwrap().to_string(), "3\n");
779 }
780
781 #[test]
782 fn parser_reading_here_doc_contents_twice() {
783 let delimiter1 = "ONE".parse().unwrap();
784 let delimiter2 = "TWO".parse().unwrap();
785
786 let mut lexer = Lexer::from_memory("1\nONE\n2\nTWO\n", Source::Unknown);
787 #[allow(clippy::mutable_key_type)]
788 let aliases = AliasSet::new();
789 let mut parser = Parser::new(&mut lexer, &aliases);
790 let here_doc1 = Rc::new(HereDoc {
791 delimiter: delimiter1,
792 remove_tabs: false,
793 content: OnceCell::new(),
794 });
795 parser.memorize_unread_here_doc(Rc::clone(&here_doc1));
796 parser.here_doc_contents().now_or_never().unwrap().unwrap();
797 let here_doc2 = Rc::new(HereDoc {
798 delimiter: delimiter2,
799 remove_tabs: true,
800 content: OnceCell::new(),
801 });
802 parser.memorize_unread_here_doc(Rc::clone(&here_doc2));
803 parser.here_doc_contents().now_or_never().unwrap().unwrap();
804 assert_eq!(here_doc1.delimiter.to_string(), "ONE");
805 assert_eq!(here_doc1.remove_tabs, false);
806 assert_eq!(here_doc1.content.get().unwrap().to_string(), "1\n");
807 assert_eq!(here_doc2.delimiter.to_string(), "TWO");
808 assert_eq!(here_doc2.remove_tabs, true);
809 assert_eq!(here_doc2.content.get().unwrap().to_string(), "2\n");
810 }
811
812 #[test]
813 #[should_panic(expected = "No token must be peeked before reading here-doc contents")]
814 fn parser_here_doc_contents_must_be_called_without_pending_token() {
815 let mut lexer = Lexer::from_memory("X", Source::Unknown);
816 #[allow(clippy::mutable_key_type)]
817 let aliases = AliasSet::new();
818 let mut parser = Parser::new(&mut lexer, &aliases);
819 parser.peek_token().now_or_never().unwrap().unwrap();
820 parser.here_doc_contents().now_or_never().unwrap().unwrap();
821 }
822}