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