use nu_protocol::{ ast::Call, engine::{EngineState, Stack, StateWorkingSet}, eval_const::eval_constant, FromValue, ShellError, Value, }; use crate::eval_expression; pub trait CallExt { /// Check if a boolean flag is set (i.e. `--bool` or `--bool=true`) fn has_flag( &self, engine_state: &EngineState, stack: &mut Stack, flag_name: &str, ) -> Result; fn get_flag( &self, engine_state: &EngineState, stack: &mut Stack, name: &str, ) -> Result, ShellError>; fn rest( &self, engine_state: &EngineState, stack: &mut Stack, starting_pos: usize, ) -> Result, ShellError>; fn opt( &self, engine_state: &EngineState, stack: &mut Stack, pos: usize, ) -> Result, ShellError>; fn opt_const( &self, working_set: &StateWorkingSet, pos: usize, ) -> Result, ShellError>; fn req( &self, engine_state: &EngineState, stack: &mut Stack, pos: usize, ) -> Result; fn req_parser_info( &self, engine_state: &EngineState, stack: &mut Stack, name: &str, ) -> Result; } impl CallExt for Call { fn has_flag( &self, engine_state: &EngineState, stack: &mut Stack, flag_name: &str, ) -> Result { for name in self.named_iter() { if flag_name == name.0.item { return if let Some(expr) = &name.2 { // Check --flag=false let result = eval_expression(engine_state, stack, expr)?; match result { Value::Bool { val, .. } => Ok(val), _ => Err(ShellError::CantConvert { to_type: "bool".into(), from_type: result.get_type().to_string(), span: result.span(), help: Some("".into()), }), } } else { Ok(true) }; } } Ok(false) } fn get_flag( &self, engine_state: &EngineState, stack: &mut Stack, name: &str, ) -> Result, ShellError> { if let Some(expr) = self.get_flag_expr(name) { let result = eval_expression(engine_state, stack, expr)?; FromValue::from_value(result).map(Some) } else { Ok(None) } } fn rest( &self, engine_state: &EngineState, stack: &mut Stack, starting_pos: usize, ) -> Result, ShellError> { let mut output = vec![]; for result in self.rest_iter_flattened(starting_pos, |expr| { eval_expression(engine_state, stack, expr) })? { output.push(FromValue::from_value(result)?); } Ok(output) } fn opt( &self, engine_state: &EngineState, stack: &mut Stack, pos: usize, ) -> Result, ShellError> { if let Some(expr) = self.positional_nth(pos) { let result = eval_expression(engine_state, stack, expr)?; FromValue::from_value(result).map(Some) } else { Ok(None) } } fn opt_const( &self, working_set: &StateWorkingSet, pos: usize, ) -> Result, ShellError> { if let Some(expr) = self.positional_nth(pos) { let result = eval_constant(working_set, expr)?; FromValue::from_value(result).map(Some) } else { Ok(None) } } fn req( &self, engine_state: &EngineState, stack: &mut Stack, pos: usize, ) -> Result { if let Some(expr) = self.positional_nth(pos) { let result = eval_expression(engine_state, stack, expr)?; FromValue::from_value(result) } else if self.positional_len() == 0 { Err(ShellError::AccessEmptyContent { span: self.head }) } else { Err(ShellError::AccessBeyondEnd { max_idx: self.positional_len() - 1, span: self.head, }) } } fn req_parser_info( &self, engine_state: &EngineState, stack: &mut Stack, name: &str, ) -> Result { if let Some(expr) = self.get_parser_info(name) { let result = eval_expression(engine_state, stack, expr)?; FromValue::from_value(result) } else if self.parser_info.is_empty() { Err(ShellError::AccessEmptyContent { span: self.head }) } else { Err(ShellError::AccessBeyondEnd { max_idx: self.parser_info.len() - 1, span: self.head, }) } } }