check behavior, do CallExt for ir::Call, engine::Call
This commit is contained in:
parent
6a2dc99717
commit
f02ab3e231
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>),
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user