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::Redir;
29use crate::syntax::Scalar;
30use crate::syntax::SimpleCommand;
31use crate::syntax::Word;
32
33/// Simple command builder.
34#[derive(Default)]
35struct Builder {
36    assigns: Vec<Assign>,
37    words: Vec<Word>,
38    redirs: Vec<Redir>,
39}
40
41impl Builder {
42    fn is_empty(&self) -> bool {
43        self.assigns.is_empty() && self.words.is_empty() && self.redirs.is_empty()
44    }
45}
46
47impl From<Builder> for SimpleCommand {
48    fn from(builder: Builder) -> Self {
49        SimpleCommand {
50            assigns: builder.assigns,
51            words: builder.words,
52            redirs: builder.redirs.into(),
53        }
54    }
55}
56
57impl Parser<'_, '_> {
58    /// Parses the value of an array assignment.
59    ///
60    /// This function first consumes a `(` token, then any number of words
61    /// separated by blanks and/or newlines, and finally a `)`.
62    /// If the first token is not `(`, the result is `Ok(None)`.
63    /// If the last `)` is missing, the result is
64    /// `Err(ErrorCause::Syntax(SyntaxError::UnclosedArrayValue(_)))`.
65    pub async fn array_values(&mut self) -> Result<Option<Vec<Word>>> {
66        if self.peek_token().await?.id != Operator(OpenParen) {
67            return Ok(None);
68        }
69
70        let opening_location = self.take_token_raw().await?.word.location;
71        let mut words = vec![];
72
73        loop {
74            let next = self.take_token_auto(&[]).await?;
75            match next.id {
76                Operator(Newline) => continue,
77                Operator(CloseParen) => break,
78                Token(_keyword) => words.push(next.word),
79                _ => {
80                    return Err(Error {
81                        cause: SyntaxError::UnclosedArrayValue { opening_location }.into(),
82                        location: next.word.location,
83                    })
84                }
85            }
86        }
87
88        Ok(Some(words))
89    }
90
91    /// Parses a simple command.
92    ///
93    /// If there is no valid command at the current position, this function
94    /// returns `Ok(Rec::Parsed(None))`.
95    pub async fn simple_command(&mut self) -> Result<Rec<Option<SimpleCommand>>> {
96        let mut result = Builder::default();
97
98        loop {
99            // Parse redirection
100            if let Some(redir) = self.redirection().await? {
101                result.redirs.push(redir);
102                continue;
103            }
104
105            // Filter token type
106            match self.peek_token().await?.id {
107                Token(Some(_keyword)) if result.is_empty() => break,
108                Token(_) => (),
109                _ => break,
110            }
111
112            // Apply alias substitution
113            let token = match self.take_token_manual(result.words.is_empty()).await? {
114                Rec::AliasSubstituted => {
115                    if result.is_empty() {
116                        return Ok(Rec::AliasSubstituted);
117                    } else {
118                        continue;
119                    }
120                }
121                Rec::Parsed(token) => token,
122            };
123
124            // Tell assignment from word
125            if !result.words.is_empty() {
126                result.words.push(token.word);
127                continue;
128            }
129            let mut assign = match Assign::try_from(token.word) {
130                Ok(assign) => assign,
131                Err(word) => {
132                    result.words.push(word);
133                    continue;
134                }
135            };
136
137            let units = match &assign.value {
138                Scalar(Word { units, .. }) => units,
139                _ => panic!(
140                    "Assign::try_from produced a non-scalar value {:?}",
141                    assign.value
142                ),
143            };
144
145            // Tell array assignment from scalar assignment
146            // TODO no array assignment in POSIXly-correct mode
147            if units.is_empty() && !self.has_blank().await? {
148                if let Some(words) = self.array_values().await? {
149                    assign.value = Array(words);
150                }
151            }
152
153            result.assigns.push(assign);
154        }
155
156        Ok(Rec::Parsed(if result.is_empty() {
157            None
158        } else {
159            Some(result.into())
160        }))
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::super::error::ErrorCause;
167    use super::super::lex::Lexer;
168    use super::super::lex::TokenId::EndOfInput;
169    use super::*;
170    use crate::alias::EmptyGlossary;
171    use crate::source::Source;
172    use crate::syntax::RedirBody;
173    use crate::syntax::RedirOp;
174    use assert_matches::assert_matches;
175    use futures_util::FutureExt;
176
177    #[test]
178    fn parser_array_values_no_open_parenthesis() {
179        let mut lexer = Lexer::from_memory(")", Source::Unknown);
180        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
181        let result = parser.array_values().now_or_never().unwrap().unwrap();
182        assert_eq!(result, None);
183    }
184
185    #[test]
186    fn parser_array_values_empty() {
187        let mut lexer = Lexer::from_memory("()", Source::Unknown);
188        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
189        let result = parser.array_values().now_or_never().unwrap();
190        let words = result.unwrap().unwrap();
191        assert_eq!(words, []);
192
193        let next = parser.peek_token().now_or_never().unwrap().unwrap();
194        assert_eq!(next.id, EndOfInput);
195    }
196
197    #[test]
198    fn parser_array_values_many() {
199        let mut lexer = Lexer::from_memory("(a b c)", Source::Unknown);
200        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
201        let result = parser.array_values().now_or_never().unwrap();
202        let words = result.unwrap().unwrap();
203        assert_eq!(words.len(), 3);
204        assert_eq!(words[0].to_string(), "a");
205        assert_eq!(words[1].to_string(), "b");
206        assert_eq!(words[2].to_string(), "c");
207    }
208
209    #[test]
210    fn parser_array_values_newlines_and_comments() {
211        let mut lexer = Lexer::from_memory(
212            "(
213            a # b
214            c d
215        )",
216            Source::Unknown,
217        );
218        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
219        let result = parser.array_values().now_or_never().unwrap();
220        let words = result.unwrap().unwrap();
221        assert_eq!(words.len(), 3);
222        assert_eq!(words[0].to_string(), "a");
223        assert_eq!(words[1].to_string(), "c");
224        assert_eq!(words[2].to_string(), "d");
225    }
226
227    #[test]
228    fn parser_array_values_unclosed() {
229        let mut lexer = Lexer::from_memory("(a b", Source::Unknown);
230        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
231        let e = parser.array_values().now_or_never().unwrap().unwrap_err();
232        assert_matches!(e.cause,
233             ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
234            assert_eq!(*opening_location.code.value.borrow(), "(a b");
235            assert_eq!(opening_location.code.start_line_number.get(), 1);
236            assert_eq!(*opening_location.code.source, Source::Unknown);
237            assert_eq!(opening_location.range, 0..1);
238        });
239        assert_eq!(*e.location.code.value.borrow(), "(a b");
240        assert_eq!(e.location.code.start_line_number.get(), 1);
241        assert_eq!(*e.location.code.source, Source::Unknown);
242        assert_eq!(e.location.range, 4..4);
243    }
244
245    #[test]
246    fn parser_array_values_invalid_word() {
247        let mut lexer = Lexer::from_memory("(a;b)", Source::Unknown);
248        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
249        let e = parser.array_values().now_or_never().unwrap().unwrap_err();
250        assert_matches!(e.cause,
251            ErrorCause::Syntax(SyntaxError::UnclosedArrayValue { opening_location }) => {
252            assert_eq!(*opening_location.code.value.borrow(), "(a;b)");
253            assert_eq!(opening_location.code.start_line_number.get(), 1);
254            assert_eq!(*opening_location.code.source, Source::Unknown);
255            assert_eq!(opening_location.range, 0..1);
256        });
257        assert_eq!(*e.location.code.value.borrow(), "(a;b)");
258        assert_eq!(e.location.code.start_line_number.get(), 1);
259        assert_eq!(*e.location.code.source, Source::Unknown);
260        assert_eq!(e.location.range, 2..3);
261    }
262
263    #[test]
264    fn parser_simple_command_eof() {
265        let mut lexer = Lexer::from_memory("", Source::Unknown);
266        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
267
268        let result = parser.simple_command().now_or_never().unwrap();
269        assert_eq!(result, Ok(Rec::Parsed(None)));
270    }
271
272    #[test]
273    fn parser_simple_command_keyword() {
274        let mut lexer = Lexer::from_memory("then", Source::Unknown);
275        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
276
277        let result = parser.simple_command().now_or_never().unwrap();
278        assert_eq!(result, Ok(Rec::Parsed(None)));
279    }
280
281    #[test]
282    fn parser_simple_command_one_assignment() {
283        let mut lexer = Lexer::from_memory("my=assignment", Source::Unknown);
284        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
285
286        let result = parser.simple_command().now_or_never().unwrap();
287        let sc = result.unwrap().unwrap().unwrap();
288        assert_eq!(sc.words, []);
289        assert_eq!(*sc.redirs, []);
290        assert_eq!(sc.assigns.len(), 1);
291        assert_eq!(sc.assigns[0].name, "my");
292        assert_eq!(sc.assigns[0].value.to_string(), "assignment");
293        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "my=assignment");
294        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
295        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
296        assert_eq!(sc.assigns[0].location.range, 0..13);
297    }
298
299    #[test]
300    fn parser_simple_command_many_assignments() {
301        let mut lexer = Lexer::from_memory("a= b=! c=X", Source::Unknown);
302        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
303
304        let result = parser.simple_command().now_or_never().unwrap();
305        let sc = result.unwrap().unwrap().unwrap();
306        assert_eq!(sc.words, []);
307        assert_eq!(*sc.redirs, []);
308        assert_eq!(sc.assigns.len(), 3);
309        assert_eq!(sc.assigns[0].name, "a");
310        assert_eq!(sc.assigns[0].value.to_string(), "");
311        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= b=! c=X");
312        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
313        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
314        assert_eq!(sc.assigns[0].location.range, 0..2);
315        assert_eq!(sc.assigns[1].name, "b");
316        assert_eq!(sc.assigns[1].value.to_string(), "!");
317        assert_eq!(*sc.assigns[1].location.code.value.borrow(), "a= b=! c=X");
318        assert_eq!(sc.assigns[1].location.code.start_line_number.get(), 1);
319        assert_eq!(*sc.assigns[1].location.code.source, Source::Unknown);
320        assert_eq!(sc.assigns[1].location.range, 3..6);
321        assert_eq!(sc.assigns[2].name, "c");
322        assert_eq!(sc.assigns[2].value.to_string(), "X");
323        assert_eq!(*sc.assigns[2].location.code.value.borrow(), "a= b=! c=X");
324        assert_eq!(sc.assigns[2].location.code.start_line_number.get(), 1);
325        assert_eq!(*sc.assigns[2].location.code.source, Source::Unknown);
326        assert_eq!(sc.assigns[2].location.range, 7..10);
327    }
328
329    #[test]
330    fn parser_simple_command_one_word() {
331        let mut lexer = Lexer::from_memory("word", Source::Unknown);
332        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
333
334        let result = parser.simple_command().now_or_never().unwrap();
335        let sc = result.unwrap().unwrap().unwrap();
336        assert_eq!(sc.assigns, []);
337        assert_eq!(*sc.redirs, []);
338        assert_eq!(sc.words.len(), 1);
339        assert_eq!(sc.words[0].to_string(), "word");
340    }
341
342    #[test]
343    fn parser_simple_command_many_words() {
344        let mut lexer = Lexer::from_memory(": if then", Source::Unknown);
345        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
346
347        let result = parser.simple_command().now_or_never().unwrap();
348        let sc = result.unwrap().unwrap().unwrap();
349        assert_eq!(sc.assigns, []);
350        assert_eq!(*sc.redirs, []);
351        assert_eq!(sc.words.len(), 3);
352        assert_eq!(sc.words[0].to_string(), ":");
353        assert_eq!(sc.words[1].to_string(), "if");
354        assert_eq!(sc.words[2].to_string(), "then");
355    }
356
357    #[test]
358    fn parser_simple_command_one_redirection() {
359        let mut lexer = Lexer::from_memory("<foo", Source::Unknown);
360        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
361
362        let result = parser.simple_command().now_or_never().unwrap();
363        let sc = result.unwrap().unwrap().unwrap();
364        assert_eq!(sc.assigns, []);
365        assert_eq!(sc.words, []);
366        assert_eq!(sc.redirs.len(), 1);
367        assert_eq!(sc.redirs[0].fd, None);
368        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
369            assert_eq!(operator, &RedirOp::FileIn);
370            assert_eq!(operand.to_string(), "foo")
371        });
372
373        let next = parser.peek_token().now_or_never().unwrap().unwrap();
374        assert_eq!(next.id, EndOfInput);
375    }
376
377    #[test]
378    fn parser_simple_command_many_redirections() {
379        let mut lexer = Lexer::from_memory("<one >two >>three", Source::Unknown);
380        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
381
382        let result = parser.simple_command().now_or_never().unwrap();
383        let sc = result.unwrap().unwrap().unwrap();
384        assert_eq!(sc.assigns, []);
385        assert_eq!(sc.words, []);
386        assert_eq!(sc.redirs.len(), 3);
387        assert_eq!(sc.redirs[0].fd, None);
388        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
389            assert_eq!(operator, &RedirOp::FileIn);
390            assert_eq!(operand.to_string(), "one")
391        });
392        assert_eq!(sc.redirs[1].fd, None);
393        assert_matches!(sc.redirs[1].body, RedirBody::Normal { ref operator, ref operand } => {
394            assert_eq!(operator, &RedirOp::FileOut);
395            assert_eq!(operand.to_string(), "two")
396        });
397        assert_eq!(sc.redirs[2].fd, None);
398        assert_matches!(sc.redirs[2].body, RedirBody::Normal { ref operator, ref operand } => {
399            assert_eq!(operator, &RedirOp::FileAppend);
400            assert_eq!(operand.to_string(), "three")
401        });
402
403        let next = parser.peek_token().now_or_never().unwrap().unwrap();
404        assert_eq!(next.id, EndOfInput);
405    }
406
407    #[test]
408    fn parser_simple_command_assignment_word() {
409        let mut lexer = Lexer::from_memory("if=then else", Source::Unknown);
410        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
411
412        let result = parser.simple_command().now_or_never().unwrap();
413        let sc = result.unwrap().unwrap().unwrap();
414        assert_eq!(*sc.redirs, []);
415        assert_eq!(sc.assigns.len(), 1);
416        assert_eq!(sc.words.len(), 1);
417        assert_eq!(sc.assigns[0].name, "if");
418        assert_eq!(sc.assigns[0].value.to_string(), "then");
419        assert_eq!(sc.words[0].to_string(), "else");
420    }
421
422    #[test]
423    fn parser_simple_command_word_redirection() {
424        let mut lexer = Lexer::from_memory("word <redirection", Source::Unknown);
425        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
426
427        let result = parser.simple_command().now_or_never().unwrap();
428        let sc = result.unwrap().unwrap().unwrap();
429        assert_eq!(sc.assigns, []);
430        assert_eq!(sc.words.len(), 1);
431        assert_eq!(sc.redirs.len(), 1);
432        assert_eq!(sc.words[0].to_string(), "word");
433        assert_eq!(sc.redirs[0].fd, None);
434        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
435            assert_eq!(operator, &RedirOp::FileIn);
436            assert_eq!(operand.to_string(), "redirection")
437        });
438    }
439
440    #[test]
441    fn parser_simple_command_redirection_assignment() {
442        let mut lexer = Lexer::from_memory("<foo a=b", Source::Unknown);
443        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
444
445        let result = parser.simple_command().now_or_never().unwrap();
446        let sc = result.unwrap().unwrap().unwrap();
447        assert_eq!(sc.words, []);
448        assert_eq!(sc.assigns.len(), 1);
449        assert_eq!(sc.redirs.len(), 1);
450        assert_eq!(sc.assigns[0].name, "a");
451        assert_eq!(sc.assigns[0].value.to_string(), "b");
452        assert_eq!(sc.redirs[0].fd, None);
453        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
454            assert_eq!(operator, &RedirOp::FileIn);
455            assert_eq!(operand.to_string(), "foo")
456        });
457    }
458
459    #[test]
460    fn parser_simple_command_assignment_redirection_word() {
461        let mut lexer = Lexer::from_memory("if=then <foo else", Source::Unknown);
462        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
463
464        let result = parser.simple_command().now_or_never().unwrap();
465        let sc = result.unwrap().unwrap().unwrap();
466        assert_eq!(sc.assigns.len(), 1);
467        assert_eq!(sc.words.len(), 1);
468        assert_eq!(sc.redirs.len(), 1);
469        assert_eq!(sc.assigns[0].name, "if");
470        assert_eq!(sc.assigns[0].value.to_string(), "then");
471        assert_eq!(sc.words[0].to_string(), "else");
472        assert_eq!(sc.redirs[0].fd, None);
473        assert_matches!(sc.redirs[0].body, RedirBody::Normal { ref operator, ref operand } => {
474            assert_eq!(operator, &RedirOp::FileIn);
475            assert_eq!(operand.to_string(), "foo")
476        });
477    }
478
479    #[test]
480    fn parser_simple_command_array_assignment() {
481        let mut lexer = Lexer::from_memory("a=()", Source::Unknown);
482        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
483
484        let result = parser.simple_command().now_or_never().unwrap();
485        let sc = result.unwrap().unwrap().unwrap();
486        assert_eq!(sc.assigns.len(), 1);
487        assert_eq!(sc.words, []);
488        assert_eq!(*sc.redirs, []);
489        assert_eq!(sc.assigns[0].name, "a");
490        assert_matches!(&sc.assigns[0].value, Array(words) => {
491            assert_eq!(words, &[]);
492        });
493
494        let next = parser.peek_token().now_or_never().unwrap().unwrap();
495        assert_eq!(next.id, EndOfInput);
496    }
497
498    #[test]
499    fn parser_simple_command_empty_assignment_followed_by_blank_and_parenthesis() {
500        let mut lexer = Lexer::from_memory("a= ()", Source::Unknown);
501        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
502
503        let result = parser.simple_command().now_or_never().unwrap();
504        let sc = result.unwrap().unwrap().unwrap();
505        assert_eq!(sc.assigns.len(), 1);
506        assert_eq!(sc.words, []);
507        assert_eq!(*sc.redirs, []);
508        assert_eq!(sc.assigns[0].name, "a");
509        assert_eq!(sc.assigns[0].value.to_string(), "");
510        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a= ()");
511        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
512        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
513        assert_eq!(sc.assigns[0].location.range, 0..2);
514
515        let next = parser.peek_token().now_or_never().unwrap().unwrap();
516        assert_eq!(next.id, Operator(OpenParen));
517    }
518
519    #[test]
520    fn parser_simple_command_non_empty_assignment_followed_by_parenthesis() {
521        let mut lexer = Lexer::from_memory("a=b()", Source::Unknown);
522        let mut parser = Parser::new(&mut lexer, &EmptyGlossary);
523
524        let result = parser.simple_command().now_or_never().unwrap();
525        let sc = result.unwrap().unwrap().unwrap();
526        assert_eq!(sc.assigns.len(), 1);
527        assert_eq!(sc.words, []);
528        assert_eq!(*sc.redirs, []);
529        assert_eq!(sc.assigns[0].name, "a");
530        assert_eq!(sc.assigns[0].value.to_string(), "b");
531        assert_eq!(*sc.assigns[0].location.code.value.borrow(), "a=b()");
532        assert_eq!(sc.assigns[0].location.code.start_line_number.get(), 1);
533        assert_eq!(*sc.assigns[0].location.code.source, Source::Unknown);
534        assert_eq!(sc.assigns[0].location.range, 0..3);
535
536        let next = parser.peek_token().now_or_never().unwrap().unwrap();
537        assert_eq!(next.id, Operator(OpenParen));
538    }
539}