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("".to_string()),
254                WordUnit::Unquoted(TextUnit::Literal(':')),
255                WordUnit::Tilde("b".to_string()),
256            ]
257        );
258        assert_eq!(mode, ExpansionMode::Single);
259    }
260
261    #[test]
262    fn parser_array_values_no_open_parenthesis() {
263        let mut lexer = Lexer::with_code(")");
264        let mut parser = Parser::new(&mut lexer);
265        let result = parser.array_values().now_or_never().unwrap().unwrap();
266        assert_eq!(result, None);
267    }
268
269    #[test]
270    fn parser_array_values_empty() {
271        let mut lexer = Lexer::with_code("()");
272        let mut parser = Parser::new(&mut lexer);
273        let result = parser.array_values().now_or_never().unwrap();
274        let words = result.unwrap().unwrap();
275        assert_eq!(words, []);
276
277        let next = parser.peek_token().now_or_never().unwrap().unwrap();
278        assert_eq!(next.id, EndOfInput);
279    }
280
281    #[test]
282    fn parser_array_values_many() {
283        let mut lexer = Lexer::with_code("(a b c)");
284        let mut parser = Parser::new(&mut lexer);
285        let result = parser.array_values().now_or_never().unwrap();
286        let words = result.unwrap().unwrap();
287        assert_eq!(words.len(), 3);
288        assert_eq!(words[0].to_string(), "a");
289        assert_eq!(words[1].to_string(), "b");
290        assert_eq!(words[2].to_string(), "c");
291    }
292
293    #[test]
294    fn parser_array_values_newlines_and_comments() {
295        let mut lexer = Lexer::with_code(
296            "(
297            a # b
298            c d
299        )",
300        );
301        let mut parser = Parser::new(&mut lexer);
302        let result = parser.array_values().now_or_never().unwrap();
303        let words = result.unwrap().unwrap();
304        assert_eq!(words.len(), 3);
305        assert_eq!(words[0].to_string(), "a");
306        assert_eq!(words[1].to_string(), "c");
307        assert_eq!(words[2].to_string(), "d");
308    }
309
310    #[test]
311    fn parser_array_values_unclosed() {
312        let mut lexer = Lexer::with_code("(a b");
313        let mut parser = Parser::new(&mut lexer);
314        let e = parser.array_values().now_or_never().unwrap().unwrap_err();
315        assert_matches!(e.cause,
316             ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
317            assert_eq!(*opening_location.code.value.borrow(), "(a b");
318            assert_eq!(opening_location.code.start_line_number.get(), 1);
319            assert_eq!(*opening_location.code.source, Source::Unknown);
320            assert_eq!(opening_location.range, 0..1);
321        });
322        assert_eq!(*e.location.code.value.borrow(), "(a b");
323        assert_eq!(e.location.code.start_line_number.get(), 1);
324        assert_eq!(*e.location.code.source, Source::Unknown);
325        assert_eq!(e.location.range, 4..4);
326    }
327
328    #[test]
329    fn parser_array_values_invalid_word() {
330        let mut lexer = Lexer::with_code("(a;b)");
331        let mut parser = Parser::new(&mut lexer);
332        let e = parser.array_values().now_or_never().unwrap().unwrap_err();
333        assert_matches!(e.cause,
334            ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
335            assert_eq!(*opening_location.code.value.borrow(), "(a;b)");
336            assert_eq!(opening_location.code.start_line_number.get(), 1);
337            assert_eq!(*opening_location.code.source, Source::Unknown);
338            assert_eq!(opening_location.range, 0..1);
339        });
340        assert_eq!(*e.location.code.value.borrow(), "(a;b)");
341        assert_eq!(e.location.code.start_line_number.get(), 1);
342        assert_eq!(*e.location.code.source, Source::Unknown);
343        assert_eq!(e.location.range, 2..3);
344    }
345
346    #[test]
347    fn parser_simple_command_eof() {
348        let mut lexer = Lexer::with_code("");
349        let mut parser = Parser::new(&mut lexer);
350
351        let result = parser.simple_command().now_or_never().unwrap();
352        assert_eq!(result, Ok(Rec::Parsed(None)));
353    }
354
355    #[test]
356    fn parser_simple_command_keyword() {
357        let mut lexer = Lexer::with_code("then");
358        let mut parser = Parser::new(&mut lexer);
359
360        let result = parser.simple_command().now_or_never().unwrap();
361        assert_eq!(result, Ok(Rec::Parsed(None)));
362    }
363
364    #[test]
365    fn parser_simple_command_one_assignment() {
366        let mut lexer = Lexer::with_code("my=assignment");
367        let mut parser = Parser::new(&mut lexer);
368
369        let result = parser.simple_command().now_or_never().unwrap();
370        let sc = result.unwrap().unwrap().unwrap();
371        assert_eq!(sc.words, []);
372        assert_eq!(*sc.redirs, []);
373        assert_eq!(sc.assigns.len(), 1);
374        assert_eq!(sc.assigns[0].name, "my");
375        assert_eq!(sc.assigns[0].value.to_string(), "assignment");
376        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "my=assignment");
377        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
378        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
379        assert_eq!(sc.assigns[0].location.range, 0..13);
380    }
381
382    #[test]
383    fn parser_simple_command_many_assignments() {
384        let mut lexer = Lexer::with_code("a= b=! c=X");
385        let mut parser = Parser::new(&mut lexer);
386
387        let result = parser.simple_command().now_or_never().unwrap();
388        let sc = result.unwrap().unwrap().unwrap();
389        assert_eq!(sc.words, []);
390        assert_eq!(*sc.redirs, []);
391        assert_eq!(sc.assigns.len(), 3);
392        assert_eq!(sc.assigns[0].name, "a");
393        assert_eq!(sc.assigns[0].value.to_string(), "");
394        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= b=! c=X");
395        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
396        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
397        assert_eq!(sc.assigns[0].location.range, 0..2);
398        assert_eq!(sc.assigns[1].name, "b");
399        assert_eq!(sc.assigns[1].value.to_string(), "!");
400        assert_eq!(*sc.assigns[1].location.code.value.borrow(), "a= b=! c=X");
401        assert_eq!(sc.assigns[1].location.code.start_line_number.get(), 1);
402        assert_eq!(*sc.assigns[1].location.code.source, Source::Unknown);
403        assert_eq!(sc.assigns[1].location.range, 3..6);
404        assert_eq!(sc.assigns[2].name, "c");
405        assert_eq!(sc.assigns[2].value.to_string(), "X");
406        assert_eq!(*sc.assigns[2].location.code.value.borrow(), "a= b=! c=X");
407        assert_eq!(sc.assigns[2].location.code.start_line_number.get(), 1);
408        assert_eq!(*sc.assigns[2].location.code.source, Source::Unknown);
409        assert_eq!(sc.assigns[2].location.range, 7..10);
410    }
411
412    #[test]
413    fn parser_simple_command_one_word() {
414        let mut lexer = Lexer::with_code("word");
415        let mut parser = Parser::new(&mut lexer);
416
417        let result = parser.simple_command().now_or_never().unwrap();
418        let sc = result.unwrap().unwrap().unwrap();
419        assert_eq!(sc.assigns, []);
420        assert_eq!(*sc.redirs, []);
421        assert_eq!(sc.words.len(), 1);
422        assert_eq!(sc.words[0].0.to_string(), "word");
423        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
424    }
425
426    #[test]
427    fn parser_simple_command_many_words() {
428        let mut lexer = Lexer::with_code(": if then");
429        let mut parser = Parser::new(&mut lexer);
430
431        let result = parser.simple_command().now_or_never().unwrap();
432        let sc = result.unwrap().unwrap().unwrap();
433        assert_eq!(sc.assigns, []);
434        assert_eq!(*sc.redirs, []);
435        assert_eq!(sc.words.len(), 3);
436        assert_eq!(sc.words[0].0.to_string(), ":");
437        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
438        assert_eq!(sc.words[1].0.to_string(), "if");
439        assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
440        assert_eq!(sc.words[2].0.to_string(), "then");
441        assert_eq!(sc.words[2].1, ExpansionMode::Multiple);
442    }
443
444    #[test]
445    fn parser_simple_command_one_redirection() {
446        let mut lexer = Lexer::with_code("<foo");
447        let mut parser = Parser::new(&mut lexer);
448
449        let result = parser.simple_command().now_or_never().unwrap();
450        let sc = result.unwrap().unwrap().unwrap();
451        assert_eq!(sc.assigns, []);
452        assert_eq!(sc.words, []);
453        assert_eq!(sc.redirs.len(), 1);
454        assert_eq!(sc.redirs[0].fd, None);
455        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
456            assert_eq!(operator, &RedirOp::FileIn);
457            assert_eq!(operand.to_string(), "foo")
458        });
459
460        let next = parser.peek_token().now_or_never().unwrap().unwrap();
461        assert_eq!(next.id, EndOfInput);
462    }
463
464    #[test]
465    fn parser_simple_command_many_redirections() {
466        let mut lexer = Lexer::with_code("<one >two >>three");
467        let mut parser = Parser::new(&mut lexer);
468
469        let result = parser.simple_command().now_or_never().unwrap();
470        let sc = result.unwrap().unwrap().unwrap();
471        assert_eq!(sc.assigns, []);
472        assert_eq!(sc.words, []);
473        assert_eq!(sc.redirs.len(), 3);
474        assert_eq!(sc.redirs[0].fd, None);
475        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
476            assert_eq!(operator, &RedirOp::FileIn);
477            assert_eq!(operand.to_string(), "one")
478        });
479        assert_eq!(sc.redirs[1].fd, None);
480        assert_matches!(sc.redirs[1].body, RedirBody::Normal { ref operator, ref operand } => {
481            assert_eq!(operator, &RedirOp::FileOut);
482            assert_eq!(operand.to_string(), "two")
483        });
484        assert_eq!(sc.redirs[2].fd, None);
485        assert_matches!(sc.redirs[2].body, RedirBody::Normal { ref operator, ref operand } => {
486            assert_eq!(operator, &RedirOp::FileAppend);
487            assert_eq!(operand.to_string(), "three")
488        });
489
490        let next = parser.peek_token().now_or_never().unwrap().unwrap();
491        assert_eq!(next.id, EndOfInput);
492    }
493
494    #[test]
495    fn parser_simple_command_assignment_word() {
496        let mut lexer = Lexer::with_code("if=then else");
497        let mut parser = Parser::new(&mut lexer);
498
499        let result = parser.simple_command().now_or_never().unwrap();
500        let sc = result.unwrap().unwrap().unwrap();
501        assert_eq!(*sc.redirs, []);
502        assert_eq!(sc.assigns.len(), 1);
503        assert_eq!(sc.words.len(), 1);
504        assert_eq!(sc.assigns[0].name, "if");
505        assert_eq!(sc.assigns[0].value.to_string(), "then");
506        assert_eq!(sc.words[0].0.to_string(), "else");
507        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
508    }
509
510    #[test]
511    fn parser_simple_command_word_redirection() {
512        let mut lexer = Lexer::with_code("word <redirection");
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.len(), 1);
519        assert_eq!(sc.redirs.len(), 1);
520        assert_eq!(sc.words[0].0.to_string(), "word");
521        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
522        assert_eq!(sc.redirs[0].fd, None);
523        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
524            assert_eq!(operator, &RedirOp::FileIn);
525            assert_eq!(operand.to_string(), "redirection")
526        });
527    }
528
529    #[test]
530    fn parser_simple_command_redirection_assignment() {
531        let mut lexer = Lexer::with_code("<foo a=b");
532        let mut parser = Parser::new(&mut lexer);
533
534        let result = parser.simple_command().now_or_never().unwrap();
535        let sc = result.unwrap().unwrap().unwrap();
536        assert_eq!(sc.words, []);
537        assert_eq!(sc.assigns.len(), 1);
538        assert_eq!(sc.redirs.len(), 1);
539        assert_eq!(sc.assigns[0].name, "a");
540        assert_eq!(sc.assigns[0].value.to_string(), "b");
541        assert_eq!(sc.redirs[0].fd, None);
542        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
543            assert_eq!(operator, &RedirOp::FileIn);
544            assert_eq!(operand.to_string(), "foo")
545        });
546    }
547
548    #[test]
549    fn parser_simple_command_assignment_redirection_word() {
550        let mut lexer = Lexer::with_code("if=then <foo else");
551        let mut parser = Parser::new(&mut lexer);
552
553        let result = parser.simple_command().now_or_never().unwrap();
554        let sc = result.unwrap().unwrap().unwrap();
555        assert_eq!(sc.assigns.len(), 1);
556        assert_eq!(sc.words.len(), 1);
557        assert_eq!(sc.redirs.len(), 1);
558        assert_eq!(sc.assigns[0].name, "if");
559        assert_eq!(sc.assigns[0].value.to_string(), "then");
560        assert_eq!(sc.words[0].0.to_string(), "else");
561        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
562        assert_eq!(sc.redirs[0].fd, None);
563        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
564            assert_eq!(operator, &RedirOp::FileIn);
565            assert_eq!(operand.to_string(), "foo")
566        });
567    }
568
569    #[test]
570    fn parser_simple_command_array_assignment() {
571        let mut lexer = Lexer::with_code("a=()");
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.len(), 1);
577        assert_eq!(sc.words, []);
578        assert_eq!(*sc.redirs, []);
579        assert_eq!(sc.assigns[0].name, "a");
580        assert_matches!(&sc.assigns[0].value, Array(words) => {
581            assert_eq!(words, &[]);
582        });
583
584        let next = parser.peek_token().now_or_never().unwrap().unwrap();
585        assert_eq!(next.id, EndOfInput);
586    }
587
588    #[test]
589    fn parser_simple_command_empty_assignment_followed_by_blank_and_parenthesis() {
590        let mut lexer = Lexer::with_code("a= ()");
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.assigns.len(), 1);
596        assert_eq!(sc.words, []);
597        assert_eq!(*sc.redirs, []);
598        assert_eq!(sc.assigns[0].name, "a");
599        assert_eq!(sc.assigns[0].value.to_string(), "");
600        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= ()");
601        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
602        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
603        assert_eq!(sc.assigns[0].location.range, 0..2);
604
605        let next = parser.peek_token().now_or_never().unwrap().unwrap();
606        assert_eq!(next.id, Operator(OpenParen));
607    }
608
609    #[test]
610    fn parser_simple_command_non_empty_assignment_followed_by_parenthesis() {
611        let mut lexer = Lexer::with_code("a=b()");
612        let mut parser = Parser::new(&mut lexer);
613
614        let result = parser.simple_command().now_or_never().unwrap();
615        let sc = result.unwrap().unwrap().unwrap();
616        assert_eq!(sc.assigns.len(), 1);
617        assert_eq!(sc.words, []);
618        assert_eq!(*sc.redirs, []);
619        assert_eq!(sc.assigns[0].name, "a");
620        assert_eq!(sc.assigns[0].value.to_string(), "b");
621        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a=b()");
622        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
623        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
624        assert_eq!(sc.assigns[0].location.range, 0..3);
625
626        let next = parser.peek_token().now_or_never().unwrap().unwrap();
627        assert_eq!(next.id, Operator(OpenParen));
628    }
629
630    #[test]
631    fn word_with_single_expansion_mode_in_declaration_utility() {
632        // "export" is a declaration utility, so the expansion mode of the word
633        // "a=b" should be single.
634        let mut lexer = Lexer::with_code("export a=b");
635        let mut parser = Parser::new(&mut lexer);
636
637        let result = parser.simple_command().now_or_never().unwrap();
638        let sc = result.unwrap().unwrap().unwrap();
639        assert_eq!(sc.assigns, []);
640        assert_eq!(sc.words.len(), 2);
641        assert_eq!(*sc.redirs, []);
642        assert_eq!(sc.words[0].0.to_string(), "export");
643        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
644        assert_eq!(sc.words[1].0.to_string(), "a=b");
645        assert_eq!(sc.words[1].1, ExpansionMode::Single);
646    }
647
648    #[test]
649    fn word_with_multiple_expansion_mode_in_declaration_utility() {
650        // The expansion mode of the word "foo" should be multiple because it
651        // cannot be parsed as an assignment.
652        let mut lexer = Lexer::with_code("export foo");
653        let mut parser = Parser::new(&mut lexer);
654
655        let result = parser.simple_command().now_or_never().unwrap();
656        let sc = result.unwrap().unwrap().unwrap();
657        assert_eq!(sc.assigns, []);
658        assert_eq!(sc.words.len(), 2);
659        assert_eq!(*sc.redirs, []);
660        assert_eq!(sc.words[0].0.to_string(), "export");
661        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
662        assert_eq!(sc.words[1].0.to_string(), "foo");
663        assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
664    }
665
666    #[test]
667    fn word_with_multiple_expansion_mode_in_non_declaration_utility() {
668        // "foo" is not a declaration utility, so the expansion mode of the word
669        // "a=b" should be multiple.
670        let mut lexer = Lexer::with_code("foo 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, []);
676        assert_eq!(sc.words.len(), 2);
677        assert_eq!(*sc.redirs, []);
678        assert_eq!(sc.words[0].0.to_string(), "foo");
679        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
680        assert_eq!(sc.words[1].0.to_string(), "a=b");
681        assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
682    }
683
684    #[test]
685    fn declaration_utility_determined_by_non_first_word() {
686        // "command" delegates to the next word to determine whether it is a
687        // declaration utility.
688        let mut lexer = Lexer::with_code("command command export foo a=b");
689        let mut parser = Parser::new(&mut lexer);
690        let result = parser.simple_command().now_or_never().unwrap();
691        let sc = result.unwrap().unwrap().unwrap();
692        assert_eq!(sc.words[4].0.to_string(), "a=b");
693        assert_eq!(sc.words[4].1, ExpansionMode::Single);
694
695        let mut lexer = Lexer::with_code("command command foo export a=b");
696        let mut parser = Parser::new(&mut lexer);
697        let result = parser.simple_command().now_or_never().unwrap();
698        let sc = result.unwrap().unwrap().unwrap();
699        assert_eq!(sc.words[4].0.to_string(), "a=b");
700        assert_eq!(sc.words[4].1, ExpansionMode::Multiple);
701    }
702
703    #[test]
704    fn no_declaration_utilities_with_empty_glossary() {
705        // "export" is not a declaration utility in the empty glossary.
706        let mut lexer = Lexer::with_code("export a=b");
707        let mut parser = Parser::config()
708            .declaration_utilities(&EmptyGlossary)
709            .input(&mut lexer);
710
711        let result = parser.simple_command().now_or_never().unwrap();
712        let sc = result.unwrap().unwrap().unwrap();
713        assert_eq!(sc.assigns, []);
714        assert_eq!(sc.words.len(), 2);
715        assert_eq!(*sc.redirs, []);
716        assert_eq!(sc.words[0].0.to_string(), "export");
717        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
718        assert_eq!(sc.words[1].0.to_string(), "a=b");
719        assert_eq!(sc.words[1].1, ExpansionMode::Multiple);
720    }
721
722    #[test]
723    fn custom_declaration_utility_glossary() {
724        // "foo" is a declaration utility in the custom glossary.
725        #[derive(Debug)]
726        struct CustomGlossary;
727        impl crate::decl_util::Glossary for CustomGlossary {
728            fn is_declaration_utility(&self, name: &str) -> Option<bool> {
729                Some(name == "foo")
730            }
731        }
732
733        let mut lexer = Lexer::with_code("foo a=b");
734        let mut parser = Parser::config()
735            .declaration_utilities(&CustomGlossary)
736            .input(&mut lexer);
737
738        let result = parser.simple_command().now_or_never().unwrap();
739        let sc = result.unwrap().unwrap().unwrap();
740        assert_eq!(sc.assigns, []);
741        assert_eq!(sc.words.len(), 2);
742        assert_eq!(*sc.redirs, []);
743        assert_eq!(sc.words[0].0.to_string(), "foo");
744        assert_eq!(sc.words[0].1, ExpansionMode::Multiple);
745        assert_eq!(sc.words[1].0.to_string(), "a=b");
746        assert_eq!(sc.words[1].1, ExpansionMode::Single);
747    }
748
749    #[test]
750    fn assignment_is_not_considered_for_declaration_utility() {
751        #[derive(Debug)]
752        struct CustomGlossary;
753        impl crate::decl_util::Glossary for CustomGlossary {
754            fn is_declaration_utility(&self, _name: &str) -> Option<bool> {
755                unreachable!("is_declaration_utility should not be called for assignments");
756            }
757        }
758
759        let mut lexer = Lexer::with_code("a=b");
760        let mut parser = Parser::config()
761            .declaration_utilities(&CustomGlossary)
762            .input(&mut lexer);
763
764        let result = parser.simple_command().now_or_never().unwrap();
765        let sc = result.unwrap().unwrap().unwrap();
766        assert_eq!(sc.assigns.len(), 1);
767        assert_eq!(sc.words, []);
768        assert_eq!(*sc.redirs, [])
769    }
770}