1use crate::eval_expression;
2use crate::named_flags::flag_type_accepts_nothing;
3use nu_protocol::{
4 FromValue, ShellError, Span, Value, ast,
5 debugger::WithoutDebug,
6 engine::{self, EngineState, Stack, StateWorkingSet},
7 eval_const::eval_constant,
8 ir,
9};
10
11pub trait CallExt {
12 fn has_flag(
14 &self,
15 engine_state: &EngineState,
16 stack: &mut Stack,
17 flag_name: &str,
18 ) -> Result<bool, ShellError>;
19
20 fn get_flag<T: FromValue>(
21 &self,
22 engine_state: &EngineState,
23 stack: &mut Stack,
24 name: &str,
25 ) -> Result<Option<T>, ShellError>;
26
27 fn get_flag_span(&self, stack: &Stack, name: &str) -> Option<Span>;
29
30 fn rest<T: FromValue>(
31 &self,
32 engine_state: &EngineState,
33 stack: &mut Stack,
34 starting_pos: usize,
35 ) -> Result<Vec<T>, ShellError>;
36
37 fn rest_preserving_spreads<T: FromValue>(
43 &self,
44 engine_state: &EngineState,
45 stack: &mut Stack,
46 starting_pos: usize,
47 ) -> Result<Vec<(T, bool)>, ShellError>;
48
49 fn opt<T: FromValue>(
50 &self,
51 engine_state: &EngineState,
52 stack: &mut Stack,
53 pos: usize,
54 ) -> Result<Option<T>, ShellError>;
55
56 fn opt_const<T: FromValue>(
57 &self,
58 working_set: &StateWorkingSet,
59 stack: &Stack,
60 pos: usize,
61 ) -> Result<Option<T>, ShellError>;
62
63 fn req<T: FromValue>(
64 &self,
65 engine_state: &EngineState,
66 stack: &mut Stack,
67 pos: usize,
68 ) -> Result<T, ShellError>;
69
70 fn req_parser_info<T: FromValue>(
71 &self,
72 engine_state: &EngineState,
73 stack: &mut Stack,
74 name: &str,
75 ) -> Result<T, ShellError>;
76
77 fn has_positional_args(&self, stack: &Stack, starting_pos: usize) -> bool;
79}
80
81impl CallExt for ast::Call {
82 fn has_flag(
83 &self,
84 engine_state: &EngineState,
85 stack: &mut Stack,
86 flag_name: &str,
87 ) -> Result<bool, ShellError> {
88 for name in self.named_iter() {
89 if flag_name == name.0.item {
90 return if let Some(expr) = &name.2 {
91 let stack = &mut stack.use_call_arg_out_dest();
93 let result = eval_expression::<WithoutDebug>(engine_state, stack, expr)?;
94 match result {
95 Value::Bool { val, .. } => Ok(val),
96 _ => Err(ShellError::CantConvert {
97 to_type: "bool".into(),
98 from_type: result.get_type().to_string(),
99 span: result.span(),
100 help: Some("".into()),
101 }),
102 }
103 } else {
104 Ok(true)
105 };
106 }
107 }
108
109 Ok(false)
110 }
111
112 fn get_flag<T: FromValue>(
113 &self,
114 engine_state: &EngineState,
115 stack: &mut Stack,
116 name: &str,
117 ) -> Result<Option<T>, ShellError> {
118 if let Some(expr) = self.get_flag_expr(name) {
119 let stack = &mut stack.use_call_arg_out_dest();
120 let result = eval_expression::<WithoutDebug>(engine_state, stack, expr)?;
121 if result.is_nothing() {
124 let accepts = engine_state
125 .get_decl(self.decl_id)
126 .signature()
127 .get_long_flag(name)
128 .is_some_and(|flag| flag_type_accepts_nothing(&flag));
129 if !accepts {
130 return Ok(None);
131 }
132 }
133 FromValue::from_value(result).map(Some)
134 } else {
135 Ok(None)
136 }
137 }
138
139 fn get_flag_span(&self, _stack: &Stack, name: &str) -> Option<Span> {
140 self.get_named_arg(name).map(|arg| arg.span)
141 }
142
143 fn rest<T: FromValue>(
144 &self,
145 engine_state: &EngineState,
146 stack: &mut Stack,
147 starting_pos: usize,
148 ) -> Result<Vec<T>, ShellError> {
149 let stack = &mut stack.use_call_arg_out_dest();
150 self.rest_iter_flattened(starting_pos, |expr| {
151 eval_expression::<WithoutDebug>(engine_state, stack, expr)
152 })?
153 .into_iter()
154 .map(FromValue::from_value)
155 .collect()
156 }
157
158 fn rest_preserving_spreads<T: FromValue>(
159 &self,
160 engine_state: &EngineState,
161 stack: &mut Stack,
162 starting_pos: usize,
163 ) -> Result<Vec<(T, bool)>, ShellError> {
164 let stack = &mut stack.use_call_arg_out_dest();
165 self.rest_iter(starting_pos)
166 .map(|(expr, is_spread)| {
167 let result = eval_expression::<WithoutDebug>(engine_state, stack, expr)?;
168 Ok((T::from_value(result)?, is_spread))
169 })
170 .collect()
171 }
172
173 fn opt<T: FromValue>(
174 &self,
175 engine_state: &EngineState,
176 stack: &mut Stack,
177 pos: usize,
178 ) -> Result<Option<T>, ShellError> {
179 if let Some(expr) = self.positional_iter().nth(pos) {
180 let stack = &mut stack.use_call_arg_out_dest();
181 let result = eval_expression::<WithoutDebug>(engine_state, stack, expr)?;
182 if result.is_nothing() {
183 Ok(None)
184 } else {
185 FromValue::from_value(result).map(Some)
186 }
187 } else {
188 Ok(None)
189 }
190 }
191
192 fn opt_const<T: FromValue>(
193 &self,
194 working_set: &StateWorkingSet,
195 _stack: &Stack,
196 pos: usize,
197 ) -> Result<Option<T>, ShellError> {
198 if let Some(expr) = self.positional_iter().nth(pos) {
199 let result = eval_constant(working_set, expr)?;
200 if result.is_nothing() {
201 Ok(None)
202 } else {
203 FromValue::from_value(result).map(Some)
204 }
205 } else {
206 Ok(None)
207 }
208 }
209
210 fn req<T: FromValue>(
211 &self,
212 engine_state: &EngineState,
213 stack: &mut Stack,
214 pos: usize,
215 ) -> Result<T, ShellError> {
216 let maybe_expr = self.positional_iter().nth(pos);
217 let expr = maybe_expr.ok_or_else(|| {
218 let max_idx = self.positional_iter().count().checked_sub(1);
219 match max_idx {
220 None => ShellError::AccessEmptyContent { span: self.head },
221 Some(max_idx) => ShellError::AccessBeyondEnd {
222 max_idx,
223 span: self.head,
224 },
225 }
226 })?;
227
228 let stack = &mut stack.use_call_arg_out_dest();
229 let result = eval_expression::<WithoutDebug>(engine_state, stack, expr)?;
230 FromValue::from_value(result)
231 }
232
233 fn req_parser_info<T: FromValue>(
234 &self,
235 engine_state: &EngineState,
236 stack: &mut Stack,
237 name: &str,
238 ) -> Result<T, ShellError> {
239 if let Some(expr) = self.get_parser_info(name) {
240 let stack = &mut stack.use_call_arg_out_dest();
241 let result = eval_expression::<WithoutDebug>(engine_state, stack, expr)?;
242 FromValue::from_value(result)
243 } else if self.parser_info.is_empty() {
244 Err(ShellError::AccessEmptyContent { span: self.head })
245 } else {
246 Err(ShellError::AccessBeyondEnd {
247 max_idx: self.parser_info.len() - 1,
248 span: self.head,
249 })
250 }
251 }
252
253 fn has_positional_args(&self, _stack: &Stack, starting_pos: usize) -> bool {
254 self.rest_iter(starting_pos).next().is_some()
255 }
256}
257
258impl CallExt for ir::Call {
259 fn has_flag(
260 &self,
261 _engine_state: &EngineState,
262 stack: &mut Stack,
263 flag_name: &str,
264 ) -> Result<bool, ShellError> {
265 Ok(self
266 .named_iter(stack)
267 .find(|(name, _)| name.item == flag_name)
268 .is_some_and(|(_, value)| {
269 !matches!(value, Some(Value::Bool { val: false, .. }))
271 }))
272 }
273
274 fn get_flag<T: FromValue>(
275 &self,
276 _engine_state: &EngineState,
277 stack: &mut Stack,
278 name: &str,
279 ) -> Result<Option<T>, ShellError> {
280 if let Some(val) = self.get_named_arg(stack, name) {
283 T::from_value(val.clone()).map(Some)
284 } else {
285 Ok(None)
286 }
287 }
288
289 fn get_flag_span(&self, stack: &Stack, name: &str) -> Option<Span> {
290 self.named_iter(stack)
291 .find_map(|(i_name, _)| (i_name.item == name).then_some(i_name.span))
292 }
293
294 fn rest<T: FromValue>(
295 &self,
296 _engine_state: &EngineState,
297 stack: &mut Stack,
298 starting_pos: usize,
299 ) -> Result<Vec<T>, ShellError> {
300 self.rest_iter_flattened(stack, starting_pos)?
301 .into_iter()
302 .map(T::from_value)
303 .collect()
304 }
305
306 fn rest_preserving_spreads<T: FromValue>(
307 &self,
308 _engine_state: &EngineState,
309 stack: &mut Stack,
310 starting_pos: usize,
311 ) -> Result<Vec<(T, bool)>, ShellError> {
312 self.rest_iter(stack, starting_pos)
313 .map(|(val, is_spread)| Ok((T::from_value(val.clone())?, is_spread)))
314 .collect()
315 }
316
317 fn opt<T: FromValue>(
318 &self,
319 _engine_state: &EngineState,
320 stack: &mut Stack,
321 pos: usize,
322 ) -> Result<Option<T>, ShellError> {
323 self.positional_iter(stack)
324 .nth(pos)
325 .filter(|v| !v.is_nothing())
326 .cloned()
327 .map(T::from_value)
328 .transpose()
329 }
330
331 fn opt_const<T: FromValue>(
332 &self,
333 _working_set: &StateWorkingSet,
334 stack: &Stack,
335 pos: usize,
336 ) -> Result<Option<T>, ShellError> {
337 self.positional_iter(stack)
338 .nth(pos)
339 .filter(|v| !v.is_nothing())
340 .cloned()
341 .map(T::from_value)
342 .transpose()
343 }
344
345 fn req<T: FromValue>(
346 &self,
347 _engine_state: &EngineState,
348 stack: &mut Stack,
349 pos: usize,
350 ) -> Result<T, ShellError> {
351 let maybe_val = self.positional_iter(stack).nth(pos).cloned();
352 let val = maybe_val.ok_or_else(|| {
353 let max_idx = self.positional_iter(stack).count().checked_sub(1);
354 match max_idx {
355 None => ShellError::AccessEmptyContent { span: self.head },
356 Some(max_idx) => ShellError::AccessBeyondEnd {
357 max_idx,
358 span: self.head,
359 },
360 }
361 })?;
362
363 T::from_value(val)
364 }
365
366 fn req_parser_info<T: FromValue>(
367 &self,
368 engine_state: &EngineState,
369 stack: &mut Stack,
370 name: &str,
371 ) -> Result<T, ShellError> {
372 if let Some(expr) = self.get_parser_info(stack, name) {
376 let expr = expr.clone();
377 let stack = &mut stack.use_call_arg_out_dest();
378 let result = eval_expression::<WithoutDebug>(engine_state, stack, &expr)?;
379 FromValue::from_value(result)
380 } else {
381 Err(ShellError::CantFindColumn {
382 col_name: name.into(),
383 span: None,
384 src_span: self.head,
385 })
386 }
387 }
388
389 fn has_positional_args(&self, stack: &Stack, starting_pos: usize) -> bool {
390 self.rest_iter(stack, starting_pos).next().is_some()
391 }
392}
393
394macro_rules! proxy {
395 ($self:ident . $method:ident ($($param:expr),*)) => (match &$self.inner {
396 engine::CallImpl::AstRef(call) => call.$method($($param),*),
397 engine::CallImpl::AstBox(call) => call.$method($($param),*),
398 engine::CallImpl::IrRef(call) => call.$method($($param),*),
399 engine::CallImpl::IrBox(call) => call.$method($($param),*),
400 })
401}
402
403impl CallExt for engine::Call<'_> {
404 fn has_flag(
405 &self,
406 engine_state: &EngineState,
407 stack: &mut Stack,
408 flag_name: &str,
409 ) -> Result<bool, ShellError> {
410 proxy!(self.has_flag(engine_state, stack, flag_name))
411 }
412
413 fn get_flag<T: FromValue>(
414 &self,
415 engine_state: &EngineState,
416 stack: &mut Stack,
417 name: &str,
418 ) -> Result<Option<T>, ShellError> {
419 proxy!(self.get_flag(engine_state, stack, name))
420 }
421
422 fn get_flag_span(&self, stack: &Stack, name: &str) -> Option<Span> {
423 proxy!(self.get_flag_span(stack, name))
424 }
425
426 fn rest<T: FromValue>(
427 &self,
428 engine_state: &EngineState,
429 stack: &mut Stack,
430 starting_pos: usize,
431 ) -> Result<Vec<T>, ShellError> {
432 proxy!(self.rest(engine_state, stack, starting_pos))
433 }
434
435 fn rest_preserving_spreads<T: FromValue>(
436 &self,
437 engine_state: &EngineState,
438 stack: &mut Stack,
439 starting_pos: usize,
440 ) -> Result<Vec<(T, bool)>, ShellError> {
441 proxy!(self.rest_preserving_spreads(engine_state, stack, starting_pos))
442 }
443
444 fn opt<T: FromValue>(
445 &self,
446 engine_state: &EngineState,
447 stack: &mut Stack,
448 pos: usize,
449 ) -> Result<Option<T>, ShellError> {
450 proxy!(self.opt(engine_state, stack, pos))
451 }
452
453 fn opt_const<T: FromValue>(
454 &self,
455 working_set: &StateWorkingSet,
456 stack: &Stack,
457 pos: usize,
458 ) -> Result<Option<T>, ShellError> {
459 proxy!(self.opt_const(working_set, stack, pos))
460 }
461
462 fn req<T: FromValue>(
463 &self,
464 engine_state: &EngineState,
465 stack: &mut Stack,
466 pos: usize,
467 ) -> Result<T, ShellError> {
468 proxy!(self.req(engine_state, stack, pos))
469 }
470
471 fn req_parser_info<T: FromValue>(
472 &self,
473 engine_state: &EngineState,
474 stack: &mut Stack,
475 name: &str,
476 ) -> Result<T, ShellError> {
477 proxy!(self.req_parser_info(engine_state, stack, name))
478 }
479
480 fn has_positional_args(&self, stack: &Stack, starting_pos: usize) -> bool {
481 proxy!(self.has_positional_args(stack, starting_pos))
482 }
483}