yash_syntax/parser/
simple_command.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2020 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Syntax parser for simple command
18
19use 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
35/// Determines the expansion mode of a word.
36///
37/// This function converts a raw token into a word-mode pair assuming that the
38/// token is a command argument word for a declaration utility.
39///
40/// This function tests if the word is in the form of `name=value`. If it is,
41/// the expansion mode is `ExpansionMode::Single`, and tilde expansions are
42/// parsed after the equal sign. Otherwise, the expansion mode is
43/// `ExpansionMode::Multiple`, and the word is returned as is.
44fn 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/// Simple command builder
59#[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    /// Parses the value of an array assignment.
84    ///
85    /// This function first consumes a `(` token, then any number of words
86    /// separated by blanks and/or newlines, and finally a `)`.
87    /// If the first token is not `(`, the result is `Ok(None)`.
88    /// If the last `)` is missing, the result is
89    /// `Err(ErrorCause::Syntax(SyntaxError::UnclosedArrayValue(_)))`.
90    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    /// Parses a simple command.
117    ///
118    /// If there is no valid command at the current position, this function
119    /// returns `Ok(Rec::Parsed(None))`.
120    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            // Parse redirection
126            if let Some(redir) = self.redirection().await? {
127                result.redirs.push(redir);
128                continue;
129            }
130
131            // Filter token type
132            match self.peek_token().await?.id {
133                Token(Some(_keyword)) if result.is_empty() => break,
134                Token(_) => (),
135                _ => break,
136            }
137
138            // Apply alias substitution
139            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            // Handle command argument word
151            if let Some(is_declaration_utility) = is_declaration_utility {
152                // The word determined (not) to be a declaration utility
153                // must already be in the words list.
154                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            // Tell assignment from word
165            let assign_or_word = if result.words.is_empty() {
166                // We don't have any words yet, so this token may be an assignment or a word.
167                Assign::try_from(token.word)
168            } else {
169                // We already have some words, so remaining tokens are all words.
170                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            // Tell array assignment from scalar assignment
191            // TODO no array assignment in POSIXly-correct mode
192            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        // "export" is a declaration utility, so the expansion mode of the word
639        // "a=b" should be single.
640        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        // The expansion mode of the word "foo" should be multiple because it
657        // cannot be parsed as an assignment.
658        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        // "foo" is not a declaration utility, so the expansion mode of the word
675        // "a=b" should be multiple.
676        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        // "command" delegates to the next word to determine whether it is a
693        // declaration utility.
694        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        // "export" is not a declaration utility in the empty glossary.
712        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        // "foo" is a declaration utility in the custom glossary.
731        #[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}