1use super::core::Parser;
20use super::core::Result;
21use super::error::Error;
22use super::error::SyntaxError;
23use super::lex::Keyword::{Elif, Else, Fi, If, Then};
24use super::lex::TokenId::Token;
25use crate::syntax::CompoundCommand;
26use crate::syntax::ElifThen;
27
28impl Parser<'_, '_> {
29 async fn elif_then_clause(&mut self) -> Result<Option<ElifThen>> {
33 if self.peek_token().await?.id != Token(Some(Elif)) {
34 return Ok(None);
35 }
36
37 let elif = self.take_token_raw().await?;
38
39 let condition = self.maybe_compound_list_boxed().await?;
40 let then = self.take_token_raw().await?;
41
42 if condition.0.is_empty() {
44 let cause = SyntaxError::EmptyElifCondition.into();
45 let location = then.word.location;
46 return Err(Error { cause, location });
47 }
48 if then.id != Token(Some(Then)) {
49 let elif_location = elif.word.location;
50 let cause = SyntaxError::ElifMissingThen { elif_location }.into();
51 let location = then.word.location;
52 return Err(Error { cause, location });
53 }
54
55 let body = self.maybe_compound_list_boxed().await?;
56 if body.0.is_empty() {
58 let cause = SyntaxError::EmptyElifBody.into();
59 let location = self.take_token_raw().await?.word.location;
60 return Err(Error { cause, location });
61 }
62
63 Ok(Some(ElifThen { condition, body }))
64 }
65
66 pub async fn if_command(&mut self) -> Result<CompoundCommand> {
74 let open = self.take_token_raw().await?;
75 assert_eq!(open.id, Token(Some(If)));
76
77 let condition = self.maybe_compound_list_boxed().await?;
78 let then = self.take_token_raw().await?;
79
80 if condition.0.is_empty() {
82 let cause = SyntaxError::EmptyIfCondition.into();
83 let location = then.word.location;
84 return Err(Error { cause, location });
85 }
86 if then.id != Token(Some(Then)) {
87 let if_location = open.word.location;
88 let cause = SyntaxError::IfMissingThen { if_location }.into();
89 let location = then.word.location;
90 return Err(Error { cause, location });
91 }
92
93 let body = self.maybe_compound_list_boxed().await?;
94 if body.0.is_empty() {
96 let cause = SyntaxError::EmptyIfBody.into();
97 let location = self.take_token_raw().await?.word.location;
98 return Err(Error { cause, location });
99 }
100
101 let mut elifs = Vec::new();
102 while let Some(elif) = self.elif_then_clause().await? {
103 elifs.push(elif);
104 }
105
106 let r#else = if self.peek_token().await?.id == Token(Some(Else)) {
107 self.take_token_raw().await?;
108 let content = self.maybe_compound_list_boxed().await?;
109 if content.0.is_empty() {
111 let cause = SyntaxError::EmptyElse.into();
112 let location = self.take_token_raw().await?.word.location;
113 return Err(Error { cause, location });
114 }
115 Some(content)
116 } else {
117 None
118 };
119
120 let fi = self.take_token_raw().await?;
121 if fi.id != Token(Some(Fi)) {
122 let opening_location = open.word.location;
123 let cause = SyntaxError::UnclosedIf { opening_location }.into();
124 let location = fi.word.location;
125 return Err(Error { cause, location });
126 }
127
128 Ok(CompoundCommand::If {
129 condition,
130 body,
131 elifs,
132 r#else,
133 })
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::super::error::ErrorCause;
140 use super::super::lex::Lexer;
141 use super::super::lex::TokenId::EndOfInput;
142 use super::*;
143 use crate::alias::EmptyGlossary;
144 use crate::source::Source;
145 use assert_matches::assert_matches;
146 use futures_util::FutureExt;
147
148 #[test]
149 fn parser_if_command_minimum() {
150 let mut lexer = Lexer::from_memory("if a; then b; fi", Source::Unknown);
151 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
152
153 let result = parser.compound_command().now_or_never().unwrap();
154 let compound_command = result.unwrap().unwrap();
155 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
156 assert_eq!(condition.to_string(), "a");
157 assert_eq!(body.to_string(), "b");
158 assert_eq!(elifs, []);
159 assert_eq!(r#else, None);
160 });
161
162 let next = parser.peek_token().now_or_never().unwrap().unwrap();
163 assert_eq!(next.id, EndOfInput);
164 }
165
166 #[test]
167 fn parser_if_command_one_elif() {
168 let mut lexer = Lexer::from_memory(
169 "if\ntrue\nthen\nfalse\n\nelif x; then y& fi",
170 Source::Unknown,
171 );
172 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
173
174 let result = parser.compound_command().now_or_never().unwrap();
175 let compound_command = result.unwrap().unwrap();
176 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
177 assert_eq!(condition.to_string(), "true");
178 assert_eq!(body.to_string(), "false");
179 assert_eq!(elifs.len(), 1);
180 assert_eq!(elifs[0].to_string(), "elif x; then y&");
181 assert_eq!(r#else, None);
182 });
183
184 let next = parser.peek_token().now_or_never().unwrap().unwrap();
185 assert_eq!(next.id, EndOfInput);
186 }
187
188 #[test]
189 fn parser_if_command_many_elifs() {
190 let mut lexer = Lexer::from_memory(
191 "if a; then b; elif c; then d; elif e 1; e 2& then f 1; f 2& elif g; then h; fi",
192 Source::Unknown,
193 );
194 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
195
196 let result = parser.compound_command().now_or_never().unwrap();
197 let compound_command = result.unwrap().unwrap();
198 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
199 assert_eq!(condition.to_string(), "a");
200 assert_eq!(body.to_string(), "b");
201 assert_eq!(elifs.len(), 3);
202 assert_eq!(elifs[0].to_string(), "elif c; then d");
203 assert_eq!(elifs[1].to_string(), "elif e 1; e 2& then f 1; f 2&");
204 assert_eq!(elifs[2].to_string(), "elif g; then h");
205 assert_eq!(r#else, None);
206 });
207
208 let next = parser.peek_token().now_or_never().unwrap().unwrap();
209 assert_eq!(next.id, EndOfInput);
210 }
211
212 #[test]
213 fn parser_if_command_else() {
214 let mut lexer = Lexer::from_memory("if a; then b; else c; d; fi", Source::Unknown);
215 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
216
217 let result = parser.compound_command().now_or_never().unwrap();
218 let compound_command = result.unwrap().unwrap();
219 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
220 assert_eq!(condition.to_string(), "a");
221 assert_eq!(body.to_string(), "b");
222 assert_eq!(elifs, []);
223 assert_eq!(r#else.unwrap().to_string(), "c; d");
224 });
225
226 let next = parser.peek_token().now_or_never().unwrap().unwrap();
227 assert_eq!(next.id, EndOfInput);
228 }
229
230 #[test]
231 fn parser_if_command_elif_and_else() {
232 let mut lexer =
233 Lexer::from_memory("if 1; then 2; elif 3; then 4; else 5; fi", Source::Unknown);
234 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
235
236 let result = parser.compound_command().now_or_never().unwrap();
237 let compound_command = result.unwrap().unwrap();
238 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
239 assert_eq!(condition.to_string(), "1");
240 assert_eq!(body.to_string(), "2");
241 assert_eq!(elifs.len(), 1);
242 assert_eq!(elifs[0].to_string(), "elif 3; then 4");
243 assert_eq!(r#else.unwrap().to_string(), "5");
244 });
245
246 let next = parser.peek_token().now_or_never().unwrap().unwrap();
247 assert_eq!(next.id, EndOfInput);
248 }
249
250 #[test]
251 fn parser_if_command_without_then_after_if() {
252 let mut lexer = Lexer::from_memory(" if :; fi", Source::Unknown);
253 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
254
255 let result = parser.compound_command().now_or_never().unwrap();
256 let e = result.unwrap_err();
257 assert_matches!(e.cause, ErrorCause::Syntax(SyntaxError::IfMissingThen { if_location }) => {
258 assert_eq!(*if_location.code.value.borrow(), " if :; fi");
259 assert_eq!(if_location.code.start_line_number.get(), 1);
260 assert_eq!(*if_location.code.source, Source::Unknown);
261 assert_eq!(if_location.range, 1..3);
262 });
263 assert_eq!(*e.location.code.value.borrow(), " if :; fi");
264 assert_eq!(e.location.code.start_line_number.get(), 1);
265 assert_eq!(*e.location.code.source, Source::Unknown);
266 assert_eq!(e.location.range, 7..9);
267 }
268
269 #[test]
270 fn parser_if_command_without_then_after_elif() {
271 let mut lexer = Lexer::from_memory("if a; then b; elif c; fi", Source::Unknown);
272 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
273
274 let result = parser.compound_command().now_or_never().unwrap();
275 let e = result.unwrap_err();
276 assert_matches!(e.cause,
277 ErrorCause::Syntax(SyntaxError::ElifMissingThen { elif_location }) => {
278 assert_eq!(*elif_location.code.value.borrow(), "if a; then b; elif c; fi");
279 assert_eq!(elif_location.code.start_line_number.get(), 1);
280 assert_eq!(*elif_location.code.source, Source::Unknown);
281 assert_eq!(elif_location.range, 14..18);
282 });
283 assert_eq!(*e.location.code.value.borrow(), "if a; then b; elif c; fi");
284 assert_eq!(e.location.code.start_line_number.get(), 1);
285 assert_eq!(*e.location.code.source, Source::Unknown);
286 assert_eq!(e.location.range, 22..24);
287 }
288
289 #[test]
290 fn parser_if_command_without_fi() {
291 let mut lexer = Lexer::from_memory(" if :; then :; }", Source::Unknown);
292 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
293
294 let result = parser.compound_command().now_or_never().unwrap();
295 let e = result.unwrap_err();
296 assert_matches!(e.cause,
297 ErrorCause::Syntax(SyntaxError::UnclosedIf { opening_location }) => {
298 assert_eq!(*opening_location.code.value.borrow(), " if :; then :; }");
299 assert_eq!(opening_location.code.start_line_number.get(), 1);
300 assert_eq!(*opening_location.code.source, Source::Unknown);
301 assert_eq!(opening_location.range, 2..4);
302 });
303 assert_eq!(*e.location.code.value.borrow(), " if :; then :; }");
304 assert_eq!(e.location.code.start_line_number.get(), 1);
305 assert_eq!(*e.location.code.source, Source::Unknown);
306 assert_eq!(e.location.range, 16..17);
307 }
308
309 #[test]
310 fn parser_if_command_empty_condition() {
311 let mut lexer = Lexer::from_memory(" if then :; fi", Source::Unknown);
312 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
313
314 let result = parser.compound_command().now_or_never().unwrap();
315 let e = result.unwrap_err();
316 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyIfCondition));
317 assert_eq!(*e.location.code.value.borrow(), " if then :; fi");
318 assert_eq!(e.location.code.start_line_number.get(), 1);
319 assert_eq!(*e.location.code.source, Source::Unknown);
320 assert_eq!(e.location.range, 6..10);
321 }
322
323 #[test]
324 fn parser_if_command_empty_body() {
325 let mut lexer = Lexer::from_memory("if :; then fi", Source::Unknown);
326 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
327
328 let result = parser.compound_command().now_or_never().unwrap();
329 let e = result.unwrap_err();
330 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyIfBody));
331 assert_eq!(*e.location.code.value.borrow(), "if :; then fi");
332 assert_eq!(e.location.code.start_line_number.get(), 1);
333 assert_eq!(*e.location.code.source, Source::Unknown);
334 assert_eq!(e.location.range, 11..13);
335 }
336
337 #[test]
338 fn parser_if_command_empty_elif_condition() {
339 let mut lexer = Lexer::from_memory("if :; then :; elif then :; fi", Source::Unknown);
340 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
341
342 let result = parser.compound_command().now_or_never().unwrap();
343 let e = result.unwrap_err();
344 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyElifCondition));
345 assert_eq!(
346 *e.location.code.value.borrow(),
347 "if :; then :; elif then :; fi"
348 );
349 assert_eq!(e.location.code.start_line_number.get(), 1);
350 assert_eq!(*e.location.code.source, Source::Unknown);
351 assert_eq!(e.location.range, 19..23);
352 }
353
354 #[test]
355 fn parser_if_command_empty_elif_body() {
356 let mut lexer = Lexer::from_memory("if :; then :; elif :; then fi", Source::Unknown);
357 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
358
359 let result = parser.compound_command().now_or_never().unwrap();
360 let e = result.unwrap_err();
361 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyElifBody));
362 assert_eq!(
363 *e.location.code.value.borrow(),
364 "if :; then :; elif :; then fi"
365 );
366 assert_eq!(e.location.code.start_line_number.get(), 1);
367 assert_eq!(*e.location.code.source, Source::Unknown);
368 assert_eq!(e.location.range, 27..29);
369 }
370
371 #[test]
372 fn parser_if_command_empty_else() {
373 let mut lexer = Lexer::from_memory("if :; then :; else fi", Source::Unknown);
374 let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
375
376 let result = parser.compound_command().now_or_never().unwrap();
377 let e = result.unwrap_err();
378 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyElse));
379 assert_eq!(*e.location.code.value.borrow(), "if :; then :; else fi");
380 assert_eq!(e.location.code.start_line_number.get(), 1);
381 assert_eq!(*e.location.code.source, Source::Unknown);
382 assert_eq!(e.location.range, 19..21);
383 }
384}