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 super::lex::is_portable_name;
27use crate::syntax::Array;
28use crate::syntax::Assign;
29use crate::syntax::ExpansionMode;
30use crate::syntax::MaybeLiteral as _;
31use crate::syntax::Redir;
32use crate::syntax::Scalar;
33use crate::syntax::SimpleCommand;
34use crate::syntax::TextUnit::Literal;
35use crate::syntax::Unquote as _;
36use crate::syntax::Word;
37use crate::syntax::WordUnit::Unquoted;
38
39fn determine_expansion_mode(word: Word) -> (Word, ExpansionMode) {
49 if let Some(eq) = word.units.iter().position(|u| *u == Unquoted(Literal('=')))
50 && let Some(name) = word.units[..eq].to_string_if_literal()
51 && !name.is_empty()
52 {
53 let mut word = word;
54 word.parse_tilde_everywhere_after(eq + 1);
55 return (word, ExpansionMode::Single);
56 }
57 (word, ExpansionMode::Multiple)
58}
59
60fn ends_with_colon(word: &Word) -> bool {
69 if word.units.len() <= 1 {
70 return false;
72 }
73
74 if let Some(unit) = word.units.last()
75 && unit != &Unquoted(Literal(':'))
76 {
77 return false;
79 }
80
81 !word.unquote().1
83}
84
85#[derive(Default)]
87struct Builder {
88 assigns: Vec<Assign>,
89 words: Vec<(Word, ExpansionMode)>,
90 redirs: Vec<Redir>,
91}
92
93impl Builder {
94 fn is_empty(&self) -> bool {
95 self.assigns.is_empty() && self.words.is_empty() && self.redirs.is_empty()
96 }
97}
98
99impl From<Builder> for SimpleCommand {
100 fn from(builder: Builder) -> Self {
101 SimpleCommand {
102 assigns: builder.assigns,
103 words: builder.words,
104 redirs: builder.redirs.into(),
105 }
106 }
107}
108
109impl Parser<'_, '_> {
110 pub async fn array_values(&mut self) -> Result<Option<Vec<Word>>> {
118 if self.peek_token().await?.id != Operator(OpenParen) {
119 return Ok(None);
120 }
121
122 let opening_location = self.take_token_raw().await?.word.location;
123 let mut words = vec![];
124
125 loop {
126 let next = self.take_token_auto(&[]).await?;
127 match next.id {
128 Operator(Newline) => continue,
129 Operator(CloseParen) => break,
130 Token(_keyword) => words.push(next.word),
131 _ => {
132 return Err(Error {
133 cause: SyntaxError::UnclosedArrayValue { opening_location }.into(),
134 location: next.word.location,
135 });
136 }
137 }
138 }
139
140 Ok(Some(words))
141 }
142
143 pub async fn simple_command(&mut self) -> Result<Rec<Option<SimpleCommand>>> {
148 let mut is_declaration_utility = None;
149 let mut result = Builder::default();
150
151 loop {
152 if let Some(redir) = self.redirection().await? {
154 result.redirs.push(redir);
155 continue;
156 }
157
158 match self.peek_token().await?.id {
160 Token(Some(_keyword)) if result.is_empty() => break,
161 Token(_) => (),
162 _ => break,
163 }
164
165 let token = match self.take_token_manual(result.words.is_empty()).await? {
167 Rec::AliasSubstituted => {
168 if result.is_empty() {
169 return Ok(Rec::AliasSubstituted);
170 } else {
171 continue;
172 }
173 }
174 Rec::Parsed(token) => token,
175 };
176
177 if let Some(is_declaration_utility) = is_declaration_utility {
179 debug_assert!(!result.words.is_empty());
182
183 result.words.push(if is_declaration_utility {
184 determine_expansion_mode(token.word)
185 } else {
186 (token.word, ExpansionMode::Multiple)
187 });
188 continue;
189 }
190
191 let assign_or_word = if result.words.is_empty() {
193 Assign::try_from(token.word)
195 } else {
196 Err(token.word)
198 };
199 let mut assign = match assign_or_word {
200 Ok(assign) => assign,
201 Err(word) => {
202 debug_assert!(is_declaration_utility.is_none());
203
204 if self.mode().portable && result.is_empty() && ends_with_colon(&word) {
215 return Err(Error {
216 cause: SyntaxError::ColonSuffixedCommandName.into(),
217 location: word.location,
218 });
219 }
220
221 is_declaration_utility = self.word_names_declaration_utility(&word);
222 result.words.push((word, ExpansionMode::Multiple));
223 continue;
224 }
225 };
226
227 if self.mode().portable && !is_portable_name(&assign.name) {
228 return Err(Error {
229 cause: SyntaxError::NonPortableAssignmentName.into(),
230 location: assign.location,
231 });
232 }
233
234 let units = match &assign.value {
235 Scalar(Word { units, .. }) => units,
236 _ => panic!(
237 "Assign::try_from produced a non-scalar value {:?}",
238 assign.value
239 ),
240 };
241
242 if units.is_empty()
244 && !self.has_blank().await?
245 && let Some(words) = self.array_values().await?
246 {
247 if self.mode().portable {
248 let mut location = assign.location;
249 location.range.end = self.location().await?.range.start;
250 return Err(Error {
251 cause: SyntaxError::ArrayAssignment.into(),
252 location,
253 });
254 }
255 assign.value = Array(words);
256 }
257
258 result.assigns.push(assign);
259 }
260
261 Ok(Rec::Parsed((!result.is_empty()).then(|| result.into())))
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::super::error::ErrorCause;
268 use super::super::lex::Lexer;
269 use super::super::lex::TokenId::EndOfInput;
270 use super::*;
271 use crate::decl_util::EmptyGlossary;
272 use crate::source::Source;
273 use crate::syntax::RedirBody;
274 use crate::syntax::RedirOp;
275 use crate::syntax::TextUnit;
276 use crate::syntax::WordUnit;
277 use assert_matches::assert_matches;
278 use futures_util::FutureExt as _;
279
280 #[test]
281 fn determine_expansion_mode_empty_name() {
282 let in_word = "=".parse::<Word>().unwrap();
283 let (out_word, mode) = determine_expansion_mode(in_word.clone());
284 assert_eq!(out_word, in_word);
285 assert_eq!(mode, ExpansionMode::Multiple);
286 }
287
288 #[test]
289 fn determine_expansion_mode_nonempty_name() {
290 let in_word = "foo=".parse::<Word>().unwrap();
291 let (out_word, mode) = determine_expansion_mode(in_word.clone());
292 assert_eq!(out_word, in_word);
293 assert_eq!(mode, ExpansionMode::Single);
294 }
295
296 #[test]
297 fn determine_expansion_mode_non_literal_name() {
298 let in_word = "${X}=".parse::<Word>().unwrap();
299 let (out_word, mode) = determine_expansion_mode(in_word.clone());
300 assert_eq!(out_word, in_word);
301 assert_eq!(mode, ExpansionMode::Multiple);
302 }
303
304 #[test]
305 fn determine_expansion_mode_tilde_expansions_after_equal() {
306 let word = "~=~:~b".parse().unwrap();
307 let (word, mode) = determine_expansion_mode(word);
308 assert_eq!(
309 word.units,
310 [
311 WordUnit::Unquoted(TextUnit::Literal('~')),
312 WordUnit::Unquoted(TextUnit::Literal('=')),
313 WordUnit::Tilde {
314 name: "".to_string(),
315 followed_by_slash: false
316 },
317 WordUnit::Unquoted(TextUnit::Literal(':')),
318 WordUnit::Tilde {
319 name: "b".to_string(),
320 followed_by_slash: false
321 },
322 ]
323 );
324 assert_eq!(mode, ExpansionMode::Single);
325 }
326
327 #[test]
328 fn parser_array_values_no_open_parenthesis() {
329 let mut lexer = Lexer::with_code(")");
330 let mut parser = Parser::new(&mut lexer);
331 let result = parser.array_values().now_or_never().unwrap().unwrap();
332 assert_eq!(result, None);
333 }
334
335 #[test]
336 fn parser_array_values_empty() {
337 let mut lexer = Lexer::with_code("()");
338 let mut parser = Parser::new(&mut lexer);
339 let result = parser.array_values().now_or_never().unwrap();
340 let words = result.unwrap().unwrap();
341 assert_eq!(words, []);
342
343 let next = parser.peek_token().now_or_never().unwrap().unwrap();
344 assert_eq!(next.id, EndOfInput);
345 }
346
347 #[test]
348 fn parser_array_values_many() {
349 let mut lexer = Lexer::with_code("(a b c)");
350 let mut parser = Parser::new(&mut lexer);
351 let result = parser.array_values().now_or_never().unwrap();
352 let words = result.unwrap().unwrap();
353 assert_eq!(words.len(), 3);
354 assert_eq!(words[0].to_string(), "a");
355 assert_eq!(words[1].to_string(), "b");
356 assert_eq!(words[2].to_string(), "c");
357 }
358
359 #[test]
360 fn parser_array_values_newlines_and_comments() {
361 let mut lexer = Lexer::with_code(
362 "(
363 a # b
364 c d
365 )",
366 );
367 let mut parser = Parser::new(&mut lexer);
368 let result = parser.array_values().now_or_never().unwrap();
369 let words = result.unwrap().unwrap();
370 assert_eq!(words.len(), 3);
371 assert_eq!(words[0].to_string(), "a");
372 assert_eq!(words[1].to_string(), "c");
373 assert_eq!(words[2].to_string(), "d");
374 }
375
376 #[test]
377 fn parser_array_values_unclosed() {
378 let mut lexer = Lexer::with_code("(a b");
379 let mut parser = Parser::new(&mut lexer);
380 let e = parser.array_values().now_or_never().unwrap().unwrap_err();
381 assert_matches!(e.cause,
382 ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
383 assert_eq!(*opening_location.code.value.borrow(), "(a b");
384 assert_eq!(opening_location.code.start_line_number.get(), 1);
385 assert_eq!(*opening_location.code.source, Source::Unknown);
386 assert_eq!(opening_location.range, 0..1);
387 });
388 assert_eq!(*e.location.code.value.borrow(), "(a b");
389 assert_eq!(e.location.code.start_line_number.get(), 1);
390 assert_eq!(*e.location.code.source, Source::Unknown);
391 assert_eq!(e.location.range, 4..4);
392 }
393
394 #[test]
395 fn parser_array_values_invalid_word() {
396 let mut lexer = Lexer::with_code("(a;b)");
397 let mut parser = Parser::new(&mut lexer);
398 let e = parser.array_values().now_or_never().unwrap().unwrap_err();
399 assert_matches!(e.cause,
400 ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
401 assert_eq!(*opening_location.code.value.borrow(), "(a;b)");
402 assert_eq!(opening_location.code.start_line_number.get(), 1);
403 assert_eq!(*opening_location.code.source, Source::Unknown);
404 assert_eq!(opening_location.range, 0..1);
405 });
406 assert_eq!(*e.location.code.value.borrow(), "(a;b)");
407 assert_eq!(e.location.code.start_line_number.get(), 1);
408 assert_eq!(*e.location.code.source, Source::Unknown);
409 assert_eq!(e.location.range, 2..3);
410 }
411
412 #[test]
413 fn parser_simple_command_eof() {
414 let mut lexer = Lexer::with_code("");
415 let mut parser = Parser::new(&mut lexer);
416
417 let result = parser.simple_command().now_or_never().unwrap();
418 assert_eq!(result, Ok(Rec::Parsed(None)));
419 }
420
421 #[test]
422 fn parser_simple_command_keyword() {
423 let mut lexer = Lexer::with_code("then");
424 let mut parser = Parser::new(&mut lexer);
425
426 let result = parser.simple_command().now_or_never().unwrap();
427 assert_eq!(result, Ok(Rec::Parsed(None)));
428 }
429
430 #[test]
431 fn parser_simple_command_one_assignment() {
432 let mut lexer = Lexer::with_code("my=assignment");
433 let mut parser = Parser::new(&mut lexer);
434
435 let result = parser.simple_command().now_or_never().unwrap();
436 let sc = result.unwrap().unwrap().unwrap();
437 assert_eq!(sc.words, []);
438 assert_eq!(*sc.redirs, []);
439 assert_eq!(sc.assigns.len(), 1);
440 assert_eq!(sc.assigns[0].name, "my");
441 assert_eq!(sc.assigns[0].value.to_string(), "assignment");
442 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "my=assignment");
443 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
444 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
445 assert_eq!(sc.assigns[0].location.range, 0..13);
446 }
447
448 #[test]
449 fn parser_simple_command_many_assignments() {
450 let mut lexer = Lexer::with_code("a= b=! c=X");
451 let mut parser = Parser::new(&mut lexer);
452
453 let result = parser.simple_command().now_or_never().unwrap();
454 let sc = result.unwrap().unwrap().unwrap();
455 assert_eq!(sc.words, []);
456 assert_eq!(*sc.redirs, []);
457 assert_eq!(sc.assigns.len(), 3);
458 assert_eq!(sc.assigns[0].name, "a");
459 assert_eq!(sc.assigns[0].value.to_string(), "");
460 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= b=! c=X");
461 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
462 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
463 assert_eq!(sc.assigns[0].location.range, 0..2);
464 assert_eq!(sc.assigns[1].name, "b");
465 assert_eq!(sc.assigns[1].value.to_string(), "!");
466 assert_eq!(*sc.assigns[1].location.code.value.borrow(), "a= b=! c=X");
467 assert_eq!(sc.assigns[1].location.code.start_line_number.get(), 1);
468 assert_eq!(*sc.assigns[1].location.code.source, Source::Unknown);
469 assert_eq!(sc.assigns[1].location.range, 3..6);
470 assert_eq!(sc.assigns[2].name, "c");
471 assert_eq!(sc.assigns[2].value.to_string(), "X");
472 assert_eq!(*sc.assigns[2].location.code.value.borrow(), "a= b=! c=X");
473 assert_eq!(sc.assigns[2].location.code.start_line_number.get(), 1);
474 assert_eq!(*sc.assigns[2].location.code.source, Source::Unknown);
475 assert_eq!(sc.assigns[2].location.range, 7..10);
476 }
477
478 #[test]
479 fn parser_simple_command_one_word() {
480 let mut lexer = Lexer::with_code("word");
481 let mut parser = Parser::new(&mut lexer);
482
483 let result = parser.simple_command().now_or_never().unwrap();
484 let sc = result.unwrap().unwrap().unwrap();
485 assert_eq!(sc.assigns, []);
486 assert_eq!(*sc.redirs, []);
487 assert_eq!(sc.words.len(), 1);
488 assert_eq!(sc.words[0].0.to_string(), "word");
489 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
490 }
491
492 #[test]
493 fn parser_simple_command_many_words() {
494 let mut lexer = Lexer::with_code(": if then");
495 let mut parser = Parser::new(&mut lexer);
496
497 let result = parser.simple_command().now_or_never().unwrap();
498 let sc = result.unwrap().unwrap().unwrap();
499 assert_eq!(sc.assigns, []);
500 assert_eq!(*sc.redirs, []);
501 assert_eq!(sc.words.len(), 3);
502 assert_eq!(sc.words[0].0.to_string(), ":");
503 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
504 assert_eq!(sc.words[1].0.to_string(), "if");
505 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
506 assert_eq!(sc.words[2].0.to_string(), "then");
507 assert_eq!(sc.words[2].1, ExpansionMode::Multiple);
508 }
509
510 #[test]
511 fn parser_simple_command_one_redirection() {
512 let mut lexer = Lexer::with_code("<foo");
513 let mut parser = Parser::new(&mut lexer);
514
515 let result = parser.simple_command().now_or_never().unwrap();
516 let sc = result.unwrap().unwrap().unwrap();
517 assert_eq!(sc.assigns, []);
518 assert_eq!(sc.words, []);
519 assert_eq!(sc.redirs.len(), 1);
520 assert_eq!(sc.redirs[0].fd, None);
521 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
522 assert_eq!(operator, &RedirOp::FileIn);
523 assert_eq!(operand.to_string(), "foo")
524 });
525
526 let next = parser.peek_token().now_or_never().unwrap().unwrap();
527 assert_eq!(next.id, EndOfInput);
528 }
529
530 #[test]
531 fn parser_simple_command_many_redirections() {
532 let mut lexer = Lexer::with_code("<one >two >>three");
533 let mut parser = Parser::new(&mut lexer);
534
535 let result = parser.simple_command().now_or_never().unwrap();
536 let sc = result.unwrap().unwrap().unwrap();
537 assert_eq!(sc.assigns, []);
538 assert_eq!(sc.words, []);
539 assert_eq!(sc.redirs.len(), 3);
540 assert_eq!(sc.redirs[0].fd, None);
541 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
542 assert_eq!(operator, &RedirOp::FileIn);
543 assert_eq!(operand.to_string(), "one")
544 });
545 assert_eq!(sc.redirs[1].fd, None);
546 assert_matches!(sc.redirs[1].body, RedirBody::Normal { ref operator, ref operand } => {
547 assert_eq!(operator, &RedirOp::FileOut);
548 assert_eq!(operand.to_string(), "two")
549 });
550 assert_eq!(sc.redirs[2].fd, None);
551 assert_matches!(sc.redirs[2].body, RedirBody::Normal { ref operator, ref operand } => {
552 assert_eq!(operator, &RedirOp::FileAppend);
553 assert_eq!(operand.to_string(), "three")
554 });
555
556 let next = parser.peek_token().now_or_never().unwrap().unwrap();
557 assert_eq!(next.id, EndOfInput);
558 }
559
560 #[test]
561 fn parser_simple_command_assignment_word() {
562 let mut lexer = Lexer::with_code("if=then else");
563 let mut parser = Parser::new(&mut lexer);
564
565 let result = parser.simple_command().now_or_never().unwrap();
566 let sc = result.unwrap().unwrap().unwrap();
567 assert_eq!(*sc.redirs, []);
568 assert_eq!(sc.assigns.len(), 1);
569 assert_eq!(sc.words.len(), 1);
570 assert_eq!(sc.assigns[0].name, "if");
571 assert_eq!(sc.assigns[0].value.to_string(), "then");
572 assert_eq!(sc.words[0].0.to_string(), "else");
573 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
574 }
575
576 #[test]
577 fn parser_simple_command_word_redirection() {
578 let mut lexer = Lexer::with_code("word <redirection");
579 let mut parser = Parser::new(&mut lexer);
580
581 let result = parser.simple_command().now_or_never().unwrap();
582 let sc = result.unwrap().unwrap().unwrap();
583 assert_eq!(sc.assigns, []);
584 assert_eq!(sc.words.len(), 1);
585 assert_eq!(sc.redirs.len(), 1);
586 assert_eq!(sc.words[0].0.to_string(), "word");
587 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
588 assert_eq!(sc.redirs[0].fd, None);
589 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
590 assert_eq!(operator, &RedirOp::FileIn);
591 assert_eq!(operand.to_string(), "redirection")
592 });
593 }
594
595 #[test]
596 fn parser_simple_command_redirection_assignment() {
597 let mut lexer = Lexer::with_code("<foo a=b");
598 let mut parser = Parser::new(&mut lexer);
599
600 let result = parser.simple_command().now_or_never().unwrap();
601 let sc = result.unwrap().unwrap().unwrap();
602 assert_eq!(sc.words, []);
603 assert_eq!(sc.assigns.len(), 1);
604 assert_eq!(sc.redirs.len(), 1);
605 assert_eq!(sc.assigns[0].name, "a");
606 assert_eq!(sc.assigns[0].value.to_string(), "b");
607 assert_eq!(sc.redirs[0].fd, None);
608 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
609 assert_eq!(operator, &RedirOp::FileIn);
610 assert_eq!(operand.to_string(), "foo")
611 });
612 }
613
614 #[test]
615 fn parser_simple_command_assignment_redirection_word() {
616 let mut lexer = Lexer::with_code("if=then <foo else");
617 let mut parser = Parser::new(&mut lexer);
618
619 let result = parser.simple_command().now_or_never().unwrap();
620 let sc = result.unwrap().unwrap().unwrap();
621 assert_eq!(sc.assigns.len(), 1);
622 assert_eq!(sc.words.len(), 1);
623 assert_eq!(sc.redirs.len(), 1);
624 assert_eq!(sc.assigns[0].name, "if");
625 assert_eq!(sc.assigns[0].value.to_string(), "then");
626 assert_eq!(sc.words[0].0.to_string(), "else");
627 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
628 assert_eq!(sc.redirs[0].fd, None);
629 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
630 assert_eq!(operator, &RedirOp::FileIn);
631 assert_eq!(operand.to_string(), "foo")
632 });
633 }
634
635 #[test]
636 fn parser_simple_command_array_assignment() {
637 let mut lexer = Lexer::with_code("a=()");
638 let mut parser = Parser::new(&mut lexer);
639
640 let result = parser.simple_command().now_or_never().unwrap();
641 let sc = result.unwrap().unwrap().unwrap();
642 assert_eq!(sc.assigns.len(), 1);
643 assert_eq!(sc.words, []);
644 assert_eq!(*sc.redirs, []);
645 assert_eq!(sc.assigns[0].name, "a");
646 assert_matches!(&sc.assigns[0].value, Array(words) => {
647 assert_eq!(words, &[]);
648 });
649
650 let next = parser.peek_token().now_or_never().unwrap().unwrap();
651 assert_eq!(next.id, EndOfInput);
652 }
653
654 #[test]
655 fn parser_simple_command_empty_assignment_followed_by_blank_and_parenthesis() {
656 let mut lexer = Lexer::with_code("a= ()");
657 let mut parser = Parser::new(&mut lexer);
658
659 let result = parser.simple_command().now_or_never().unwrap();
660 let sc = result.unwrap().unwrap().unwrap();
661 assert_eq!(sc.assigns.len(), 1);
662 assert_eq!(sc.words, []);
663 assert_eq!(*sc.redirs, []);
664 assert_eq!(sc.assigns[0].name, "a");
665 assert_eq!(sc.assigns[0].value.to_string(), "");
666 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= ()");
667 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
668 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
669 assert_eq!(sc.assigns[0].location.range, 0..2);
670
671 let next = parser.peek_token().now_or_never().unwrap().unwrap();
672 assert_eq!(next.id, Operator(OpenParen));
673 }
674
675 #[test]
676 fn parser_simple_command_non_empty_assignment_followed_by_parenthesis() {
677 let mut lexer = Lexer::with_code("a=b()");
678 let mut parser = Parser::new(&mut lexer);
679
680 let result = parser.simple_command().now_or_never().unwrap();
681 let sc = result.unwrap().unwrap().unwrap();
682 assert_eq!(sc.assigns.len(), 1);
683 assert_eq!(sc.words, []);
684 assert_eq!(*sc.redirs, []);
685 assert_eq!(sc.assigns[0].name, "a");
686 assert_eq!(sc.assigns[0].value.to_string(), "b");
687 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a=b()");
688 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
689 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
690 assert_eq!(sc.assigns[0].location.range, 0..3);
691
692 let next = parser.peek_token().now_or_never().unwrap().unwrap();
693 assert_eq!(next.id, Operator(OpenParen));
694 }
695
696 #[test]
697 fn word_with_single_expansion_mode_in_declaration_utility() {
698 let mut lexer = Lexer::with_code("export a=b");
701 let mut parser = Parser::new(&mut lexer);
702
703 let result = parser.simple_command().now_or_never().unwrap();
704 let sc = result.unwrap().unwrap().unwrap();
705 assert_eq!(sc.assigns, []);
706 assert_eq!(sc.words.len(), 2);
707 assert_eq!(*sc.redirs, []);
708 assert_eq!(sc.words[0].0.to_string(), "export");
709 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
710 assert_eq!(sc.words[1].0.to_string(), "a=b");
711 assert_eq!(sc.words[1].1, ExpansionMode::Single);
712 }
713
714 #[test]
715 fn word_with_multiple_expansion_mode_in_declaration_utility() {
716 let mut lexer = Lexer::with_code("export foo");
719 let mut parser = Parser::new(&mut lexer);
720
721 let result = parser.simple_command().now_or_never().unwrap();
722 let sc = result.unwrap().unwrap().unwrap();
723 assert_eq!(sc.assigns, []);
724 assert_eq!(sc.words.len(), 2);
725 assert_eq!(*sc.redirs, []);
726 assert_eq!(sc.words[0].0.to_string(), "export");
727 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
728 assert_eq!(sc.words[1].0.to_string(), "foo");
729 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
730 }
731
732 #[test]
733 fn word_with_multiple_expansion_mode_in_non_declaration_utility() {
734 let mut lexer = Lexer::with_code("foo a=b");
737 let mut parser = Parser::new(&mut lexer);
738
739 let result = parser.simple_command().now_or_never().unwrap();
740 let sc = result.unwrap().unwrap().unwrap();
741 assert_eq!(sc.assigns, []);
742 assert_eq!(sc.words.len(), 2);
743 assert_eq!(*sc.redirs, []);
744 assert_eq!(sc.words[0].0.to_string(), "foo");
745 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
746 assert_eq!(sc.words[1].0.to_string(), "a=b");
747 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
748 }
749
750 #[test]
751 fn declaration_utility_determined_by_non_first_word() {
752 let mut lexer = Lexer::with_code("command command export foo a=b");
755 let mut parser = Parser::new(&mut lexer);
756 let result = parser.simple_command().now_or_never().unwrap();
757 let sc = result.unwrap().unwrap().unwrap();
758 assert_eq!(sc.words[4].0.to_string(), "a=b");
759 assert_eq!(sc.words[4].1, ExpansionMode::Single);
760
761 let mut lexer = Lexer::with_code("command command foo export a=b");
762 let mut parser = Parser::new(&mut lexer);
763 let result = parser.simple_command().now_or_never().unwrap();
764 let sc = result.unwrap().unwrap().unwrap();
765 assert_eq!(sc.words[4].0.to_string(), "a=b");
766 assert_eq!(sc.words[4].1, ExpansionMode::Multiple);
767 }
768
769 #[test]
770 fn no_declaration_utilities_with_empty_glossary() {
771 let mut lexer = Lexer::with_code("export a=b");
773 let mut parser = Parser::config()
774 .declaration_utilities(&EmptyGlossary)
775 .input(&mut lexer);
776
777 let result = parser.simple_command().now_or_never().unwrap();
778 let sc = result.unwrap().unwrap().unwrap();
779 assert_eq!(sc.assigns, []);
780 assert_eq!(sc.words.len(), 2);
781 assert_eq!(*sc.redirs, []);
782 assert_eq!(sc.words[0].0.to_string(), "export");
783 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
784 assert_eq!(sc.words[1].0.to_string(), "a=b");
785 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
786 }
787
788 #[test]
789 fn custom_declaration_utility_glossary() {
790 #[derive(Debug)]
792 struct CustomGlossary;
793 impl crate::decl_util::Glossary for CustomGlossary {
794 fn is_declaration_utility(&self, name: &str) -> Option<bool> {
795 Some(name == "foo")
796 }
797 }
798
799 let mut lexer = Lexer::with_code("foo a=b");
800 let mut parser = Parser::config()
801 .declaration_utilities(&CustomGlossary)
802 .input(&mut lexer);
803
804 let result = parser.simple_command().now_or_never().unwrap();
805 let sc = result.unwrap().unwrap().unwrap();
806 assert_eq!(sc.assigns, []);
807 assert_eq!(sc.words.len(), 2);
808 assert_eq!(*sc.redirs, []);
809 assert_eq!(sc.words[0].0.to_string(), "foo");
810 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
811 assert_eq!(sc.words[1].0.to_string(), "a=b");
812 assert_eq!(sc.words[1].1, ExpansionMode::Single);
813 }
814
815 fn portable_mode() -> yash_env::parser::Mode {
816 let mut mode = yash_env::parser::Mode::default();
817 mode.portable = true;
818 mode
819 }
820
821 #[test]
822 fn command_name_ending_with_colon_rejected_in_portable_mode() {
823 let mut lexer = Lexer::with_code("$foo:");
824 lexer.set_mode(portable_mode());
825 let mut parser = Parser::new(&mut lexer);
826
827 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
828 assert_eq!(
829 e.cause,
830 ErrorCause::Syntax(SyntaxError::ColonSuffixedCommandName)
831 );
832 assert_eq!(*e.location.code.value.borrow(), "$foo:");
833 assert_eq!(e.location.range, 0..5);
834 }
835
836 #[test]
837 fn lone_colon_command_name_accepted_in_portable_mode() {
838 let mut lexer = Lexer::with_code(":");
840 lexer.set_mode(portable_mode());
841 let mut parser = Parser::new(&mut lexer);
842
843 let result = parser.simple_command().now_or_never().unwrap();
844 let sc = result.unwrap().unwrap().unwrap();
845 assert_eq!(sc.words.len(), 1);
846 assert_eq!(sc.words[0].0.to_string(), ":");
847 }
848
849 #[test]
850 fn command_name_ending_with_colon_accepted_without_portable_mode() {
851 let mut lexer = Lexer::with_code("$foo:");
852 let mut parser = Parser::new(&mut lexer);
853
854 let result = parser.simple_command().now_or_never().unwrap();
855 let sc = result.unwrap().unwrap().unwrap();
856 assert_eq!(sc.words.len(), 1);
857 assert_eq!(sc.words[0].0.to_string(), "$foo:");
858 }
859
860 #[test]
861 fn argument_ending_with_colon_accepted_in_portable_mode() {
862 let mut lexer = Lexer::with_code("echo foo:");
864 lexer.set_mode(portable_mode());
865 let mut parser = Parser::new(&mut lexer);
866
867 let result = parser.simple_command().now_or_never().unwrap();
868 let sc = result.unwrap().unwrap().unwrap();
869 assert_eq!(sc.words.len(), 2);
870 assert_eq!(sc.words[0].0.to_string(), "echo");
871 assert_eq!(sc.words[1].0.to_string(), "foo:");
872 }
873
874 #[test]
875 fn command_name_ending_with_colon_after_assignment_accepted_in_portable_mode() {
876 let mut lexer = Lexer::with_code("a=b foo:");
878 lexer.set_mode(portable_mode());
879 let mut parser = Parser::new(&mut lexer);
880
881 let result = parser.simple_command().now_or_never().unwrap();
882 let sc = result.unwrap().unwrap().unwrap();
883 assert_eq!(sc.assigns.len(), 1);
884 assert_eq!(sc.words.len(), 1);
885 assert_eq!(sc.words[0].0.to_string(), "foo:");
886 }
887
888 #[test]
889 fn quoted_colon_suffix_command_name_accepted_in_portable_mode() {
890 let mut lexer = Lexer::with_code(r"foo\:");
892 lexer.set_mode(portable_mode());
893 let mut parser = Parser::new(&mut lexer);
894
895 let result = parser.simple_command().now_or_never().unwrap();
896 let sc = result.unwrap().unwrap().unwrap();
897 assert_eq!(sc.words.len(), 1);
898 assert_eq!(sc.words[0].0.to_string(), r"foo\:");
899 }
900
901 #[test]
902 fn assignment_value_ending_with_colon_accepted_in_portable_mode() {
903 let mut lexer = Lexer::with_code("a=b:");
905 lexer.set_mode(portable_mode());
906 let mut parser = Parser::new(&mut lexer);
907
908 let result = parser.simple_command().now_or_never().unwrap();
909 let sc = result.unwrap().unwrap().unwrap();
910 assert_eq!(sc.assigns.len(), 1);
911 assert_eq!(sc.assigns[0].name, "a");
912 assert_eq!(sc.assigns[0].value.to_string(), "b:");
913 }
914
915 #[test]
916 fn assignment_name_starting_with_digit_rejected_in_portable_mode() {
917 let mut lexer = Lexer::with_code("1a=b");
918 lexer.set_mode(portable_mode());
919 let mut parser = Parser::new(&mut lexer);
920
921 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
922 assert_eq!(
923 e.cause,
924 ErrorCause::Syntax(SyntaxError::NonPortableAssignmentName)
925 );
926 assert_eq!(*e.location.code.value.borrow(), "1a=b");
927 assert_eq!(e.location.range, 0..4);
928 }
929
930 #[test]
931 fn assignment_name_with_non_portable_character_rejected_in_portable_mode() {
932 let mut lexer = Lexer::with_code("a.b=c");
933 lexer.set_mode(portable_mode());
934 let mut parser = Parser::new(&mut lexer);
935
936 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
937 assert_eq!(
938 e.cause,
939 ErrorCause::Syntax(SyntaxError::NonPortableAssignmentName)
940 );
941 }
942
943 #[test]
944 fn array_assignment_name_starting_with_digit_rejected_in_portable_mode() {
945 let mut lexer = Lexer::with_code("1a=(b c)");
946 lexer.set_mode(portable_mode());
947 let mut parser = Parser::new(&mut lexer);
948
949 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
950 assert_eq!(
951 e.cause,
952 ErrorCause::Syntax(SyntaxError::NonPortableAssignmentName)
953 );
954 }
955
956 #[test]
957 fn assignment_portable_name_allowed_in_portable_mode() {
958 let mut lexer = Lexer::with_code("_Az9=b");
959 lexer.set_mode(portable_mode());
960 let mut parser = Parser::new(&mut lexer);
961
962 let result = parser.simple_command().now_or_never().unwrap();
963 let sc = result.unwrap().unwrap().unwrap();
964 assert_eq!(sc.assigns.len(), 1);
965 assert_eq!(sc.assigns[0].name, "_Az9");
966 assert_eq!(sc.assigns[0].value.to_string(), "b");
967 }
968
969 #[test]
970 fn assignment_non_portable_name_allowed_without_portable_mode() {
971 let mut lexer = Lexer::with_code("1a=b");
972 let mut parser = Parser::new(&mut lexer);
973
974 let result = parser.simple_command().now_or_never().unwrap();
975 let sc = result.unwrap().unwrap().unwrap();
976 assert_eq!(sc.assigns.len(), 1);
977 assert_eq!(sc.assigns[0].name, "1a");
978 assert_eq!(sc.assigns[0].value.to_string(), "b");
979 }
980
981 #[test]
982 fn array_assignment_rejected_in_portable_mode() {
983 let mut lexer = Lexer::with_code("a=(b c)");
984 lexer.set_mode(portable_mode());
985 let mut parser = Parser::new(&mut lexer);
986
987 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
988 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::ArrayAssignment));
989 assert_eq!(*e.location.code.value.borrow(), "a=(b c)");
990 assert_eq!(e.location.range, 0..7);
991 }
992
993 #[test]
994 fn empty_array_assignment_rejected_in_portable_mode() {
995 let mut lexer = Lexer::with_code("a=()");
996 lexer.set_mode(portable_mode());
997 let mut parser = Parser::new(&mut lexer);
998
999 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
1000 assert_eq!(e.cause, ErrorCause::Syntax(SyntaxError::ArrayAssignment));
1001 assert_eq!(*e.location.code.value.borrow(), "a=()");
1002 assert_eq!(e.location.range, 0..4);
1003 }
1004
1005 #[test]
1006 fn array_assignment_allowed_without_portable_mode() {
1007 let mut lexer = Lexer::with_code("a=(b c)");
1008 let mut parser = Parser::new(&mut lexer);
1009
1010 let result = parser.simple_command().now_or_never().unwrap();
1011 let sc = result.unwrap().unwrap().unwrap();
1012 assert_eq!(sc.assigns.len(), 1);
1013 assert_eq!(sc.assigns[0].name, "a");
1014 assert_matches!(&sc.assigns[0].value, Array(words) => {
1015 assert_eq!(words.len(), 2);
1016 assert_eq!(words[0].to_string(), "b");
1017 assert_eq!(words[1].to_string(), "c");
1018 });
1019 }
1020
1021 #[test]
1022 fn assignment_is_not_considered_for_declaration_utility() {
1023 #[derive(Debug)]
1024 struct CustomGlossary;
1025 impl crate::decl_util::Glossary for CustomGlossary {
1026 fn is_declaration_utility(&self, _name: &str) -> Option<bool> {
1027 unreachable!("is_declaration_utility should not be called for assignments");
1028 }
1029 }
1030
1031 let mut lexer = Lexer::with_code("a=b");
1032 let mut parser = Parser::config()
1033 .declaration_utilities(&CustomGlossary)
1034 .input(&mut lexer);
1035
1036 let result = parser.simple_command().now_or_never().unwrap();
1037 let sc = result.unwrap().unwrap().unwrap();
1038 assert_eq!(sc.assigns.len(), 1);
1039 assert_eq!(sc.words, []);
1040 assert_eq!(*sc.redirs, [])
1041 }
1042}