yash_syntax/parser/
and_or.rs1use super::core::Parser;
20use super::core::Rec;
21use super::core::Result;
22use super::error::Error;
23use super::error::SyntaxError;
24use super::lex::Operator::{AndAnd, BarBar};
25use super::lex::TokenId::Operator;
26use crate::syntax::AndOr;
27use crate::syntax::AndOrList;
28
29impl Parser<'_, '_> {
30 pub async fn and_or_list(&mut self) -> Result<Rec<Option<AndOrList>>> {
35 let first = match self.pipeline().await? {
36 Rec::AliasSubstituted => return Ok(Rec::AliasSubstituted),
37 Rec::Parsed(None) => return Ok(Rec::Parsed(None)),
38 Rec::Parsed(Some(p)) => p,
39 };
40
41 let mut rest = vec![];
42 loop {
43 let condition = match self.peek_token().await?.id {
44 Operator(AndAnd) => AndOr::AndThen,
45 Operator(BarBar) => AndOr::OrElse,
46 _ => break,
47 };
48 self.take_token_raw().await?;
49
50 while self.newline_and_here_doc_contents().await? {}
51
52 let maybe_pipeline = loop {
53 if let Rec::Parsed(maybe_pipeline) = self.pipeline().await? {
54 break maybe_pipeline;
55 }
56 };
57 let pipeline = match maybe_pipeline {
58 None => {
59 let cause = SyntaxError::MissingPipeline(condition).into();
60 let location = self.peek_token().await?.word.location.clone();
61 return Err(Error { cause, location });
62 }
63 Some(pipeline) => pipeline,
64 };
65
66 rest.push((condition, pipeline));
67 }
68
69 Ok(Rec::Parsed(Some(AndOrList { first, rest })))
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::super::error::ErrorCause;
76 use super::super::lex::Lexer;
77 use super::*;
78 use crate::source::Source;
79 use futures_util::FutureExt;
80
81 #[test]
82 fn parser_and_or_list_eof() {
83 let mut lexer = Lexer::with_code("");
84 let mut parser = Parser::new(&mut lexer);
85
86 let result = parser.and_or_list().now_or_never().unwrap();
87 assert_eq!(result, Ok(Rec::Parsed(None)));
88 }
89
90 #[test]
91 fn parser_and_or_list_one() {
92 let mut lexer = Lexer::with_code("foo");
93 let mut parser = Parser::new(&mut lexer);
94
95 let result = parser.and_or_list().now_or_never().unwrap();
96 let aol = result.unwrap().unwrap().unwrap();
97 assert_eq!(aol.first.to_string(), "foo");
98 assert_eq!(aol.rest, vec![]);
99 }
100
101 #[test]
102 fn parser_and_or_list_many() {
103 let mut lexer = Lexer::with_code("first && second || \n\n third;");
104 let mut parser = Parser::new(&mut lexer);
105
106 let result = parser.and_or_list().now_or_never().unwrap();
107 let aol = result.unwrap().unwrap().unwrap();
108 assert_eq!(aol.first.to_string(), "first");
109 assert_eq!(aol.rest.len(), 2);
110 assert_eq!(aol.rest[0].0, AndOr::AndThen);
111 assert_eq!(aol.rest[0].1.to_string(), "second");
112 assert_eq!(aol.rest[1].0, AndOr::OrElse);
113 assert_eq!(aol.rest[1].1.to_string(), "third");
114 }
115
116 #[test]
117 fn parser_and_or_list_missing_command_after_and_and() {
118 let mut lexer = Lexer::with_code("foo &&");
119 let mut parser = Parser::new(&mut lexer);
120
121 let e = parser.and_or_list().now_or_never().unwrap().unwrap_err();
122 assert_eq!(
123 e.cause,
124 ErrorCause::Syntax(SyntaxError::MissingPipeline(AndOr::AndThen))
125 );
126 assert_eq!(*e.location.code.value.borrow(), "foo &&");
127 assert_eq!(e.location.code.start_line_number.get(), 1);
128 assert_eq!(*e.location.code.source, Source::Unknown);
129 assert_eq!(e.location.range, 6..6);
130 }
131}