yash_syntax/parser/
command.rs1use super::core::Parser;
23use super::core::Rec;
24use super::core::Result;
25use super::lex::Keyword::{Function, Namespace, OpenBracketBracket, Select};
26use super::lex::TokenId::Token;
27use super::{Error, SyntaxError};
28use crate::syntax::Command;
29
30impl Parser<'_, '_> {
31 pub async fn command(&mut self) -> Result<Rec<Option<Command>>> {
36 match self.simple_command().await? {
37 Rec::AliasSubstituted => Ok(Rec::AliasSubstituted),
38
39 Rec::Parsed(None) => {
40 if let Some(compound) = self.full_compound_command().await? {
41 return Ok(Rec::Parsed(Some(Command::Compound(compound))));
42 }
43
44 let next = self.peek_token().await?;
45 match next.id {
46 Token(Some(Function)) => {
47 let cause = SyntaxError::UnsupportedFunctionDefinitionSyntax.into();
48 let location = next.word.location.clone();
49 Err(Error { cause, location })
50 }
51 Token(Some(OpenBracketBracket)) => {
52 let cause = SyntaxError::UnsupportedDoubleBracketCommand.into();
53 let location = next.word.location.clone();
54 Err(Error { cause, location })
55 }
56 Token(Some(Namespace)) => {
57 let cause = SyntaxError::UnsupportedNamespaceCommand.into();
58 let location = next.word.location.clone();
59 Err(Error { cause, location })
60 }
61 Token(Some(Select)) => {
62 let cause = SyntaxError::UnsupportedSelectCommand.into();
63 let location = next.word.location.clone();
64 Err(Error { cause, location })
65 }
66 _ => Ok(Rec::Parsed(None)),
67 }
68 }
69
70 Rec::Parsed(Some(c)) => self
71 .short_function_definition(c)
72 .await
73 .map(|c| Rec::Parsed(Some(c))),
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::super::ErrorCause;
81 use super::super::lex::Lexer;
82 use super::super::lex::TokenId::EndOfInput;
83 use super::*;
84 use crate::source::Source;
85 use assert_matches::assert_matches;
86 use futures_util::FutureExt as _;
87
88 #[test]
89 fn parser_command_simple() {
90 let mut lexer = Lexer::with_code("foo < bar");
91 let mut parser = Parser::new(&mut lexer);
92
93 let result = parser.command().now_or_never().unwrap();
94 let command = result.unwrap().unwrap().unwrap();
95 assert_matches!(command, Command::Simple(c) => {
96 assert_eq!(c.to_string(), "foo <bar");
97 });
98
99 let next = parser.peek_token().now_or_never().unwrap().unwrap();
100 assert_eq!(next.id, EndOfInput);
101 }
102
103 #[test]
104 fn parser_command_compound() {
105 let mut lexer = Lexer::with_code("(foo) < bar");
106 let mut parser = Parser::new(&mut lexer);
107
108 let result = parser.command().now_or_never().unwrap();
109 let command = result.unwrap().unwrap().unwrap();
110 assert_matches!(command, Command::Compound(c) => {
111 assert_eq!(c.to_string(), "(foo) <bar");
112 });
113
114 let next = parser.peek_token().now_or_never().unwrap().unwrap();
115 assert_eq!(next.id, EndOfInput);
116 }
117
118 #[test]
119 fn parser_command_short_function() {
120 let mut lexer = Lexer::with_code("fun () ( echo )");
121 let mut parser = Parser::new(&mut lexer);
122
123 let result = parser.command().now_or_never().unwrap();
124 let command = result.unwrap().unwrap().unwrap();
125 assert_matches!(command, Command::Function(f) => {
126 assert_eq!(f.to_string(), "fun() (echo)");
127 });
128
129 let next = parser.peek_token().now_or_never().unwrap().unwrap();
130 assert_eq!(next.id, EndOfInput);
131 }
132
133 #[test]
134 fn parser_command_long_function() {
135 let mut lexer = Lexer::with_code(" function fun { echo; }");
136 let mut parser = Parser::new(&mut lexer);
137
138 let e = parser.command().now_or_never().unwrap().unwrap_err();
139 assert_eq!(
140 e.cause,
141 ErrorCause::Syntax(SyntaxError::UnsupportedFunctionDefinitionSyntax)
142 );
143 assert_eq!(*e.location.code.value.borrow(), " function fun { echo; }");
144 assert_eq!(e.location.code.start_line_number.get(), 1);
145 assert_eq!(*e.location.code.source, Source::Unknown);
146 assert_eq!(e.location.range, 2..10);
147 }
148
149 #[test]
150 fn parser_command_double_bracket() {
151 let mut lexer = Lexer::with_code(" [[ foo ]]");
152 let mut parser = Parser::new(&mut lexer);
153
154 let e = parser.command().now_or_never().unwrap().unwrap_err();
155 assert_eq!(
156 e.cause,
157 ErrorCause::Syntax(SyntaxError::UnsupportedDoubleBracketCommand)
158 );
159 assert_eq!(*e.location.code.value.borrow(), " [[ foo ]]");
160 assert_eq!(e.location.code.start_line_number.get(), 1);
161 assert_eq!(*e.location.code.source, Source::Unknown);
162 assert_eq!(e.location.range, 1..3);
163 }
164
165 #[test]
166 fn parser_command_namespace() {
167 let mut lexer = Lexer::with_code(" namespace foo { echo; }");
168 let mut parser = Parser::new(&mut lexer);
169
170 let e = parser.command().now_or_never().unwrap().unwrap_err();
171 assert_eq!(
172 e.cause,
173 ErrorCause::Syntax(SyntaxError::UnsupportedNamespaceCommand)
174 );
175 assert_eq!(*e.location.code.value.borrow(), " namespace foo { echo; }");
176 assert_eq!(e.location.code.start_line_number.get(), 1);
177 assert_eq!(*e.location.code.source, Source::Unknown);
178 assert_eq!(e.location.range, 1..10);
179 }
180
181 #[test]
182 fn parser_command_select() {
183 let mut lexer = Lexer::with_code(" select i in a b; do echo; done");
184 let mut parser = Parser::new(&mut lexer);
185
186 let e = parser.command().now_or_never().unwrap().unwrap_err();
187 assert_eq!(
188 e.cause,
189 ErrorCause::Syntax(SyntaxError::UnsupportedSelectCommand)
190 );
191 assert_eq!(
192 *e.location.code.value.borrow(),
193 " select i in a b; do echo; done"
194 );
195 assert_eq!(e.location.code.start_line_number.get(), 1);
196 assert_eq!(*e.location.code.source, Source::Unknown);
197 assert_eq!(e.location.range, 1..7);
198 }
199
200 #[test]
201 fn parser_command_eof() {
202 let mut lexer = Lexer::with_code("");
203 let mut parser = Parser::new(&mut lexer);
204
205 let result = parser.command().now_or_never().unwrap().unwrap();
206 assert_eq!(result, Rec::Parsed(None));
207 }
208}