1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 ast::Expression, engine::StateWorkingSet, eval_const::eval_constant, DeclId, FromValue,
7 ShellError, Span, Spanned, Value,
8};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub enum Argument {
15 Positional(Expression),
21 Named((Spanned<String>, Option<Spanned<String>>, Option<Expression>)),
30 Unknown(Expression),
32 Spread(Expression),
34}
35
36impl Argument {
37 pub fn span(&self) -> Span {
39 match self {
40 Argument::Positional(e) => e.span,
41 Argument::Named((named, short, expr)) => {
42 let start = named.span.start;
43 let end = if let Some(expr) = expr {
44 expr.span.end
45 } else if let Some(short) = short {
46 short.span.end
47 } else {
48 named.span.end
49 };
50
51 Span::new(start, end)
52 }
53 Argument::Unknown(e) => e.span,
54 Argument::Spread(e) => e.span,
55 }
56 }
57
58 pub fn expr(&self) -> Option<&Expression> {
59 match self {
60 Argument::Named((_, _, expr)) => expr.as_ref(),
61 Argument::Positional(expr) | Argument::Unknown(expr) | Argument::Spread(expr) => {
62 Some(expr)
63 }
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
72pub enum ExternalArgument {
73 Regular(Expression),
75 Spread(Expression),
77}
78
79impl ExternalArgument {
80 pub fn expr(&self) -> &Expression {
81 match self {
82 ExternalArgument::Regular(expr) => expr,
83 ExternalArgument::Spread(expr) => expr,
84 }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
96pub struct Call {
97 pub decl_id: DeclId,
99 pub head: Span,
100 pub arguments: Vec<Argument>,
101 pub parser_info: HashMap<String, Expression>,
103}
104
105impl Call {
106 pub fn new(head: Span) -> Call {
107 Self {
108 decl_id: DeclId::new(0),
109 head,
110 arguments: vec![],
111 parser_info: HashMap::new(),
112 }
113 }
114
115 pub fn arguments_span(&self) -> Span {
122 if self.arguments.is_empty() {
123 self.head.past()
124 } else {
125 Span::merge_many(self.arguments.iter().map(|a| a.span()))
126 }
127 }
128
129 pub fn named_iter(
130 &self,
131 ) -> impl Iterator<Item = &(Spanned<String>, Option<Spanned<String>>, Option<Expression>)> {
132 self.arguments.iter().filter_map(|arg| match arg {
133 Argument::Named(named) => Some(named),
134 Argument::Positional(_) => None,
135 Argument::Unknown(_) => None,
136 Argument::Spread(_) => None,
137 })
138 }
139
140 pub fn named_iter_mut(
141 &mut self,
142 ) -> impl Iterator<Item = &mut (Spanned<String>, Option<Spanned<String>>, Option<Expression>)>
143 {
144 self.arguments.iter_mut().filter_map(|arg| match arg {
145 Argument::Named(named) => Some(named),
146 Argument::Positional(_) => None,
147 Argument::Unknown(_) => None,
148 Argument::Spread(_) => None,
149 })
150 }
151
152 pub fn named_len(&self) -> usize {
153 self.named_iter().count()
154 }
155
156 pub fn add_named(
157 &mut self,
158 named: (Spanned<String>, Option<Spanned<String>>, Option<Expression>),
159 ) {
160 self.arguments.push(Argument::Named(named));
161 }
162
163 pub fn add_positional(&mut self, positional: Expression) {
164 self.arguments.push(Argument::Positional(positional));
165 }
166
167 pub fn add_unknown(&mut self, unknown: Expression) {
168 self.arguments.push(Argument::Unknown(unknown));
169 }
170
171 pub fn add_spread(&mut self, args: Expression) {
172 self.arguments.push(Argument::Spread(args));
173 }
174
175 pub fn positional_iter(&self) -> impl Iterator<Item = &Expression> {
176 self.arguments
177 .iter()
178 .take_while(|arg| match arg {
179 Argument::Spread(_) => false, _ => true,
181 })
182 .filter_map(|arg| match arg {
183 Argument::Named(_) => None,
184 Argument::Positional(positional) => Some(positional),
185 Argument::Unknown(unknown) => Some(unknown),
186 Argument::Spread(_) => None,
187 })
188 }
189
190 pub fn positional_nth(&self, i: usize) -> Option<&Expression> {
191 self.positional_iter().nth(i)
192 }
193
194 pub fn positional_len(&self) -> usize {
195 self.positional_iter().count()
196 }
197
198 pub fn rest_iter(&self, start: usize) -> impl Iterator<Item = (&Expression, bool)> {
201 let args = self
203 .arguments
204 .iter()
205 .filter_map(|arg| match arg {
206 Argument::Named(_) => None,
207 Argument::Positional(positional) => Some((positional, false)),
208 Argument::Unknown(unknown) => Some((unknown, false)),
209 Argument::Spread(args) => Some((args, true)),
210 })
211 .collect::<Vec<_>>();
212 let spread_start = args.iter().position(|(_, spread)| *spread).unwrap_or(start);
213 args.into_iter().skip(start.min(spread_start))
214 }
215
216 pub fn get_parser_info(&self, name: &str) -> Option<&Expression> {
217 self.parser_info.get(name)
218 }
219
220 pub fn set_parser_info(&mut self, name: String, val: Expression) -> Option<Expression> {
221 self.parser_info.insert(name, val)
222 }
223
224 pub fn get_flag_expr(&self, flag_name: &str) -> Option<&Expression> {
225 for name in self.named_iter() {
226 if flag_name == name.0.item {
227 return name.2.as_ref();
228 }
229 }
230
231 None
232 }
233
234 pub fn get_named_arg(&self, flag_name: &str) -> Option<Spanned<String>> {
235 for name in self.named_iter() {
236 if flag_name == name.0.item {
237 return Some(name.0.clone());
238 }
239 }
240
241 None
242 }
243
244 pub fn has_flag_const(
247 &self,
248 working_set: &StateWorkingSet,
249 flag_name: &str,
250 ) -> Result<bool, ShellError> {
251 for name in self.named_iter() {
252 if flag_name == name.0.item {
253 return if let Some(expr) = &name.2 {
254 let result = eval_constant(working_set, expr)?;
256 match result {
257 Value::Bool { val, .. } => Ok(val),
258 _ => Err(ShellError::CantConvert {
259 to_type: "bool".into(),
260 from_type: result.get_type().to_string(),
261 span: result.span(),
262 help: Some("".into()),
263 }),
264 }
265 } else {
266 Ok(true)
267 };
268 }
269 }
270
271 Ok(false)
272 }
273
274 pub fn get_flag_const<T: FromValue>(
275 &self,
276 working_set: &StateWorkingSet,
277 name: &str,
278 ) -> Result<Option<T>, ShellError> {
279 if let Some(expr) = self.get_flag_expr(name) {
280 let result = eval_constant(working_set, expr)?;
281 FromValue::from_value(result).map(Some)
282 } else {
283 Ok(None)
284 }
285 }
286
287 pub fn rest_const<T: FromValue>(
288 &self,
289 working_set: &StateWorkingSet,
290 starting_pos: usize,
291 ) -> Result<Vec<T>, ShellError> {
292 let mut output = vec![];
293
294 for result in
295 self.rest_iter_flattened(starting_pos, |expr| eval_constant(working_set, expr))?
296 {
297 output.push(FromValue::from_value(result)?);
298 }
299
300 Ok(output)
301 }
302
303 pub fn rest_iter_flattened<F>(
304 &self,
305 start: usize,
306 mut eval: F,
307 ) -> Result<Vec<Value>, ShellError>
308 where
309 F: FnMut(&Expression) -> Result<Value, ShellError>,
310 {
311 let mut output = Vec::new();
312
313 for (expr, spread) in self.rest_iter(start) {
314 let result = eval(expr)?;
315 if spread {
316 match result {
317 Value::List { mut vals, .. } => output.append(&mut vals),
318 _ => return Err(ShellError::CannotSpreadAsList { span: expr.span }),
319 }
320 } else {
321 output.push(result);
322 }
323 }
324
325 Ok(output)
326 }
327
328 pub fn req_const<T: FromValue>(
329 &self,
330 working_set: &StateWorkingSet,
331 pos: usize,
332 ) -> Result<T, ShellError> {
333 if let Some(expr) = self.positional_nth(pos) {
334 let result = eval_constant(working_set, expr)?;
335 FromValue::from_value(result)
336 } else if self.positional_len() == 0 {
337 Err(ShellError::AccessEmptyContent { span: self.head })
338 } else {
339 Err(ShellError::AccessBeyondEnd {
340 max_idx: self.positional_len() - 1,
341 span: self.head,
342 })
343 }
344 }
345
346 pub fn span(&self) -> Span {
347 self.head.merge(self.arguments_span())
348 }
349}
350
351#[cfg(test)]
352mod test {
353 use super::*;
354 use crate::engine::EngineState;
355
356 #[test]
357 fn argument_span_named() {
358 let engine_state = EngineState::new();
359 let mut working_set = StateWorkingSet::new(&engine_state);
360
361 let named = Spanned {
362 item: "named".to_string(),
363 span: Span::new(2, 3),
364 };
365 let short = Spanned {
366 item: "short".to_string(),
367 span: Span::new(5, 7),
368 };
369 let expr = Expression::garbage(&mut working_set, Span::new(11, 13));
370
371 let arg = Argument::Named((named.clone(), None, None));
372
373 assert_eq!(Span::new(2, 3), arg.span());
374
375 let arg = Argument::Named((named.clone(), Some(short.clone()), None));
376
377 assert_eq!(Span::new(2, 7), arg.span());
378
379 let arg = Argument::Named((named.clone(), None, Some(expr.clone())));
380
381 assert_eq!(Span::new(2, 13), arg.span());
382
383 let arg = Argument::Named((named.clone(), Some(short.clone()), Some(expr.clone())));
384
385 assert_eq!(Span::new(2, 13), arg.span());
386 }
387
388 #[test]
389 fn argument_span_positional() {
390 let engine_state = EngineState::new();
391 let mut working_set = StateWorkingSet::new(&engine_state);
392
393 let span = Span::new(2, 3);
394 let expr = Expression::garbage(&mut working_set, span);
395 let arg = Argument::Positional(expr);
396
397 assert_eq!(span, arg.span());
398 }
399
400 #[test]
401 fn argument_span_unknown() {
402 let engine_state = EngineState::new();
403 let mut working_set = StateWorkingSet::new(&engine_state);
404
405 let span = Span::new(2, 3);
406 let expr = Expression::garbage(&mut working_set, span);
407 let arg = Argument::Unknown(expr);
408
409 assert_eq!(span, arg.span());
410 }
411
412 #[test]
413 fn call_arguments_span() {
414 let engine_state = EngineState::new();
415 let mut working_set = StateWorkingSet::new(&engine_state);
416
417 let mut call = Call::new(Span::new(0, 1));
418 call.add_positional(Expression::garbage(&mut working_set, Span::new(2, 3)));
419 call.add_positional(Expression::garbage(&mut working_set, Span::new(5, 7)));
420
421 assert_eq!(Span::new(2, 7), call.arguments_span());
422 }
423}