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()
245 && !self.has_blank().await?
246 && let Some(words) = self.array_values().await?
247 {
248 assign.value = Array(words);
249 }
250
251 result.assigns.push(assign);
252 }
253
254 Ok(Rec::Parsed((!result.is_empty()).then(|| result.into())))
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::super::error::ErrorCause;
261 use super::super::lex::Lexer;
262 use super::super::lex::TokenId::EndOfInput;
263 use super::*;
264 use crate::decl_util::EmptyGlossary;
265 use crate::source::Source;
266 use crate::syntax::RedirBody;
267 use crate::syntax::RedirOp;
268 use crate::syntax::TextUnit;
269 use crate::syntax::WordUnit;
270 use assert_matches::assert_matches;
271 use futures_util::FutureExt as _;
272
273 #[test]
274 fn determine_expansion_mode_empty_name() {
275 let in_word = "=".parse::<Word>().unwrap();
276 let (out_word, mode) = determine_expansion_mode(in_word.clone());
277 assert_eq!(out_word, in_word);
278 assert_eq!(mode, ExpansionMode::Multiple);
279 }
280
281 #[test]
282 fn determine_expansion_mode_nonempty_name() {
283 let in_word = "foo=".parse::<Word>().unwrap();
284 let (out_word, mode) = determine_expansion_mode(in_word.clone());
285 assert_eq!(out_word, in_word);
286 assert_eq!(mode, ExpansionMode::Single);
287 }
288
289 #[test]
290 fn determine_expansion_mode_non_literal_name() {
291 let in_word = "${X}=".parse::<Word>().unwrap();
292 let (out_word, mode) = determine_expansion_mode(in_word.clone());
293 assert_eq!(out_word, in_word);
294 assert_eq!(mode, ExpansionMode::Multiple);
295 }
296
297 #[test]
298 fn determine_expansion_mode_tilde_expansions_after_equal() {
299 let word = "~=~:~b".parse().unwrap();
300 let (word, mode) = determine_expansion_mode(word);
301 assert_eq!(
302 word.units,
303 [
304 WordUnit::Unquoted(TextUnit::Literal('~')),
305 WordUnit::Unquoted(TextUnit::Literal('=')),
306 WordUnit::Tilde {
307 name: "".to_string(),
308 followed_by_slash: false
309 },
310 WordUnit::Unquoted(TextUnit::Literal(':')),
311 WordUnit::Tilde {
312 name: "b".to_string(),
313 followed_by_slash: false
314 },
315 ]
316 );
317 assert_eq!(mode, ExpansionMode::Single);
318 }
319
320 #[test]
321 fn parser_array_values_no_open_parenthesis() {
322 let mut lexer = Lexer::with_code(")");
323 let mut parser = Parser::new(&mut lexer);
324 let result = parser.array_values().now_or_never().unwrap().unwrap();
325 assert_eq!(result, None);
326 }
327
328 #[test]
329 fn parser_array_values_empty() {
330 let mut lexer = Lexer::with_code("()");
331 let mut parser = Parser::new(&mut lexer);
332 let result = parser.array_values().now_or_never().unwrap();
333 let words = result.unwrap().unwrap();
334 assert_eq!(words, []);
335
336 let next = parser.peek_token().now_or_never().unwrap().unwrap();
337 assert_eq!(next.id, EndOfInput);
338 }
339
340 #[test]
341 fn parser_array_values_many() {
342 let mut lexer = Lexer::with_code("(a b c)");
343 let mut parser = Parser::new(&mut lexer);
344 let result = parser.array_values().now_or_never().unwrap();
345 let words = result.unwrap().unwrap();
346 assert_eq!(words.len(), 3);
347 assert_eq!(words[0].to_string(), "a");
348 assert_eq!(words[1].to_string(), "b");
349 assert_eq!(words[2].to_string(), "c");
350 }
351
352 #[test]
353 fn parser_array_values_newlines_and_comments() {
354 let mut lexer = Lexer::with_code(
355 "(
356 a # b
357 c d
358 )",
359 );
360 let mut parser = Parser::new(&mut lexer);
361 let result = parser.array_values().now_or_never().unwrap();
362 let words = result.unwrap().unwrap();
363 assert_eq!(words.len(), 3);
364 assert_eq!(words[0].to_string(), "a");
365 assert_eq!(words[1].to_string(), "c");
366 assert_eq!(words[2].to_string(), "d");
367 }
368
369 #[test]
370 fn parser_array_values_unclosed() {
371 let mut lexer = Lexer::with_code("(a b");
372 let mut parser = Parser::new(&mut lexer);
373 let e = parser.array_values().now_or_never().unwrap().unwrap_err();
374 assert_matches!(e.cause,
375 ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
376 assert_eq!(*opening_location.code.value.borrow(), "(a b");
377 assert_eq!(opening_location.code.start_line_number.get(), 1);
378 assert_eq!(*opening_location.code.source, Source::Unknown);
379 assert_eq!(opening_location.range, 0..1);
380 });
381 assert_eq!(*e.location.code.value.borrow(), "(a b");
382 assert_eq!(e.location.code.start_line_number.get(), 1);
383 assert_eq!(*e.location.code.source, Source::Unknown);
384 assert_eq!(e.location.range, 4..4);
385 }
386
387 #[test]
388 fn parser_array_values_invalid_word() {
389 let mut lexer = Lexer::with_code("(a;b)");
390 let mut parser = Parser::new(&mut lexer);
391 let e = parser.array_values().now_or_never().unwrap().unwrap_err();
392 assert_matches!(e.cause,
393 ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
394 assert_eq!(*opening_location.code.value.borrow(), "(a;b)");
395 assert_eq!(opening_location.code.start_line_number.get(), 1);
396 assert_eq!(*opening_location.code.source, Source::Unknown);
397 assert_eq!(opening_location.range, 0..1);
398 });
399 assert_eq!(*e.location.code.value.borrow(), "(a;b)");
400 assert_eq!(e.location.code.start_line_number.get(), 1);
401 assert_eq!(*e.location.code.source, Source::Unknown);
402 assert_eq!(e.location.range, 2..3);
403 }
404
405 #[test]
406 fn parser_simple_command_eof() {
407 let mut lexer = Lexer::with_code("");
408 let mut parser = Parser::new(&mut lexer);
409
410 let result = parser.simple_command().now_or_never().unwrap();
411 assert_eq!(result, Ok(Rec::Parsed(None)));
412 }
413
414 #[test]
415 fn parser_simple_command_keyword() {
416 let mut lexer = Lexer::with_code("then");
417 let mut parser = Parser::new(&mut lexer);
418
419 let result = parser.simple_command().now_or_never().unwrap();
420 assert_eq!(result, Ok(Rec::Parsed(None)));
421 }
422
423 #[test]
424 fn parser_simple_command_one_assignment() {
425 let mut lexer = Lexer::with_code("my=assignment");
426 let mut parser = Parser::new(&mut lexer);
427
428 let result = parser.simple_command().now_or_never().unwrap();
429 let sc = result.unwrap().unwrap().unwrap();
430 assert_eq!(sc.words, []);
431 assert_eq!(*sc.redirs, []);
432 assert_eq!(sc.assigns.len(), 1);
433 assert_eq!(sc.assigns[0].name, "my");
434 assert_eq!(sc.assigns[0].value.to_string(), "assignment");
435 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "my=assignment");
436 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
437 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
438 assert_eq!(sc.assigns[0].location.range, 0..13);
439 }
440
441 #[test]
442 fn parser_simple_command_many_assignments() {
443 let mut lexer = Lexer::with_code("a= b=! c=X");
444 let mut parser = Parser::new(&mut lexer);
445
446 let result = parser.simple_command().now_or_never().unwrap();
447 let sc = result.unwrap().unwrap().unwrap();
448 assert_eq!(sc.words, []);
449 assert_eq!(*sc.redirs, []);
450 assert_eq!(sc.assigns.len(), 3);
451 assert_eq!(sc.assigns[0].name, "a");
452 assert_eq!(sc.assigns[0].value.to_string(), "");
453 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= b=! c=X");
454 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
455 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
456 assert_eq!(sc.assigns[0].location.range, 0..2);
457 assert_eq!(sc.assigns[1].name, "b");
458 assert_eq!(sc.assigns[1].value.to_string(), "!");
459 assert_eq!(*sc.assigns[1].location.code.value.borrow(), "a= b=! c=X");
460 assert_eq!(sc.assigns[1].location.code.start_line_number.get(), 1);
461 assert_eq!(*sc.assigns[1].location.code.source, Source::Unknown);
462 assert_eq!(sc.assigns[1].location.range, 3..6);
463 assert_eq!(sc.assigns[2].name, "c");
464 assert_eq!(sc.assigns[2].value.to_string(), "X");
465 assert_eq!(*sc.assigns[2].location.code.value.borrow(), "a= b=! c=X");
466 assert_eq!(sc.assigns[2].location.code.start_line_number.get(), 1);
467 assert_eq!(*sc.assigns[2].location.code.source, Source::Unknown);
468 assert_eq!(sc.assigns[2].location.range, 7..10);
469 }
470
471 #[test]
472 fn parser_simple_command_one_word() {
473 let mut lexer = Lexer::with_code("word");
474 let mut parser = Parser::new(&mut lexer);
475
476 let result = parser.simple_command().now_or_never().unwrap();
477 let sc = result.unwrap().unwrap().unwrap();
478 assert_eq!(sc.assigns, []);
479 assert_eq!(*sc.redirs, []);
480 assert_eq!(sc.words.len(), 1);
481 assert_eq!(sc.words[0].0.to_string(), "word");
482 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
483 }
484
485 #[test]
486 fn parser_simple_command_many_words() {
487 let mut lexer = Lexer::with_code(": if then");
488 let mut parser = Parser::new(&mut lexer);
489
490 let result = parser.simple_command().now_or_never().unwrap();
491 let sc = result.unwrap().unwrap().unwrap();
492 assert_eq!(sc.assigns, []);
493 assert_eq!(*sc.redirs, []);
494 assert_eq!(sc.words.len(), 3);
495 assert_eq!(sc.words[0].0.to_string(), ":");
496 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
497 assert_eq!(sc.words[1].0.to_string(), "if");
498 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
499 assert_eq!(sc.words[2].0.to_string(), "then");
500 assert_eq!(sc.words[2].1, ExpansionMode::Multiple);
501 }
502
503 #[test]
504 fn parser_simple_command_one_redirection() {
505 let mut lexer = Lexer::with_code("<foo");
506 let mut parser = Parser::new(&mut lexer);
507
508 let result = parser.simple_command().now_or_never().unwrap();
509 let sc = result.unwrap().unwrap().unwrap();
510 assert_eq!(sc.assigns, []);
511 assert_eq!(sc.words, []);
512 assert_eq!(sc.redirs.len(), 1);
513 assert_eq!(sc.redirs[0].fd, None);
514 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
515 assert_eq!(operator, &RedirOp::FileIn);
516 assert_eq!(operand.to_string(), "foo")
517 });
518
519 let next = parser.peek_token().now_or_never().unwrap().unwrap();
520 assert_eq!(next.id, EndOfInput);
521 }
522
523 #[test]
524 fn parser_simple_command_many_redirections() {
525 let mut lexer = Lexer::with_code("<one >two >>three");
526 let mut parser = Parser::new(&mut lexer);
527
528 let result = parser.simple_command().now_or_never().unwrap();
529 let sc = result.unwrap().unwrap().unwrap();
530 assert_eq!(sc.assigns, []);
531 assert_eq!(sc.words, []);
532 assert_eq!(sc.redirs.len(), 3);
533 assert_eq!(sc.redirs[0].fd, None);
534 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
535 assert_eq!(operator, &RedirOp::FileIn);
536 assert_eq!(operand.to_string(), "one")
537 });
538 assert_eq!(sc.redirs[1].fd, None);
539 assert_matches!(sc.redirs[1].body, RedirBody::Normal { ref operator, ref operand } => {
540 assert_eq!(operator, &RedirOp::FileOut);
541 assert_eq!(operand.to_string(), "two")
542 });
543 assert_eq!(sc.redirs[2].fd, None);
544 assert_matches!(sc.redirs[2].body, RedirBody::Normal { ref operator, ref operand } => {
545 assert_eq!(operator, &RedirOp::FileAppend);
546 assert_eq!(operand.to_string(), "three")
547 });
548
549 let next = parser.peek_token().now_or_never().unwrap().unwrap();
550 assert_eq!(next.id, EndOfInput);
551 }
552
553 #[test]
554 fn parser_simple_command_assignment_word() {
555 let mut lexer = Lexer::with_code("if=then else");
556 let mut parser = Parser::new(&mut lexer);
557
558 let result = parser.simple_command().now_or_never().unwrap();
559 let sc = result.unwrap().unwrap().unwrap();
560 assert_eq!(*sc.redirs, []);
561 assert_eq!(sc.assigns.len(), 1);
562 assert_eq!(sc.words.len(), 1);
563 assert_eq!(sc.assigns[0].name, "if");
564 assert_eq!(sc.assigns[0].value.to_string(), "then");
565 assert_eq!(sc.words[0].0.to_string(), "else");
566 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
567 }
568
569 #[test]
570 fn parser_simple_command_word_redirection() {
571 let mut lexer = Lexer::with_code("word <redirection");
572 let mut parser = Parser::new(&mut lexer);
573
574 let result = parser.simple_command().now_or_never().unwrap();
575 let sc = result.unwrap().unwrap().unwrap();
576 assert_eq!(sc.assigns, []);
577 assert_eq!(sc.words.len(), 1);
578 assert_eq!(sc.redirs.len(), 1);
579 assert_eq!(sc.words[0].0.to_string(), "word");
580 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
581 assert_eq!(sc.redirs[0].fd, None);
582 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
583 assert_eq!(operator, &RedirOp::FileIn);
584 assert_eq!(operand.to_string(), "redirection")
585 });
586 }
587
588 #[test]
589 fn parser_simple_command_redirection_assignment() {
590 let mut lexer = Lexer::with_code("<foo a=b");
591 let mut parser = Parser::new(&mut lexer);
592
593 let result = parser.simple_command().now_or_never().unwrap();
594 let sc = result.unwrap().unwrap().unwrap();
595 assert_eq!(sc.words, []);
596 assert_eq!(sc.assigns.len(), 1);
597 assert_eq!(sc.redirs.len(), 1);
598 assert_eq!(sc.assigns[0].name, "a");
599 assert_eq!(sc.assigns[0].value.to_string(), "b");
600 assert_eq!(sc.redirs[0].fd, None);
601 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
602 assert_eq!(operator, &RedirOp::FileIn);
603 assert_eq!(operand.to_string(), "foo")
604 });
605 }
606
607 #[test]
608 fn parser_simple_command_assignment_redirection_word() {
609 let mut lexer = Lexer::with_code("if=then <foo else");
610 let mut parser = Parser::new(&mut lexer);
611
612 let result = parser.simple_command().now_or_never().unwrap();
613 let sc = result.unwrap().unwrap().unwrap();
614 assert_eq!(sc.assigns.len(), 1);
615 assert_eq!(sc.words.len(), 1);
616 assert_eq!(sc.redirs.len(), 1);
617 assert_eq!(sc.assigns[0].name, "if");
618 assert_eq!(sc.assigns[0].value.to_string(), "then");
619 assert_eq!(sc.words[0].0.to_string(), "else");
620 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
621 assert_eq!(sc.redirs[0].fd, None);
622 assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
623 assert_eq!(operator, &RedirOp::FileIn);
624 assert_eq!(operand.to_string(), "foo")
625 });
626 }
627
628 #[test]
629 fn parser_simple_command_array_assignment() {
630 let mut lexer = Lexer::with_code("a=()");
631 let mut parser = Parser::new(&mut lexer);
632
633 let result = parser.simple_command().now_or_never().unwrap();
634 let sc = result.unwrap().unwrap().unwrap();
635 assert_eq!(sc.assigns.len(), 1);
636 assert_eq!(sc.words, []);
637 assert_eq!(*sc.redirs, []);
638 assert_eq!(sc.assigns[0].name, "a");
639 assert_matches!(&sc.assigns[0].value, Array(words) => {
640 assert_eq!(words, &[]);
641 });
642
643 let next = parser.peek_token().now_or_never().unwrap().unwrap();
644 assert_eq!(next.id, EndOfInput);
645 }
646
647 #[test]
648 fn parser_simple_command_empty_assignment_followed_by_blank_and_parenthesis() {
649 let mut lexer = Lexer::with_code("a= ()");
650 let mut parser = Parser::new(&mut lexer);
651
652 let result = parser.simple_command().now_or_never().unwrap();
653 let sc = result.unwrap().unwrap().unwrap();
654 assert_eq!(sc.assigns.len(), 1);
655 assert_eq!(sc.words, []);
656 assert_eq!(*sc.redirs, []);
657 assert_eq!(sc.assigns[0].name, "a");
658 assert_eq!(sc.assigns[0].value.to_string(), "");
659 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= ()");
660 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
661 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
662 assert_eq!(sc.assigns[0].location.range, 0..2);
663
664 let next = parser.peek_token().now_or_never().unwrap().unwrap();
665 assert_eq!(next.id, Operator(OpenParen));
666 }
667
668 #[test]
669 fn parser_simple_command_non_empty_assignment_followed_by_parenthesis() {
670 let mut lexer = Lexer::with_code("a=b()");
671 let mut parser = Parser::new(&mut lexer);
672
673 let result = parser.simple_command().now_or_never().unwrap();
674 let sc = result.unwrap().unwrap().unwrap();
675 assert_eq!(sc.assigns.len(), 1);
676 assert_eq!(sc.words, []);
677 assert_eq!(*sc.redirs, []);
678 assert_eq!(sc.assigns[0].name, "a");
679 assert_eq!(sc.assigns[0].value.to_string(), "b");
680 assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a=b()");
681 assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
682 assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
683 assert_eq!(sc.assigns[0].location.range, 0..3);
684
685 let next = parser.peek_token().now_or_never().unwrap().unwrap();
686 assert_eq!(next.id, Operator(OpenParen));
687 }
688
689 #[test]
690 fn word_with_single_expansion_mode_in_declaration_utility() {
691 let mut lexer = Lexer::with_code("export a=b");
694 let mut parser = Parser::new(&mut lexer);
695
696 let result = parser.simple_command().now_or_never().unwrap();
697 let sc = result.unwrap().unwrap().unwrap();
698 assert_eq!(sc.assigns, []);
699 assert_eq!(sc.words.len(), 2);
700 assert_eq!(*sc.redirs, []);
701 assert_eq!(sc.words[0].0.to_string(), "export");
702 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
703 assert_eq!(sc.words[1].0.to_string(), "a=b");
704 assert_eq!(sc.words[1].1, ExpansionMode::Single);
705 }
706
707 #[test]
708 fn word_with_multiple_expansion_mode_in_declaration_utility() {
709 let mut lexer = Lexer::with_code("export foo");
712 let mut parser = Parser::new(&mut lexer);
713
714 let result = parser.simple_command().now_or_never().unwrap();
715 let sc = result.unwrap().unwrap().unwrap();
716 assert_eq!(sc.assigns, []);
717 assert_eq!(sc.words.len(), 2);
718 assert_eq!(*sc.redirs, []);
719 assert_eq!(sc.words[0].0.to_string(), "export");
720 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
721 assert_eq!(sc.words[1].0.to_string(), "foo");
722 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
723 }
724
725 #[test]
726 fn word_with_multiple_expansion_mode_in_non_declaration_utility() {
727 let mut lexer = Lexer::with_code("foo a=b");
730 let mut parser = Parser::new(&mut lexer);
731
732 let result = parser.simple_command().now_or_never().unwrap();
733 let sc = result.unwrap().unwrap().unwrap();
734 assert_eq!(sc.assigns, []);
735 assert_eq!(sc.words.len(), 2);
736 assert_eq!(*sc.redirs, []);
737 assert_eq!(sc.words[0].0.to_string(), "foo");
738 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
739 assert_eq!(sc.words[1].0.to_string(), "a=b");
740 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
741 }
742
743 #[test]
744 fn declaration_utility_determined_by_non_first_word() {
745 let mut lexer = Lexer::with_code("command command export foo a=b");
748 let mut parser = Parser::new(&mut lexer);
749 let result = parser.simple_command().now_or_never().unwrap();
750 let sc = result.unwrap().unwrap().unwrap();
751 assert_eq!(sc.words[4].0.to_string(), "a=b");
752 assert_eq!(sc.words[4].1, ExpansionMode::Single);
753
754 let mut lexer = Lexer::with_code("command command foo export 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::Multiple);
760 }
761
762 #[test]
763 fn no_declaration_utilities_with_empty_glossary() {
764 let mut lexer = Lexer::with_code("export a=b");
766 let mut parser = Parser::config()
767 .declaration_utilities(&EmptyGlossary)
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, []);
773 assert_eq!(sc.words.len(), 2);
774 assert_eq!(*sc.redirs, []);
775 assert_eq!(sc.words[0].0.to_string(), "export");
776 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
777 assert_eq!(sc.words[1].0.to_string(), "a=b");
778 assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
779 }
780
781 #[test]
782 fn custom_declaration_utility_glossary() {
783 #[derive(Debug)]
785 struct CustomGlossary;
786 impl crate::decl_util::Glossary for CustomGlossary {
787 fn is_declaration_utility(&self, name: &str) -> Option<bool> {
788 Some(name == "foo")
789 }
790 }
791
792 let mut lexer = Lexer::with_code("foo a=b");
793 let mut parser = Parser::config()
794 .declaration_utilities(&CustomGlossary)
795 .input(&mut lexer);
796
797 let result = parser.simple_command().now_or_never().unwrap();
798 let sc = result.unwrap().unwrap().unwrap();
799 assert_eq!(sc.assigns, []);
800 assert_eq!(sc.words.len(), 2);
801 assert_eq!(*sc.redirs, []);
802 assert_eq!(sc.words[0].0.to_string(), "foo");
803 assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
804 assert_eq!(sc.words[1].0.to_string(), "a=b");
805 assert_eq!(sc.words[1].1, ExpansionMode::Single);
806 }
807
808 fn portable_mode() -> yash_env::parser::Mode {
809 let mut mode = yash_env::parser::Mode::default();
810 mode.portable = true;
811 mode
812 }
813
814 #[test]
815 fn command_name_ending_with_colon_rejected_in_portable_mode() {
816 let mut lexer = Lexer::with_code("$foo:");
817 lexer.set_mode(portable_mode());
818 let mut parser = Parser::new(&mut lexer);
819
820 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
821 assert_eq!(
822 e.cause,
823 ErrorCause::Syntax(SyntaxError::ColonSuffixedCommandName)
824 );
825 assert_eq!(*e.location.code.value.borrow(), "$foo:");
826 assert_eq!(e.location.range, 0..5);
827 }
828
829 #[test]
830 fn lone_colon_command_name_accepted_in_portable_mode() {
831 let mut lexer = Lexer::with_code(":");
833 lexer.set_mode(portable_mode());
834 let mut parser = Parser::new(&mut lexer);
835
836 let result = parser.simple_command().now_or_never().unwrap();
837 let sc = result.unwrap().unwrap().unwrap();
838 assert_eq!(sc.words.len(), 1);
839 assert_eq!(sc.words[0].0.to_string(), ":");
840 }
841
842 #[test]
843 fn command_name_ending_with_colon_accepted_without_portable_mode() {
844 let mut lexer = Lexer::with_code("$foo:");
845 let mut parser = Parser::new(&mut lexer);
846
847 let result = parser.simple_command().now_or_never().unwrap();
848 let sc = result.unwrap().unwrap().unwrap();
849 assert_eq!(sc.words.len(), 1);
850 assert_eq!(sc.words[0].0.to_string(), "$foo:");
851 }
852
853 #[test]
854 fn argument_ending_with_colon_accepted_in_portable_mode() {
855 let mut lexer = Lexer::with_code("echo foo:");
857 lexer.set_mode(portable_mode());
858 let mut parser = Parser::new(&mut lexer);
859
860 let result = parser.simple_command().now_or_never().unwrap();
861 let sc = result.unwrap().unwrap().unwrap();
862 assert_eq!(sc.words.len(), 2);
863 assert_eq!(sc.words[0].0.to_string(), "echo");
864 assert_eq!(sc.words[1].0.to_string(), "foo:");
865 }
866
867 #[test]
868 fn command_name_ending_with_colon_after_assignment_accepted_in_portable_mode() {
869 let mut lexer = Lexer::with_code("a=b foo:");
871 lexer.set_mode(portable_mode());
872 let mut parser = Parser::new(&mut lexer);
873
874 let result = parser.simple_command().now_or_never().unwrap();
875 let sc = result.unwrap().unwrap().unwrap();
876 assert_eq!(sc.assigns.len(), 1);
877 assert_eq!(sc.words.len(), 1);
878 assert_eq!(sc.words[0].0.to_string(), "foo:");
879 }
880
881 #[test]
882 fn quoted_colon_suffix_command_name_accepted_in_portable_mode() {
883 let mut lexer = Lexer::with_code(r"foo\:");
885 lexer.set_mode(portable_mode());
886 let mut parser = Parser::new(&mut lexer);
887
888 let result = parser.simple_command().now_or_never().unwrap();
889 let sc = result.unwrap().unwrap().unwrap();
890 assert_eq!(sc.words.len(), 1);
891 assert_eq!(sc.words[0].0.to_string(), r"foo\:");
892 }
893
894 #[test]
895 fn assignment_value_ending_with_colon_accepted_in_portable_mode() {
896 let mut lexer = Lexer::with_code("a=b:");
898 lexer.set_mode(portable_mode());
899 let mut parser = Parser::new(&mut lexer);
900
901 let result = parser.simple_command().now_or_never().unwrap();
902 let sc = result.unwrap().unwrap().unwrap();
903 assert_eq!(sc.assigns.len(), 1);
904 assert_eq!(sc.assigns[0].name, "a");
905 assert_eq!(sc.assigns[0].value.to_string(), "b:");
906 }
907
908 #[test]
909 fn assignment_name_starting_with_digit_rejected_in_portable_mode() {
910 let mut lexer = Lexer::with_code("1a=b");
911 lexer.set_mode(portable_mode());
912 let mut parser = Parser::new(&mut lexer);
913
914 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
915 assert_eq!(
916 e.cause,
917 ErrorCause::Syntax(SyntaxError::NonPortableAssignmentName)
918 );
919 assert_eq!(*e.location.code.value.borrow(), "1a=b");
920 assert_eq!(e.location.range, 0..4);
921 }
922
923 #[test]
924 fn assignment_name_with_non_portable_character_rejected_in_portable_mode() {
925 let mut lexer = Lexer::with_code("a.b=c");
926 lexer.set_mode(portable_mode());
927 let mut parser = Parser::new(&mut lexer);
928
929 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
930 assert_eq!(
931 e.cause,
932 ErrorCause::Syntax(SyntaxError::NonPortableAssignmentName)
933 );
934 }
935
936 #[test]
937 fn array_assignment_name_starting_with_digit_rejected_in_portable_mode() {
938 let mut lexer = Lexer::with_code("1a=(b c)");
939 lexer.set_mode(portable_mode());
940 let mut parser = Parser::new(&mut lexer);
941
942 let e = parser.simple_command().now_or_never().unwrap().unwrap_err();
943 assert_eq!(
944 e.cause,
945 ErrorCause::Syntax(SyntaxError::NonPortableAssignmentName)
946 );
947 }
948
949 #[test]
950 fn assignment_portable_name_allowed_in_portable_mode() {
951 let mut lexer = Lexer::with_code("_Az9=b");
952 lexer.set_mode(portable_mode());
953 let mut parser = Parser::new(&mut lexer);
954
955 let result = parser.simple_command().now_or_never().unwrap();
956 let sc = result.unwrap().unwrap().unwrap();
957 assert_eq!(sc.assigns.len(), 1);
958 assert_eq!(sc.assigns[0].name, "_Az9");
959 assert_eq!(sc.assigns[0].value.to_string(), "b");
960 }
961
962 #[test]
963 fn assignment_non_portable_name_allowed_without_portable_mode() {
964 let mut lexer = Lexer::with_code("1a=b");
965 let mut parser = Parser::new(&mut lexer);
966
967 let result = parser.simple_command().now_or_never().unwrap();
968 let sc = result.unwrap().unwrap().unwrap();
969 assert_eq!(sc.assigns.len(), 1);
970 assert_eq!(sc.assigns[0].name, "1a");
971 assert_eq!(sc.assigns[0].value.to_string(), "b");
972 }
973
974 #[test]
975 fn assignment_is_not_considered_for_declaration_utility() {
976 #[derive(Debug)]
977 struct CustomGlossary;
978 impl crate::decl_util::Glossary for CustomGlossary {
979 fn is_declaration_utility(&self, _name: &str) -> Option<bool> {
980 unreachable!("is_declaration_utility should not be called for assignments");
981 }
982 }
983
984 let mut lexer = Lexer::with_code("a=b");
985 let mut parser = Parser::config()
986 .declaration_utilities(&CustomGlossary)
987 .input(&mut lexer);
988
989 let result = parser.simple_command().now_or_never().unwrap();
990 let sc = result.unwrap().unwrap().unwrap();
991 assert_eq!(sc.assigns.len(), 1);
992 assert_eq!(sc.words, []);
993 assert_eq!(*sc.redirs, [])
994 }
995}