1use super::core::Parser;
20use super::core::Rec;
21use super::core::Result;
22use super::error::Error;
23use super::error::SyntaxError;
24use super::lex::Operator::{CloseParen, Newline, OpenParen};
25use super::lex::TokenId::{Operator, Token};
26use crate::syntax::Array;
27use crate::syntax::Assign;
28use crate::syntax::ExpansionMode;
29use crate::syntax::MaybeLiteral as _;
30use crate::syntax::Redir;
31use crate::syntax::Scalar;
32use crate::syntax::SimpleCommand;
33use crate::syntax::Word;
34
35fn determine_expansion_mode(word: Word) -> (Word, ExpansionMode) {
45 use crate::syntax::{TextUnit::Literal, WordUnit::Unquoted};
46 if let Some(eq) = word.units.iter().position(|u| *u == Unquoted(Literal('='))) {
47 if let Some(name) = word.units[..eq].to_string_if_literal() {
48 if !name.is_empty() {
49 let mut word = word;
50 word.parse_tilde_everywhere_after(eq + 1);
51 return (word, ExpansionMode::Single);
52 }
53 }
54 }
55 (word, ExpansionMode::Multiple)
56}
57
58#[derive(Default)]
60struct Builder {
61 assigns: Vec<Assign>,
62 words: Vec<(Word, ExpansionMode)>,
63 redirs: Vec<Redir>,
64}
65
66impl Builder {
67 fn is_empty(&self) -> bool {
68 self.assigns.is_empty() && self.words.is_empty() && self.redirs.is_empty()
69 }
70}
71
72impl From<Builder> for SimpleCommand {
73 fn from(builder: Builder) -> Self {
74 SimpleCommand {
75 assigns: builder.assigns,
76 words: builder.words,
77 redirs: builder.redirs.into(),
78 }
79 }
80}
81
82impl Parser<'_, '_> {
83 pub async fn array_values(&mut self) -> Result<Option<Vec<Word>>> {
91 if self.peek_token().await?.id != Operator(OpenParen) {
92 return Ok(None);
93 }
94
95 let opening_location = self.take_token_raw().await?.word.location;
96 let mut words = vec![];
97
98 loop {
99 let next = self.take_token_auto(&[]).await?;
100 match next.id {
101 Operator(Newline) => continue,
102 Operator(CloseParen) => break,
103 Token(_keyword) => words.push(next.word),
104 _ => {
105 return Err(Error {
106 cause: SyntaxError::UnclosedArrayValue { opening_location }.into(),
107 location: next.word.location,
108 });
109 }
110 }
111 }
112
113 Ok(Some(words))
114 }
115
116 pub async fn simple_command(&mut self) -> Result<Rec<Option<SimpleCommand>>> {
121 let mut is_declaration_utility = None;
122 let mut result = Builder::default();
123
124 loop {
125 if let Some(redir) = self.redirection().await? {
127 result.redirs.push(redir);
128 continue;
129 }
130
131 match self.peek_token().await?.id {
133 Token(Some(_keyword)) if result.is_empty() => break,
134 Token(_) => (),
135 _ => break,
136 }
137
138 let token = match self.take_token_manual(result.words.is_empty()).await? {
140 Rec::AliasSubstituted => {
141 if result.is_empty() {
142 return Ok(Rec::AliasSubstituted);
143 } else {
144 continue;
145 }
146 }
147 Rec::Parsed(token) => token,
148 };
149
150 if let Some(is_declaration_utility) = is_declaration_utility {
152 debug_assert!(!result.words.is_empty());
155
156 result.words.push(if is_declaration_utility {
157 determine_expansion_mode(token.word)
158 } else {
159 (token.word, ExpansionMode::Multiple)
160 });
161 continue;
162 }
163
164 let assign_or_word = if result.words.is_empty() {
166 Assign::try_from(token.word)
168 } else {
169 Err(token.word)
171 };
172 let mut assign = match assign_or_word {
173 Ok(assign) => assign,
174 Err(word) => {
175 debug_assert!(is_declaration_utility.is_none());
176 is_declaration_utility = self.word_names_declaration_utility(&word);
177 result.words.push((word, ExpansionMode::Multiple));
178 continue;
179 }
180 };
181
182 let units = match &assign.value {
183 Scalar(Word { units, .. }) => units,
184 _ => panic!(
185 "Assign::try_from produced a non-scalar value {:?}",
186 assign.value
187 ),
188 };
189
190 if units.is_empty() && !self.has_blank().await? {
193 if let Some(words) = self.array_values().await? {
194 assign.value = Array(words);
195 }
196 }
197
198 result.assigns.push(assign);
199 }
200
201 Ok(Rec::Parsed((!result.is_empty()).then(|| result.into())))
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::super::error::ErrorCause;
208 use super::super::lex::Lexer;
209 use super::super::lex::TokenId::EndOfInput;
210 use super::*;
211 use crate::decl_util::EmptyGlossary;
212 use crate::source::Source;
213 use crate::syntax::RedirBody;
214 use crate::syntax::RedirOp;
215 use crate::syntax::TextUnit;
216 use crate::syntax::WordUnit;
217 use assert_matches::assert_matches;
218 use futures_util::FutureExt as _;
219
220 #[test]
221 fn determine_expansion_mode_empty_name() {
222 let in_word = "=".parse::<Word>().unwrap();
223 let (out_word, mode) = determine_expansion_mode(in_word.clone());
224 assert_eq!(out_word, in_word);
225 assert_eq!(mode, ExpansionMode::Multiple);
226 }
227
228 #[test]
229 fn determine_expansion_mode_nonempty_name() {
230 let in_word = "foo=".parse::<Word>().unwrap();
231 let (out_word, mode) = determine_expansion_mode(in_word.clone());
232 assert_eq!(out_word, in_word);
233 assert_eq!(mode, ExpansionMode::Single);
234 }
235
236 #[test]
237 fn determine_expansion_mode_non_literal_name() {
238 let in_word = "${X}=".parse::<Word>().unwrap();
239 let (out_word, mode) = determine_expansion_mode(in_word.clone());
240 assert_eq!(out_word, in_word);
241 assert_eq!(mode, ExpansionMode::Multiple);
242 }
243
244 #[test]
245 fn determine_expansion_mode_tilde_expansions_after_equal() {
246 let word = "~=~:~b".parse().unwrap();
247 let (word, mode) = determine_expansion_mode(word);
248 assert_eq!(
249 word.units,
250 [
251 WordUnit::Unquoted(TextUnit::Literal('~')),
252 WordUnit::Unquoted(TextUnit::Literal('=')),
253 WordUnit::Tilde {
254 name: "".to_string(),
255 followed_by_slash: false
256 },
257 WordUnit::Unquoted(TextUnit::Literal(':')),
258 WordUnit::Tilde {
259 name: "b".to_string(),
260 followed_by_slash: false
261 },
262 ]
263 );
264 assert_eq!(mode, ExpansionMode::Single);
265 }
266
267 #[test]
268 fn parser_array_values_no_open_parenthesis() {
269 let mut lexer = Lexer::with_code(")");
270 let mut parser = Parser::new(&mut lexer);
271 let result = parser.array_values().now_or_never().unwrap().unwrap();
272 assert_eq!(result, None);
273 }
274
275 #[test]
276 fn parser_array_values_empty() {
277 let mut lexer = Lexer::with_code("()");
278 let mut parser = Parser::new(&mut lexer);
279 let result = parser.array_values().now_or_never().unwrap();
280 let words = result.unwrap().unwrap();
281 assert_eq!(words, []);
282
283 let next = parser.peek_token().now_or_never().unwrap().unwrap();
284 assert_eq!(next.id, EndOfInput);
285 }
286
287 #[test]
288 fn parser_array_values_many() {
289 let mut lexer = Lexer::with_code("(a b c)");
290 let mut parser = Parser::new(&mut lexer);
291 let result = parser.array_values().now_or_never().unwrap();
292 let words = result.unwrap().unwrap();
293 assert_eq!(words.len(), 3);
294 assert_eq!(words[0].to_string(), "a");
295 assert_eq!(words[1].to_string(), "b");
296 assert_eq!(words[2].to_string(), "c");
297 }
298
299 #[test]
300 fn parser_array_values_newlines_and_comments() {
301 let mut lexer = Lexer::with_code(
302 "(
303 a # b
304 c d
305 )",
306 );
307 let mut parser = Parser::new(&mut lexer);
308 let result = parser.array_values().now_or_never().unwrap();
309 let words = result.unwrap().unwrap();
310 assert_eq!(words.len(), 3);
311 assert_eq!(words[0].to_string(), "a");
312 assert_eq!(words[1].to_string(), "c");
313 assert_eq!(words[2].to_string(), "d");
314 }
315
316 #[test]
317 fn parser_array_values_unclosed() {
318 let mut lexer = Lexer::with_code("(a b");
319 let mut parser = Parser::new(&mut lexer);
320 let e = parser.array_values().now_or_never().unwrap().unwrap_err();
321 assert_matches!(e.cause,
322 ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
323 assert_eq!(*opening_location.code.value.borrow(), "(a b");
324 assert_eq!(opening_location.code.start_line_number.get(), 1);
325 assert_eq!(*opening_location.code.source, Source::Unknown);
326 assert_eq!(opening_location.range, 0..1);
327 });
328 assert_eq!(*e.location.code.value.borrow(), "(a b");
329 assert_eq!(e.location.code.start_line_number.get(), 1);
330 assert_eq!(*e.location.code.source, Source::Unknown);
331 assert_eq!(e.location.range, 4..4);
332 }
333
334 #[test]
335 fn parser_array_values_invalid_word() {
336 let mut lexer = Lexer::with_code("(a;b)");
337 let mut parser = Parser::new(&mut lexer);
338 let e = parser.array_values().now_or_never().unwrap().unwrap_err();
339 assert_matches!(e.cause,
340 ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
341 assert_eq!(*opening_location.code.value.borrow(), "(a;b)");
342 assert_eq!(opening_location.code.start_line_number.get(), 1);
343 assert_eq!(*opening_location.code.source, Source::Unknown);
344 assert_eq!(opening_location.range, 0..1);
345 });
346 assert_eq!(*e.location.code.value.borrow(), "(a;b)");
347 assert_eq!(e.location.code.start_line_number.get(), 1);
348 assert_eq!(*e.location.code.source, Source::Unknown);
349 assert_eq!(e.location.range, 2..3);
350 }
351
352 #[test]
353 fn parser_simple_command_eof() {
354 let mut lexer = Lexer::with_code("");
355 let mut parser = Parser::new(&mut lexer);
356
357 let result = parser.simple_command().now_or_never().unwrap();
358 assert_eq!(result, Ok(Rec::Parsed(None)));
359 }
360
361 #[test]
362 fn parser_simple_command_keyword() {
363 let mut lexer = Lexer::with_code("then");
364 let mut parser = Parser::new(&mut lexer);
365
366 let result = parser.simple_command().now_or_never().unwrap();
367 assert_eq!(result, Ok(Rec::Parsed(None)));
368 }
369
370 #[test]
371 fn parser_simple_command_one_assignment() {
372 let mut lexer = Lexer::with_code("my=assignment");
373 let mut parser = Parser::new(&mut lexer);
374
375 let result = parser.simple_command().now_or_never().unwrap();
376 let sc = result.unwrap().unwrap().unwrap();
377 assert_eq!(sc.words, []);
378 assert_eq!(*sc.redirs, []);
379 assert_eq!(sc.assigns.len(), 1);
380 assert_eq!(sc.assigns[0].name, "my");
381 assert_eq!(sc.assigns[0].value.to_string(), "assignment");
382 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "my=assignment");
383 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
384 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
385 assert_eq!(sc.assigns[0].location.range, 0..13);
386 }
387
388 #[test]
389 fn parser_simple_command_many_assignments() {
390 let mut lexer = Lexer::with_code("a= b=! c=X");
391 let mut parser = Parser::new(&mut lexer);
392
393 let result = parser.simple_command().now_or_never().unwrap();
394 let sc = result.unwrap().unwrap().unwrap();
395 assert_eq!(sc.words, []);
396 assert_eq!(*sc.redirs, []);
397 assert_eq!(sc.assigns.len(), 3);
398 assert_eq!(sc.assigns[0].name, "a");
399 assert_eq!(sc.assigns[0].value.to_string(), "");
400 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= b=! c=X");
401 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
402 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
403 assert_eq!(sc.assigns[0].location.range, 0..2);
404 assert_eq!(sc.assigns[1].name, "b");
405 assert_eq!(sc.assigns[1].value.to_string(), "!");
406 assert_eq!(*sc.assigns[1].location.code.value.borrow(), "a= b=! c=X");
407 assert_eq!(sc.assigns[1].location.code.start_line_number.get(), 1);
408 assert_eq!(*sc.assigns[1].location.code.source, Source::Unknown);
409 assert_eq!(sc.assigns[1].location.range, 3..6);
410 assert_eq!(sc.assigns[2].name, "c");
411 assert_eq!(sc.assigns[2].value.to_string(), "X");
412 assert_eq!(*sc.assigns[2].location.code.value.borrow(), "a= b=! c=X");
413 assert_eq!(sc.assigns[2].location.code.start_line_number.get(), 1);
414 assert_eq!(*sc.assigns[2].location.code.source, Source::Unknown);
415 assert_eq!(sc.assigns[2].location.range, 7..10);
416 }
417
418 #[test]
419 fn parser_simple_command_one_word() {
420 let mut lexer = Lexer::with_code("word");
421 let mut parser = Parser::new(&mut lexer);
422
423 let result = parser.simple_command().now_or_never().unwrap();
424 let sc = result.unwrap().unwrap().unwrap();
425 assert_eq!(sc.assigns, []);
426 assert_eq!(*sc.redirs, []);
427 assert_eq!(sc.words.len(), 1);
428 assert_eq!(sc.words[0].0.to_string(), "word");
429 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
430 }
431
432 #[test]
433 fn parser_simple_command_many_words() {
434 let mut lexer = Lexer::with_code(": if then");
435 let mut parser = Parser::new(&mut lexer);
436
437 let result = parser.simple_command().now_or_never().unwrap();
438 let sc = result.unwrap().unwrap().unwrap();
439 assert_eq!(sc.assigns, []);
440 assert_eq!(*sc.redirs, []);
441 assert_eq!(sc.words.len(), 3);
442 assert_eq!(sc.words[0].0.to_string(), ":");
443 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
444 assert_eq!(sc.words[1].0.to_string(), "if");
445 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
446 assert_eq!(sc.words[2].0.to_string(), "then");
447 assert_eq!(sc.words[2].1, ExpansionMode::Multiple);
448 }
449
450 #[test]
451 fn parser_simple_command_one_redirection() {
452 let mut lexer = Lexer::with_code("<foo");
453 let mut parser = Parser::new(&mut lexer);
454
455 let result = parser.simple_command().now_or_never().unwrap();
456 let sc = result.unwrap().unwrap().unwrap();
457 assert_eq!(sc.assigns, []);
458 assert_eq!(sc.words, []);
459 assert_eq!(sc.redirs.len(), 1);
460 assert_eq!(sc.redirs[0].fd, None);
461 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
462 assert_eq!(operator, &RedirOp::FileIn);
463 assert_eq!(operand.to_string(), "foo")
464 });
465
466 let next = parser.peek_token().now_or_never().unwrap().unwrap();
467 assert_eq!(next.id, EndOfInput);
468 }
469
470 #[test]
471 fn parser_simple_command_many_redirections() {
472 let mut lexer = Lexer::with_code("<one >two >>three");
473 let mut parser = Parser::new(&mut lexer);
474
475 let result = parser.simple_command().now_or_never().unwrap();
476 let sc = result.unwrap().unwrap().unwrap();
477 assert_eq!(sc.assigns, []);
478 assert_eq!(sc.words, []);
479 assert_eq!(sc.redirs.len(), 3);
480 assert_eq!(sc.redirs[0].fd, None);
481 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
482 assert_eq!(operator, &RedirOp::FileIn);
483 assert_eq!(operand.to_string(), "one")
484 });
485 assert_eq!(sc.redirs[1].fd, None);
486 assert_matches!(sc.redirs[1].body, RedirBody::Normal { ref operator, ref operand } => {
487 assert_eq!(operator, &RedirOp::FileOut);
488 assert_eq!(operand.to_string(), "two")
489 });
490 assert_eq!(sc.redirs[2].fd, None);
491 assert_matches!(sc.redirs[2].body, RedirBody::Normal { ref operator, ref operand } => {
492 assert_eq!(operator, &RedirOp::FileAppend);
493 assert_eq!(operand.to_string(), "three")
494 });
495
496 let next = parser.peek_token().now_or_never().unwrap().unwrap();
497 assert_eq!(next.id, EndOfInput);
498 }
499
500 #[test]
501 fn parser_simple_command_assignment_word() {
502 let mut lexer = Lexer::with_code("if=then else");
503 let mut parser = Parser::new(&mut lexer);
504
505 let result = parser.simple_command().now_or_never().unwrap();
506 let sc = result.unwrap().unwrap().unwrap();
507 assert_eq!(*sc.redirs, []);
508 assert_eq!(sc.assigns.len(), 1);
509 assert_eq!(sc.words.len(), 1);
510 assert_eq!(sc.assigns[0].name, "if");
511 assert_eq!(sc.assigns[0].value.to_string(), "then");
512 assert_eq!(sc.words[0].0.to_string(), "else");
513 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
514 }
515
516 #[test]
517 fn parser_simple_command_word_redirection() {
518 let mut lexer = Lexer::with_code("word <redirection");
519 let mut parser = Parser::new(&mut lexer);
520
521 let result = parser.simple_command().now_or_never().unwrap();
522 let sc = result.unwrap().unwrap().unwrap();
523 assert_eq!(sc.assigns, []);
524 assert_eq!(sc.words.len(), 1);
525 assert_eq!(sc.redirs.len(), 1);
526 assert_eq!(sc.words[0].0.to_string(), "word");
527 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
528 assert_eq!(sc.redirs[0].fd, None);
529 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
530 assert_eq!(operator, &RedirOp::FileIn);
531 assert_eq!(operand.to_string(), "redirection")
532 });
533 }
534
535 #[test]
536 fn parser_simple_command_redirection_assignment() {
537 let mut lexer = Lexer::with_code("<foo a=b");
538 let mut parser = Parser::new(&mut lexer);
539
540 let result = parser.simple_command().now_or_never().unwrap();
541 let sc = result.unwrap().unwrap().unwrap();
542 assert_eq!(sc.words, []);
543 assert_eq!(sc.assigns.len(), 1);
544 assert_eq!(sc.redirs.len(), 1);
545 assert_eq!(sc.assigns[0].name, "a");
546 assert_eq!(sc.assigns[0].value.to_string(), "b");
547 assert_eq!(sc.redirs[0].fd, None);
548 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
549 assert_eq!(operator, &RedirOp::FileIn);
550 assert_eq!(operand.to_string(), "foo")
551 });
552 }
553
554 #[test]
555 fn parser_simple_command_assignment_redirection_word() {
556 let mut lexer = Lexer::with_code("if=then <foo else");
557 let mut parser = Parser::new(&mut lexer);
558
559 let result = parser.simple_command().now_or_never().unwrap();
560 let sc = result.unwrap().unwrap().unwrap();
561 assert_eq!(sc.assigns.len(), 1);
562 assert_eq!(sc.words.len(), 1);
563 assert_eq!(sc.redirs.len(), 1);
564 assert_eq!(sc.assigns[0].name, "if");
565 assert_eq!(sc.assigns[0].value.to_string(), "then");
566 assert_eq!(sc.words[0].0.to_string(), "else");
567 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
568 assert_eq!(sc.redirs[0].fd, None);
569 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
570 assert_eq!(operator, &RedirOp::FileIn);
571 assert_eq!(operand.to_string(), "foo")
572 });
573 }
574
575 #[test]
576 fn parser_simple_command_array_assignment() {
577 let mut lexer = Lexer::with_code("a=()");
578 let mut parser = Parser::new(&mut lexer);
579
580 let result = parser.simple_command().now_or_never().unwrap();
581 let sc = result.unwrap().unwrap().unwrap();
582 assert_eq!(sc.assigns.len(), 1);
583 assert_eq!(sc.words, []);
584 assert_eq!(*sc.redirs, []);
585 assert_eq!(sc.assigns[0].name, "a");
586 assert_matches!(&sc.assigns[0].value, Array(words) => {
587 assert_eq!(words, &[]);
588 });
589
590 let next = parser.peek_token().now_or_never().unwrap().unwrap();
591 assert_eq!(next.id, EndOfInput);
592 }
593
594 #[test]
595 fn parser_simple_command_empty_assignment_followed_by_blank_and_parenthesis() {
596 let mut lexer = Lexer::with_code("a= ()");
597 let mut parser = Parser::new(&mut lexer);
598
599 let result = parser.simple_command().now_or_never().unwrap();
600 let sc = result.unwrap().unwrap().unwrap();
601 assert_eq!(sc.assigns.len(), 1);
602 assert_eq!(sc.words, []);
603 assert_eq!(*sc.redirs, []);
604 assert_eq!(sc.assigns[0].name, "a");
605 assert_eq!(sc.assigns[0].value.to_string(), "");
606 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= ()");
607 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
608 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
609 assert_eq!(sc.assigns[0].location.range, 0..2);
610
611 let next = parser.peek_token().now_or_never().unwrap().unwrap();
612 assert_eq!(next.id, Operator(OpenParen));
613 }
614
615 #[test]
616 fn parser_simple_command_non_empty_assignment_followed_by_parenthesis() {
617 let mut lexer = Lexer::with_code("a=b()");
618 let mut parser = Parser::new(&mut lexer);
619
620 let result = parser.simple_command().now_or_never().unwrap();
621 let sc = result.unwrap().unwrap().unwrap();
622 assert_eq!(sc.assigns.len(), 1);
623 assert_eq!(sc.words, []);
624 assert_eq!(*sc.redirs, []);
625 assert_eq!(sc.assigns[0].name, "a");
626 assert_eq!(sc.assigns[0].value.to_string(), "b");
627 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a=b()");
628 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
629 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
630 assert_eq!(sc.assigns[0].location.range, 0..3);
631
632 let next = parser.peek_token().now_or_never().unwrap().unwrap();
633 assert_eq!(next.id, Operator(OpenParen));
634 }
635
636 #[test]
637 fn word_with_single_expansion_mode_in_declaration_utility() {
638 let mut lexer = Lexer::with_code("export a=b");
641 let mut parser = Parser::new(&mut lexer);
642
643 let result = parser.simple_command().now_or_never().unwrap();
644 let sc = result.unwrap().unwrap().unwrap();
645 assert_eq!(sc.assigns, []);
646 assert_eq!(sc.words.len(), 2);
647 assert_eq!(*sc.redirs, []);
648 assert_eq!(sc.words[0].0.to_string(), "export");
649 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
650 assert_eq!(sc.words[1].0.to_string(), "a=b");
651 assert_eq!(sc.words[1].1, ExpansionMode::Single);
652 }
653
654 #[test]
655 fn word_with_multiple_expansion_mode_in_declaration_utility() {
656 let mut lexer = Lexer::with_code("export foo");
659 let mut parser = Parser::new(&mut lexer);
660
661 let result = parser.simple_command().now_or_never().unwrap();
662 let sc = result.unwrap().unwrap().unwrap();
663 assert_eq!(sc.assigns, []);
664 assert_eq!(sc.words.len(), 2);
665 assert_eq!(*sc.redirs, []);
666 assert_eq!(sc.words[0].0.to_string(), "export");
667 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
668 assert_eq!(sc.words[1].0.to_string(), "foo");
669 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
670 }
671
672 #[test]
673 fn word_with_multiple_expansion_mode_in_non_declaration_utility() {
674 let mut lexer = Lexer::with_code("foo a=b");
677 let mut parser = Parser::new(&mut lexer);
678
679 let result = parser.simple_command().now_or_never().unwrap();
680 let sc = result.unwrap().unwrap().unwrap();
681 assert_eq!(sc.assigns, []);
682 assert_eq!(sc.words.len(), 2);
683 assert_eq!(*sc.redirs, []);
684 assert_eq!(sc.words[0].0.to_string(), "foo");
685 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
686 assert_eq!(sc.words[1].0.to_string(), "a=b");
687 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
688 }
689
690 #[test]
691 fn declaration_utility_determined_by_non_first_word() {
692 let mut lexer = Lexer::with_code("command command export foo a=b");
695 let mut parser = Parser::new(&mut lexer);
696 let result = parser.simple_command().now_or_never().unwrap();
697 let sc = result.unwrap().unwrap().unwrap();
698 assert_eq!(sc.words[4].0.to_string(), "a=b");
699 assert_eq!(sc.words[4].1, ExpansionMode::Single);
700
701 let mut lexer = Lexer::with_code("command command foo export a=b");
702 let mut parser = Parser::new(&mut lexer);
703 let result = parser.simple_command().now_or_never().unwrap();
704 let sc = result.unwrap().unwrap().unwrap();
705 assert_eq!(sc.words[4].0.to_string(), "a=b");
706 assert_eq!(sc.words[4].1, ExpansionMode::Multiple);
707 }
708
709 #[test]
710 fn no_declaration_utilities_with_empty_glossary() {
711 let mut lexer = Lexer::with_code("export a=b");
713 let mut parser = Parser::config()
714 .declaration_utilities(&EmptyGlossary)
715 .input(&mut lexer);
716
717 let result = parser.simple_command().now_or_never().unwrap();
718 let sc = result.unwrap().unwrap().unwrap();
719 assert_eq!(sc.assigns, []);
720 assert_eq!(sc.words.len(), 2);
721 assert_eq!(*sc.redirs, []);
722 assert_eq!(sc.words[0].0.to_string(), "export");
723 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
724 assert_eq!(sc.words[1].0.to_string(), "a=b");
725 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
726 }
727
728 #[test]
729 fn custom_declaration_utility_glossary() {
730 #[derive(Debug)]
732 struct CustomGlossary;
733 impl crate::decl_util::Glossary for CustomGlossary {
734 fn is_declaration_utility(&self, name: &str) -> Option<bool> {
735 Some(name == "foo")
736 }
737 }
738
739 let mut lexer = Lexer::with_code("foo a=b");
740 let mut parser = Parser::config()
741 .declaration_utilities(&CustomGlossary)
742 .input(&mut lexer);
743
744 let result = parser.simple_command().now_or_never().unwrap();
745 let sc = result.unwrap().unwrap().unwrap();
746 assert_eq!(sc.assigns, []);
747 assert_eq!(sc.words.len(), 2);
748 assert_eq!(*sc.redirs, []);
749 assert_eq!(sc.words[0].0.to_string(), "foo");
750 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
751 assert_eq!(sc.words[1].0.to_string(), "a=b");
752 assert_eq!(sc.words[1].1, ExpansionMode::Single);
753 }
754
755 #[test]
756 fn assignment_is_not_considered_for_declaration_utility() {
757 #[derive(Debug)]
758 struct CustomGlossary;
759 impl crate::decl_util::Glossary for CustomGlossary {
760 fn is_declaration_utility(&self, _name: &str) -> Option<bool> {
761 unreachable!("is_declaration_utility should not be called for assignments");
762 }
763 }
764
765 let mut lexer = Lexer::with_code("a=b");
766 let mut parser = Parser::config()
767 .declaration_utilities(&CustomGlossary)
768 .input(&mut lexer);
769
770 let result = parser.simple_command().now_or_never().unwrap();
771 let sc = result.unwrap().unwrap().unwrap();
772 assert_eq!(sc.assigns.len(), 1);
773 assert_eq!(sc.words, []);
774 assert_eq!(*sc.redirs, [])
775 }
776}