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::source::Source;
144 use assert_matches::assert_matches;
145 use futures_util::FutureExt;
146
147 #[test]
148 fn parser_if_command_minimum() {
149 let mut lexer = Lexer::with_code("if a; then b; fi");
150 let mut parser = Parser::new(&mut lexer);
151
152 let result = parser.compound_command().now_or_never().unwrap();
153 let compound_command = result.unwrap().unwrap();
154 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
155 assert_eq!(condition.to_string(), "a");
156 assert_eq!(body.to_string(), "b");
157 assert_eq!(elifs, []);
158 assert_eq!(r#else, None);
159 });
160
161 let next = parser.peek_token().now_or_never().unwrap().unwrap();
162 assert_eq!(next.id, EndOfInput);
163 }
164
165 #[test]
166 fn parser_if_command_one_elif() {
167 let mut lexer = Lexer::with_code("if\ntrue\nthen\nfalse\n\nelif x; then y& fi");
168 let mut parser = Parser::new(&mut lexer);
169
170 let result = parser.compound_command().now_or_never().unwrap();
171 let compound_command = result.unwrap().unwrap();
172 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
173 assert_eq!(condition.to_string(), "true");
174 assert_eq!(body.to_string(), "false");
175 assert_eq!(elifs.len(), 1);
176 assert_eq!(elifs[0].to_string(), "elif x; then y&");
177 assert_eq!(r#else, None);
178 });
179
180 let next = parser.peek_token().now_or_never().unwrap().unwrap();
181 assert_eq!(next.id, EndOfInput);
182 }
183
184 #[test]
185 fn parser_if_command_many_elifs() {
186 let mut lexer = Lexer::with_code(
187 "if a; then b; elif c; then d; elif e 1; e 2& then f 1; f 2& elif g; then h; fi",
188 );
189 let mut parser = Parser::new(&mut lexer);
190
191 let result = parser.compound_command().now_or_never().unwrap();
192 let compound_command = result.unwrap().unwrap();
193 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
194 assert_eq!(condition.to_string(), "a");
195 assert_eq!(body.to_string(), "b");
196 assert_eq!(elifs.len(), 3);
197 assert_eq!(elifs[0].to_string(), "elif c; then d");
198 assert_eq!(elifs[1].to_string(), "elif e 1; e 2& then f 1; f 2&");
199 assert_eq!(elifs[2].to_string(), "elif g; then h");
200 assert_eq!(r#else, None);
201 });
202
203 let next = parser.peek_token().now_or_never().unwrap().unwrap();
204 assert_eq!(next.id, EndOfInput);
205 }
206
207 #[test]
208 fn parser_if_command_else() {
209 let mut lexer = Lexer::with_code("if a; then b; else c; d; fi");
210 let mut parser = Parser::new(&mut lexer);
211
212 let result = parser.compound_command().now_or_never().unwrap();
213 let compound_command = result.unwrap().unwrap();
214 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
215 assert_eq!(condition.to_string(), "a");
216 assert_eq!(body.to_string(), "b");
217 assert_eq!(elifs, []);
218 assert_eq!(r#else.unwrap().to_string(), "c; d");
219 });
220
221 let next = parser.peek_token().now_or_never().unwrap().unwrap();
222 assert_eq!(next.id, EndOfInput);
223 }
224
225 #[test]
226 fn parser_if_command_elif_and_else() {
227 let mut lexer = Lexer::with_code("if 1; then 2; elif 3; then 4; else 5; fi");
228 let mut parser = Parser::new(&mut lexer);
229
230 let result = parser.compound_command().now_or_never().unwrap();
231 let compound_command = result.unwrap().unwrap();
232 assert_matches!(compound_command, CompoundCommand::If { condition, body, elifs, r#else } => {
233 assert_eq!(condition.to_string(), "1");
234 assert_eq!(body.to_string(), "2");
235 assert_eq!(elifs.len(), 1);
236 assert_eq!(elifs[0].to_string(), "elif 3; then 4");
237 assert_eq!(r#else.unwrap().to_string(), "5");
238 });
239
240 let next = parser.peek_token().now_or_never().unwrap().unwrap();
241 assert_eq!(next.id, EndOfInput);
242 }
243
244 #[test]
245 fn parser_if_command_without_then_after_if() {
246 let mut lexer = Lexer::with_code(" if :; fi");
247 let mut parser = Parser::new(&mut lexer);
248
249 let result = parser.compound_command().now_or_never().unwrap();
250 let e = result.unwrap_err();
251 assert_matches!(e.cause, ErrorCause::Syntax(SyntaxError::IfMissingThen { if_location }) => {
252 assert_eq!(*if_location.code.value.borrow(), " if :; fi");
253 assert_eq!(if_location.code.start_line_number.get(), 1);
254 assert_eq!(*if_location.code.source, Source::Unknown);
255 assert_eq!(if_location.range, 1..3);
256 });
257 assert_eq!(*e.location.code.value.borrow(), " if :; fi");
258 assert_eq!(e.location.code.start_line_number.get(), 1);
259 assert_eq!(*e.location.code.source, Source::Unknown);
260 assert_eq!(e.location.range, 7..9);
261 }
262
263 #[test]
264 fn parser_if_command_without_then_after_elif() {
265 let mut lexer = Lexer::with_code("if a; then b; elif c; fi");
266 let mut parser = Parser::new(&mut lexer);
267
268 let result = parser.compound_command().now_or_never().unwrap();
269 let e = result.unwrap_err();
270 assert_matches!(e.cause,
271 ErrorCause::Syntax(SyntaxError::ElifMissingThen { elif_location }) => {
272 assert_eq!(*elif_location.code.value.borrow(), "if a; then b; elif c; fi");
273 assert_eq!(elif_location.code.start_line_number.get(), 1);
274 assert_eq!(*elif_location.code.source, Source::Unknown);
275 assert_eq!(elif_location.range, 14..18);
276 });
277 assert_eq!(*e.location.code.value.borrow(), "if a; then b; elif c; fi");
278 assert_eq!(e.location.code.start_line_number.get(), 1);
279 assert_eq!(*e.location.code.source, Source::Unknown);
280 assert_eq!(e.location.range, 22..24);
281 }
282
283 #[test]
284 fn parser_if_command_without_fi() {
285 let mut lexer = Lexer::with_code(" if :; then :; }");
286 let mut parser = Parser::new(&mut lexer);
287
288 let result = parser.compound_command().now_or_never().unwrap();
289 let e = result.unwrap_err();
290 assert_matches!(e.cause,
291 ErrorCause::Syntax(SyntaxError::UnclosedIf { opening_location }) => {
292 assert_eq!(*opening_location.code.value.borrow(), " if :; then :; }");
293 assert_eq!(opening_location.code.start_line_number.get(), 1);
294 assert_eq!(*opening_location.code.source, Source::Unknown);
295 assert_eq!(opening_location.range, 2..4);
296 });
297 assert_eq!(*e.location.code.value.borrow(), " if :; then :; }");
298 assert_eq!(e.location.code.start_line_number.get(), 1);
299 assert_eq!(*e.location.code.source, Source::Unknown);
300 assert_eq!(e.location.range, 16..17);
301 }
302
303 #[test]
304 fn parser_if_command_empty_condition() {
305 let mut lexer = Lexer::with_code(" if then :; fi");
306 let mut parser = Parser::new(&mut lexer);
307
308 let result = parser.compound_command().now_or_never().unwrap();
309 let e = result.unwrap_err();
310 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyIfCondition));
311 assert_eq!(*e.location.code.value.borrow(), " if then :; fi");
312 assert_eq!(e.location.code.start_line_number.get(), 1);
313 assert_eq!(*e.location.code.source, Source::Unknown);
314 assert_eq!(e.location.range, 6..10);
315 }
316
317 #[test]
318 fn parser_if_command_empty_body() {
319 let mut lexer = Lexer::with_code("if :; then fi");
320 let mut parser = Parser::new(&mut lexer);
321
322 let result = parser.compound_command().now_or_never().unwrap();
323 let e = result.unwrap_err();
324 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyIfBody));
325 assert_eq!(*e.location.code.value.borrow(), "if :; then fi");
326 assert_eq!(e.location.code.start_line_number.get(), 1);
327 assert_eq!(*e.location.code.source, Source::Unknown);
328 assert_eq!(e.location.range, 11..13);
329 }
330
331 #[test]
332 fn parser_if_command_empty_elif_condition() {
333 let mut lexer = Lexer::with_code("if :; then :; elif then :; fi");
334 let mut parser = Parser::new(&mut lexer);
335
336 let result = parser.compound_command().now_or_never().unwrap();
337 let e = result.unwrap_err();
338 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyElifCondition));
339 assert_eq!(
340 *e.location.code.value.borrow(),
341 "if :; then :; elif then :; fi"
342 );
343 assert_eq!(e.location.code.start_line_number.get(), 1);
344 assert_eq!(*e.location.code.source, Source::Unknown);
345 assert_eq!(e.location.range, 19..23);
346 }
347
348 #[test]
349 fn parser_if_command_empty_elif_body() {
350 let mut lexer = Lexer::with_code("if :; then :; elif :; then fi");
351 let mut parser = Parser::new(&mut lexer);
352
353 let result = parser.compound_command().now_or_never().unwrap();
354 let e = result.unwrap_err();
355 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyElifBody));
356 assert_eq!(
357 *e.location.code.value.borrow(),
358 "if :; then :; elif :; then fi"
359 );
360 assert_eq!(e.location.code.start_line_number.get(), 1);
361 assert_eq!(*e.location.code.source, Source::Unknown);
362 assert_eq!(e.location.range, 27..29);
363 }
364
365 #[test]
366 fn parser_if_command_empty_else() {
367 let mut lexer = Lexer::with_code("if :; then :; else fi");
368 let mut parser = Parser::new(&mut lexer);
369
370 let result = parser.compound_command().now_or_never().unwrap();
371 let e = result.unwrap_err();
372 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::EmptyElse));
373 assert_eq!(*e.location.code.value.borrow(), "if :; then :; else fi");
374 assert_eq!(e.location.code.start_line_number.get(), 1);
375 assert_eq!(*e.location.code.source, Source::Unknown);
376 assert_eq!(e.location.range, 19..21);
377 }
378}