From f02ab3e23152e3fa0bc00ccd4b2b4276e81c6f0c Mon Sep 17 00:00:00 2001 From: Devyn Cairns Date: Fri, 14 Jun 2024 16:58:25 -0700 Subject: [PATCH] check behavior, do CallExt for ir::Call, engine::Call --- crates/nu-engine/src/call_ext.rs | 176 +++++++++++++++++++++++++- crates/nu-protocol/src/engine/call.rs | 4 +- crates/nu-protocol/src/ir/call.rs | 37 ++++-- 3 files changed, 199 insertions(+), 18 deletions(-) diff --git a/crates/nu-engine/src/call_ext.rs b/crates/nu-engine/src/call_ext.rs index daedb24a1f..0cbea61370 100644 --- a/crates/nu-engine/src/call_ext.rs +++ b/crates/nu-engine/src/call_ext.rs @@ -2,9 +2,9 @@ use crate::eval_expression; use nu_protocol::{ ast::Call, debugger::WithoutDebug, - engine::{EngineState, Stack, StateWorkingSet}, + engine::{self, CallImpl, EngineState, Stack, StateWorkingSet}, eval_const::eval_constant, - FromValue, ShellError, Value, + ir, FromValue, ShellError, Value, }; pub trait CallExt { @@ -190,3 +190,175 @@ impl CallExt for Call { } } } + +impl CallExt for ir::Call<'_> { + fn has_flag( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + flag_name: &str, + ) -> Result { + Ok(self + .named_iter() + .find(|(name, _)| *name == flag_name) + .is_some()) + } + + fn get_flag( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + name: &str, + ) -> Result, ShellError> { + if let Some(val) = self.get_named_arg(name) { + T::from_value(val.clone()).map(Some) + } else { + Ok(None) + } + } + + fn rest( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + starting_pos: usize, + ) -> Result, ShellError> { + self.rest_iter_flattened(starting_pos)? + .into_iter() + .map(T::from_value) + .collect() + } + + fn opt( + &self, + _engine_state: &EngineState, + _stack: &mut Stack, + pos: usize, + ) -> Result, ShellError> { + self.positional_iter() + .nth(pos) + .cloned() + .map(T::from_value) + .transpose() + } + + fn opt_const( + &self, + working_set: &StateWorkingSet, + pos: usize, + ) -> Result, ShellError> { + todo!("opt_const is not yet implemented on ir::Call") + } + + fn req( + &self, + engine_state: &EngineState, + stack: &mut Stack, + pos: usize, + ) -> Result { + if let Some(val) = self.opt(engine_state, stack, pos)? { + Ok(val) + } 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 { + todo!("req_parser_info is not yet implemented on ir::Call") + } +} + +impl CallExt for engine::Call<'_> { + fn has_flag( + &self, + engine_state: &EngineState, + stack: &mut Stack, + flag_name: &str, + ) -> Result { + match &self.inner { + CallImpl::Ast(ast_call) => ast_call.has_flag(engine_state, stack, flag_name), + CallImpl::Ir(ir_call) => ir_call.has_flag(engine_state, stack, flag_name), + } + } + + fn get_flag( + &self, + engine_state: &EngineState, + stack: &mut Stack, + name: &str, + ) -> Result, ShellError> { + match &self.inner { + CallImpl::Ast(ast_call) => ast_call.get_flag(engine_state, stack, name), + CallImpl::Ir(ir_call) => ir_call.get_flag(engine_state, stack, name), + } + } + + fn rest( + &self, + engine_state: &EngineState, + stack: &mut Stack, + starting_pos: usize, + ) -> Result, ShellError> { + match &self.inner { + CallImpl::Ast(ast_call) => ast_call.rest(engine_state, stack, starting_pos), + CallImpl::Ir(ir_call) => ir_call.rest(engine_state, stack, starting_pos), + } + } + + fn opt( + &self, + engine_state: &EngineState, + stack: &mut Stack, + pos: usize, + ) -> Result, ShellError> { + match &self.inner { + CallImpl::Ast(ast_call) => ast_call.opt(engine_state, stack, pos), + CallImpl::Ir(ir_call) => ir_call.opt(engine_state, stack, pos), + } + } + + fn opt_const( + &self, + working_set: &StateWorkingSet, + pos: usize, + ) -> Result, ShellError> { + match &self.inner { + CallImpl::Ast(ast_call) => ast_call.opt_const(working_set, pos), + CallImpl::Ir(ir_call) => ir_call.opt_const(working_set, pos), + } + } + + fn req( + &self, + engine_state: &EngineState, + stack: &mut Stack, + pos: usize, + ) -> Result { + match &self.inner { + CallImpl::Ast(ast_call) => ast_call.req(engine_state, stack, pos), + CallImpl::Ir(ir_call) => ir_call.req(engine_state, stack, pos), + } + } + + fn req_parser_info( + &self, + engine_state: &EngineState, + stack: &mut Stack, + name: &str, + ) -> Result { + match &self.inner { + CallImpl::Ast(ast_call) => ast_call.req_parser_info(engine_state, stack, name), + CallImpl::Ir(ir_call) => ir_call.req_parser_info(engine_state, stack, name), + } + } +} diff --git a/crates/nu-protocol/src/engine/call.rs b/crates/nu-protocol/src/engine/call.rs index cfaa7d2cca..525ad1e1f0 100644 --- a/crates/nu-protocol/src/engine/call.rs +++ b/crates/nu-protocol/src/engine/call.rs @@ -6,11 +6,11 @@ use crate::{ast, ir, Span}; #[derive(Debug, Clone)] pub struct Call<'a> { pub head: Span, - inner: CallImpl<'a>, + pub inner: CallImpl<'a>, } #[derive(Debug, Clone)] -enum CallImpl<'a> { +pub enum CallImpl<'a> { Ast(&'a ast::Call), Ir(ir::Call<'a>), } diff --git a/crates/nu-protocol/src/ir/call.rs b/crates/nu-protocol/src/ir/call.rs index 0bec7acc44..b65378056d 100644 --- a/crates/nu-protocol/src/ir/call.rs +++ b/crates/nu-protocol/src/ir/call.rs @@ -115,24 +115,33 @@ impl<'a> Call<'a> { self.positional_iter().nth(index) } - pub fn rest_iter(&self) -> impl Iterator { - self.arg_refs().filter_map(|arg| match arg { - ArgRef::Spread(value) => Some(value), - _ => None, - }) + /// Returns every argument to the rest parameter, as well as whether each argument + /// is spread or a normal positional argument (true for spread, false for normal) + pub fn rest_iter(&self, start: usize) -> impl Iterator { + self.arg_refs() + .filter_map(|arg| match arg { + ArgRef::Positional(value) => Some((value, false)), + ArgRef::Spread(value) => Some((value, true)), + _ => None, + }) + .skip(start) } - pub fn rest_iter_flattened(&self) -> Result, ShellError> { + pub fn rest_iter_flattened(&self, start: usize) -> Result, ShellError> { let mut acc = vec![]; - for rest_val in self.rest_iter() { - match rest_val { - Value::List { vals, .. } => acc.extend(vals.iter().cloned()), - Value::Error { error, .. } => return Err(ShellError::clone(error)), - _ => { - return Err(ShellError::CannotSpreadAsList { - span: rest_val.span(), - }) + for (rest_val, spread) in self.rest_iter(start) { + if spread { + match rest_val { + Value::List { vals, .. } => acc.extend(vals.iter().cloned()), + Value::Error { error, .. } => return Err(ShellError::clone(error)), + _ => { + return Err(ShellError::CannotSpreadAsList { + span: rest_val.span(), + }) + } } + } else { + acc.push(rest_val.clone()); } } Ok(acc)