1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 DeclId, FromValue, ShellError, Span, Spanned, Value, ast::Expression, engine::StateWorkingSet,
7 eval_const::eval_constant,
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 DoubleEndedIterator<Item = &(Spanned<String>, Option<Spanned<String>>, Option<Expression>)>
132 {
133 self.arguments.iter().filter_map(|arg| match arg {
134 Argument::Named(named) => Some(named),
135 Argument::Positional(_) => None,
136 Argument::Unknown(_) => None,
137 Argument::Spread(_) => None,
138 })
139 }
140
141 pub fn named_iter_mut(
142 &mut self,
143 ) -> impl Iterator<Item = &mut (Spanned<String>, Option<Spanned<String>>, Option<Expression>)>
144 {
145 self.arguments.iter_mut().filter_map(|arg| match arg {
146 Argument::Named(named) => Some(named),
147 Argument::Positional(_) => None,
148 Argument::Unknown(_) => None,
149 Argument::Spread(_) => None,
150 })
151 }
152
153 pub fn named_len(&self) -> usize {
154 self.named_iter().count()
155 }
156
157 pub fn add_named(
158 &mut self,
159 named: (Spanned<String>, Option<Spanned<String>>, Option<Expression>),
160 ) {
161 self.arguments.push(Argument::Named(named));
162 }
163
164 pub fn add_positional(&mut self, positional: Expression) {
165 self.arguments.push(Argument::Positional(positional));
166 }
167
168 pub fn add_unknown(&mut self, unknown: Expression) {
169 self.arguments.push(Argument::Unknown(unknown));
170 }
171
172 pub fn add_spread(&mut self, args: Expression) {
173 self.arguments.push(Argument::Spread(args));
174 }
175
176 pub fn positional_iter(&self) -> impl Iterator<Item = &Expression> {
177 self.arguments
178 .iter()
179 .take_while(|arg| match arg {
180 Argument::Spread(_) => false, _ => true,
182 })
183 .filter_map(|arg| match arg {
184 Argument::Named(_) => None,
185 Argument::Positional(positional) => Some(positional),
186 Argument::Unknown(unknown) => Some(unknown),
187 Argument::Spread(_) => None,
188 })
189 }
190
191 #[deprecated(since = "0.113.0", note = "use .positional_iter().nth(n) instead")]
192 pub fn positional_nth(&self, i: usize) -> Option<&Expression> {
193 self.positional_iter().nth(i)
194 }
195
196 #[deprecated(since = "0.113.0", note = "use .positional_iter().count(n) instead")]
197 pub fn positional_len(&self) -> usize {
198 self.positional_iter().count()
199 }
200
201 pub fn rest_iter(&self, start: usize) -> impl Iterator<Item = (&Expression, bool)> {
204 let args = self
206 .arguments
207 .iter()
208 .filter_map(|arg| match arg {
209 Argument::Named(_) => None,
210 Argument::Positional(positional) => Some((positional, false)),
211 Argument::Unknown(unknown) => Some((unknown, false)),
212 Argument::Spread(args) => Some((args, true)),
213 })
214 .collect::<Vec<_>>();
215 let spread_start = args.iter().position(|(_, spread)| *spread).unwrap_or(start);
216 args.into_iter().skip(start.min(spread_start))
217 }
218
219 pub fn get_parser_info(&self, name: &str) -> Option<&Expression> {
220 self.parser_info.get(name)
221 }
222
223 pub fn set_parser_info(&mut self, name: String, val: Expression) -> Option<Expression> {
224 self.parser_info.insert(name, val)
225 }
226
227 pub fn set_kth_argument(&mut self, k: usize, arg: Argument) -> bool {
228 self.arguments.get_mut(k).map(|a| *a = arg).is_some()
229 }
230
231 pub fn get_flag_expr(&self, flag_name: &str) -> Option<&Expression> {
232 for name in self.named_iter().rev() {
233 if flag_name == name.0.item {
234 return name.2.as_ref();
235 }
236 }
237
238 None
239 }
240
241 pub fn get_named_arg(&self, flag_name: &str) -> Option<Spanned<String>> {
242 for name in self.named_iter().rev() {
243 if flag_name == name.0.item {
244 return Some(name.0.clone());
245 }
246 }
247
248 None
249 }
250
251 pub fn has_flag_const(
254 &self,
255 working_set: &StateWorkingSet,
256 flag_name: &str,
257 ) -> Result<bool, ShellError> {
258 for name in self.named_iter() {
259 if flag_name == name.0.item {
260 return if let Some(expr) = &name.2 {
261 let result = eval_constant(working_set, expr)?;
263 match result {
264 Value::Bool { val, .. } => Ok(val),
265 _ => Err(ShellError::CantConvert {
266 to_type: "bool".into(),
267 from_type: result.get_type().to_string(),
268 span: result.span(),
269 help: Some("".into()),
270 }),
271 }
272 } else {
273 Ok(true)
274 };
275 }
276 }
277
278 Ok(false)
279 }
280
281 pub fn get_flag_const<T: FromValue>(
282 &self,
283 working_set: &StateWorkingSet,
284 name: &str,
285 ) -> Result<Option<T>, ShellError> {
286 if let Some(expr) = self.get_flag_expr(name) {
287 let result = eval_constant(working_set, expr)?;
288 FromValue::from_value(result).map(Some)
289 } else {
290 Ok(None)
291 }
292 }
293
294 pub fn rest_const<T: FromValue>(
295 &self,
296 working_set: &StateWorkingSet,
297 starting_pos: usize,
298 ) -> Result<Vec<T>, ShellError> {
299 let mut output = vec![];
300
301 for result in
302 self.rest_iter_flattened(starting_pos, |expr| eval_constant(working_set, expr))?
303 {
304 output.push(FromValue::from_value(result)?);
305 }
306
307 Ok(output)
308 }
309
310 pub fn rest_iter_flattened<F>(
311 &self,
312 start: usize,
313 mut eval: F,
314 ) -> Result<Vec<Value>, ShellError>
315 where
316 F: FnMut(&Expression) -> Result<Value, ShellError>,
317 {
318 let mut output = Vec::new();
319
320 for (expr, spread) in self.rest_iter(start) {
321 let result = eval(expr)?;
322 if spread {
323 match result {
324 Value::List { mut vals, .. } => output.append(&mut vals),
325 Value::Nothing { .. } => (),
326 _ => return Err(ShellError::CannotSpreadAsList { span: expr.span }),
327 }
328 } else {
329 output.push(result);
330 }
331 }
332
333 Ok(output)
334 }
335
336 pub fn req_const<T: FromValue>(
337 &self,
338 working_set: &StateWorkingSet,
339 pos: usize,
340 ) -> Result<T, ShellError> {
341 let expr = self.positional_iter().nth(pos).ok_or_else(|| {
342 match self.positional_iter().count().checked_sub(1) {
343 None => ShellError::AccessEmptyContent { span: self.head },
344 Some(n) => ShellError::AccessBeyondEnd {
345 max_idx: n,
346 span: self.head,
347 },
348 }
349 })?;
350
351 let result = eval_constant(working_set, expr)?;
352 FromValue::from_value(result)
353 }
354
355 pub fn span(&self) -> Span {
356 self.head.merge(self.arguments_span())
357 }
358}
359
360#[cfg(test)]
361mod test {
362 use super::*;
363 use crate::engine::EngineState;
364
365 #[test]
366 fn argument_span_named() {
367 let engine_state = EngineState::new();
368 let mut working_set = StateWorkingSet::new(&engine_state);
369
370 let named = Spanned {
371 item: "named".to_string(),
372 span: Span::new(2, 3),
373 };
374 let short = Spanned {
375 item: "short".to_string(),
376 span: Span::new(5, 7),
377 };
378 let expr = Expression::garbage(&mut working_set, Span::new(11, 13));
379
380 let arg = Argument::Named((named.clone(), None, None));
381
382 assert_eq!(Span::new(2, 3), arg.span());
383
384 let arg = Argument::Named((named.clone(), Some(short.clone()), None));
385
386 assert_eq!(Span::new(2, 7), arg.span());
387
388 let arg = Argument::Named((named.clone(), None, Some(expr.clone())));
389
390 assert_eq!(Span::new(2, 13), arg.span());
391
392 let arg = Argument::Named((named.clone(), Some(short.clone()), Some(expr.clone())));
393
394 assert_eq!(Span::new(2, 13), arg.span());
395 }
396
397 #[test]
398 fn argument_span_positional() {
399 let engine_state = EngineState::new();
400 let mut working_set = StateWorkingSet::new(&engine_state);
401
402 let span = Span::new(2, 3);
403 let expr = Expression::garbage(&mut working_set, span);
404 let arg = Argument::Positional(expr);
405
406 assert_eq!(span, arg.span());
407 }
408
409 #[test]
410 fn argument_span_unknown() {
411 let engine_state = EngineState::new();
412 let mut working_set = StateWorkingSet::new(&engine_state);
413
414 let span = Span::new(2, 3);
415 let expr = Expression::garbage(&mut working_set, span);
416 let arg = Argument::Unknown(expr);
417
418 assert_eq!(span, arg.span());
419 }
420
421 #[test]
422 fn call_arguments_span() {
423 let engine_state = EngineState::new();
424 let mut working_set = StateWorkingSet::new(&engine_state);
425
426 let mut call = Call::new(Span::new(0, 1));
427 call.add_positional(Expression::garbage(&mut working_set, Span::new(2, 3)));
428 call.add_positional(Expression::garbage(&mut working_set, Span::new(5, 7)));
429
430 assert_eq!(Span::new(2, 7), call.arguments_span());
431 }
432}