check behavior, do CallExt for ir::Call, engine::Call

This commit is contained in:
Devyn Cairns 2024-06-14 16:58:25 -07:00
parent 6a2dc99717
commit f02ab3e231
No known key found for this signature in database
3 changed files with 199 additions and 18 deletions

View File

@ -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<bool, ShellError> {
Ok(self
.named_iter()
.find(|(name, _)| *name == flag_name)
.is_some())
}
fn get_flag<T: FromValue>(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
name: &str,
) -> Result<Option<T>, ShellError> {
if let Some(val) = self.get_named_arg(name) {
T::from_value(val.clone()).map(Some)
} else {
Ok(None)
}
}
fn rest<T: FromValue>(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
starting_pos: usize,
) -> Result<Vec<T>, ShellError> {
self.rest_iter_flattened(starting_pos)?
.into_iter()
.map(T::from_value)
.collect()
}
fn opt<T: FromValue>(
&self,
_engine_state: &EngineState,
_stack: &mut Stack,
pos: usize,
) -> Result<Option<T>, ShellError> {
self.positional_iter()
.nth(pos)
.cloned()
.map(T::from_value)
.transpose()
}
fn opt_const<T: FromValue>(
&self,
working_set: &StateWorkingSet,
pos: usize,
) -> Result<Option<T>, ShellError> {
todo!("opt_const is not yet implemented on ir::Call")
}
fn req<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
pos: usize,
) -> Result<T, ShellError> {
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<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
name: &str,
) -> Result<T, ShellError> {
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<bool, ShellError> {
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<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
name: &str,
) -> Result<Option<T>, 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<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
starting_pos: usize,
) -> Result<Vec<T>, 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<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
pos: usize,
) -> Result<Option<T>, 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<T: FromValue>(
&self,
working_set: &StateWorkingSet,
pos: usize,
) -> Result<Option<T>, 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<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
pos: usize,
) -> Result<T, ShellError> {
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<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
name: &str,
) -> Result<T, ShellError> {
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),
}
}
}

View File

@ -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>),
}

View File

@ -115,24 +115,33 @@ impl<'a> Call<'a> {
self.positional_iter().nth(index)
}
pub fn rest_iter(&self) -> impl Iterator<Item = &Value> {
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<Item = (&Value, bool)> {
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<Vec<Value>, ShellError> {
pub fn rest_iter_flattened(&self, start: usize) -> Result<Vec<Value>, 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)