wip: going back to argument stack strategy, still having trouble with implementation in a way that will be ok for plugins
This commit is contained in:
parent
6ebb245411
commit
b599086994
|
@ -191,15 +191,15 @@ impl CallExt for Call {
|
|||
}
|
||||
}
|
||||
|
||||
impl CallExt for ir::Call<'_> {
|
||||
impl CallExt for ir::Call {
|
||||
fn has_flag(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
stack: &mut Stack,
|
||||
flag_name: &str,
|
||||
) -> Result<bool, ShellError> {
|
||||
Ok(self
|
||||
.named_iter()
|
||||
.named_iter(stack)
|
||||
.find(|(name, _)| *name == flag_name)
|
||||
.is_some())
|
||||
}
|
||||
|
@ -207,10 +207,10 @@ impl CallExt for ir::Call<'_> {
|
|||
fn get_flag<T: FromValue>(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
stack: &mut Stack,
|
||||
name: &str,
|
||||
) -> Result<Option<T>, ShellError> {
|
||||
if let Some(val) = self.get_named_arg(name) {
|
||||
if let Some(val) = self.get_named_arg(stack, name) {
|
||||
T::from_value(val.clone()).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
|
@ -220,10 +220,10 @@ impl CallExt for ir::Call<'_> {
|
|||
fn rest<T: FromValue>(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
stack: &mut Stack,
|
||||
starting_pos: usize,
|
||||
) -> Result<Vec<T>, ShellError> {
|
||||
self.rest_iter_flattened(starting_pos)?
|
||||
self.rest_iter_flattened(stack, starting_pos)?
|
||||
.into_iter()
|
||||
.map(T::from_value)
|
||||
.collect()
|
||||
|
@ -232,10 +232,10 @@ impl CallExt for ir::Call<'_> {
|
|||
fn opt<T: FromValue>(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
stack: &mut Stack,
|
||||
pos: usize,
|
||||
) -> Result<Option<T>, ShellError> {
|
||||
self.positional_iter()
|
||||
self.positional_iter(stack)
|
||||
.nth(pos)
|
||||
.cloned()
|
||||
.map(T::from_value)
|
||||
|
@ -258,11 +258,11 @@ impl CallExt for ir::Call<'_> {
|
|||
) -> Result<T, ShellError> {
|
||||
if let Some(val) = self.opt(engine_state, stack, pos)? {
|
||||
Ok(val)
|
||||
} else if self.positional_len() == 0 {
|
||||
} else if self.positional_len(stack) == 0 {
|
||||
Err(ShellError::AccessEmptyContent { span: *self.head })
|
||||
} else {
|
||||
Err(ShellError::AccessBeyondEnd {
|
||||
max_idx: self.positional_len() - 1,
|
||||
max_idx: self.positional_len(stack) - 1,
|
||||
span: *self.head,
|
||||
})
|
||||
}
|
||||
|
@ -278,6 +278,19 @@ impl CallExt for ir::Call<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a `CallExt` trait object from the `engine::Call` reference, for easier implementation
|
||||
///
|
||||
/// XXX: this doesn't work
|
||||
#[inline(always)]
|
||||
const fn proxy(call: &engine::Call<'_>) -> &dyn CallExt {
|
||||
match &call.inner {
|
||||
CallImpl::AstRef(ast_call) => ast_call,
|
||||
CallImpl::AstArc(ast_call) => &ast_call,
|
||||
CallImpl::IrRef(ir_call) => ir_call,
|
||||
CallImpl::IrArc(ir_call) => &ir_call,
|
||||
}
|
||||
}
|
||||
|
||||
impl CallExt for engine::Call<'_> {
|
||||
fn has_flag(
|
||||
&self,
|
||||
|
@ -285,10 +298,7 @@ impl CallExt for engine::Call<'_> {
|
|||
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),
|
||||
}
|
||||
proxy(self).has_flag(engine_state, stack, flag_name)
|
||||
}
|
||||
|
||||
fn get_flag<T: FromValue>(
|
||||
|
@ -297,10 +307,7 @@ impl CallExt for engine::Call<'_> {
|
|||
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),
|
||||
}
|
||||
proxy(self).get_flag(engine_state, stack, name)
|
||||
}
|
||||
|
||||
fn rest<T: FromValue>(
|
||||
|
@ -309,10 +316,7 @@ impl CallExt for engine::Call<'_> {
|
|||
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),
|
||||
}
|
||||
proxy(self).rest(engine_state, stack, starting_pos)
|
||||
}
|
||||
|
||||
fn opt<T: FromValue>(
|
||||
|
@ -321,10 +325,7 @@ impl CallExt for engine::Call<'_> {
|
|||
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),
|
||||
}
|
||||
proxy(self).opt(engine_state, stack, pos)
|
||||
}
|
||||
|
||||
fn opt_const<T: FromValue>(
|
||||
|
@ -332,10 +333,7 @@ impl CallExt for engine::Call<'_> {
|
|||
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),
|
||||
}
|
||||
proxy(self).opt_const(working_set, pos)
|
||||
}
|
||||
|
||||
fn req<T: FromValue>(
|
||||
|
@ -344,10 +342,7 @@ impl CallExt for engine::Call<'_> {
|
|||
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),
|
||||
}
|
||||
proxy(self).req(engine_state, stack, pos)
|
||||
}
|
||||
|
||||
fn req_parser_info<T: FromValue>(
|
||||
|
@ -356,9 +351,6 @@ impl CallExt for engine::Call<'_> {
|
|||
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),
|
||||
}
|
||||
proxy(self).req_parser_info(engine_state, stack, name)
|
||||
}
|
||||
}
|
||||
|
|
86
crates/nu-protocol/src/engine/argument.rs
Normal file
86
crates/nu-protocol/src/engine/argument.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
use crate::{Span, Value};
|
||||
|
||||
/// Represents a fully evaluated argument to a call.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Argument {
|
||||
/// A positional argument
|
||||
Positional {
|
||||
val: Value,
|
||||
span: Span,
|
||||
},
|
||||
Spread {
|
||||
vals: Value,
|
||||
span: Span,
|
||||
},
|
||||
/// A named argument with no value, e.g. `--flag`
|
||||
Flag {
|
||||
name: Box<str>,
|
||||
span: Span,
|
||||
},
|
||||
/// A named argument with a value, e.g. `--flag value` or `--flag=`
|
||||
Named {
|
||||
name: Box<str>,
|
||||
span: Span,
|
||||
val: Value,
|
||||
},
|
||||
}
|
||||
|
||||
impl Argument {
|
||||
/// The span encompassing the argument's usage within the call, distinct from the span of the
|
||||
/// actual value of the argument.
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
Argument::Positional { span, .. } => *span,
|
||||
Argument::Spread { span, .. } => *span,
|
||||
Argument::Flag { span, .. } => *span,
|
||||
Argument::Named { span, .. } => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores the argument context for calls in IR evaluation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgumentStack {
|
||||
arguments: Vec<Argument>,
|
||||
}
|
||||
|
||||
impl ArgumentStack {
|
||||
/// Create a new, empty argument stack.
|
||||
pub const fn new() -> Self {
|
||||
ArgumentStack { arguments: vec![] }
|
||||
}
|
||||
|
||||
/// Returns the index of the end of the argument stack. Call and save this before adding
|
||||
/// arguments.
|
||||
pub fn get_base(&self) -> usize {
|
||||
self.arguments.len()
|
||||
}
|
||||
|
||||
/// Calculates the number of arguments past the given [previously retrieved](.get_base) base
|
||||
/// pointer.
|
||||
pub fn get_len(&self, base: usize) -> usize {
|
||||
self.arguments.len().checked_sub(base).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"base ({}) is beyond the end of the arguments stack ({})",
|
||||
base,
|
||||
self.arguments.len()
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
/// Push an argument onto the end of the argument stack.
|
||||
pub fn push(&mut self, argument: Argument) {
|
||||
self.arguments.push(argument);
|
||||
}
|
||||
|
||||
/// Clear all of the arguments after the given base index, to prepare for the next frame.
|
||||
pub fn leave_frame(&mut self, base: usize) {
|
||||
self.arguments.truncate(base);
|
||||
}
|
||||
|
||||
/// Get arguments for the frame based on the given [`base`](`.get_base()`) and
|
||||
/// [`len`](`.get_len()`) parameters.
|
||||
pub fn get_args(&self, base: usize, len: usize) -> &[Argument] {
|
||||
&self.arguments[base..(base + len)]
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
use crate::{
|
||||
ast,
|
||||
ir::{self, Instruction},
|
||||
DeclId, Span,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{ast, ir, DeclId, Span};
|
||||
|
||||
/// This is a HACK to help [`Command`](super::Command) support both the old AST evaluator and the
|
||||
/// new IR evaluator at the same time. It should be removed once we are satisfied with the new
|
||||
|
@ -16,8 +14,31 @@ pub struct Call<'a> {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CallImpl<'a> {
|
||||
Ast(&'a ast::Call),
|
||||
Ir(ir::Call<'a>),
|
||||
AstRef(&'a ast::Call),
|
||||
AstArc(Arc<ast::Call>),
|
||||
IrRef(&'a ir::Call),
|
||||
IrArc(Arc<ir::Call>),
|
||||
}
|
||||
|
||||
impl Call<'_> {
|
||||
pub fn to_owned(&self) -> Call<'static> {
|
||||
Call {
|
||||
head: self.head,
|
||||
decl_id: self.decl_id,
|
||||
inner: self.inner.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CallImpl<'_> {
|
||||
pub fn to_owned(&self) -> CallImpl<'static> {
|
||||
match self {
|
||||
CallImpl::AstRef(call) => CallImpl::AstArc(Arc::new((*call).clone())),
|
||||
CallImpl::AstArc(call) => CallImpl::AstArc(call.clone()),
|
||||
CallImpl::IrRef(call) => CallImpl::IrArc(Arc::new((*call).clone())),
|
||||
CallImpl::IrArc(call) => CallImpl::IrArc(call.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ast::Call> for Call<'a> {
|
||||
|
@ -25,20 +46,17 @@ impl<'a> From<&'a ast::Call> for Call<'a> {
|
|||
Call {
|
||||
head: call.head,
|
||||
decl_id: call.decl_id,
|
||||
inner: CallImpl::Ast(call),
|
||||
inner: CallImpl::AstRef(call),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<ir::Call<'a>> for Call<'a> {
|
||||
fn from(call: ir::Call<'a>) -> Self {
|
||||
let Instruction::Call { decl_id, .. } = *call.instruction else {
|
||||
panic!("ir::Call instruction was not Call: {:?}", call.instruction);
|
||||
};
|
||||
impl<'a> From<&'a ir::Call> for Call<'a> {
|
||||
fn from(call: &'a ir::Call) -> Self {
|
||||
Call {
|
||||
head: *call.head,
|
||||
decl_id,
|
||||
inner: CallImpl::Ir(call),
|
||||
head: call.head,
|
||||
decl_id: call.decl_id,
|
||||
inner: CallImpl::IrRef(call),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod argument;
|
||||
mod cached_file;
|
||||
mod call;
|
||||
mod call_info;
|
||||
|
@ -16,6 +17,7 @@ mod variable;
|
|||
|
||||
pub use cached_file::CachedFile;
|
||||
|
||||
pub use argument::*;
|
||||
pub use call::*;
|
||||
pub use call_info::*;
|
||||
pub use capture_block::*;
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use super::RegisterBufCache;
|
||||
use super::{ArgumentStack, RegisterBufCache};
|
||||
|
||||
/// Environment variables per overlay
|
||||
pub type EnvVars = HashMap<String, HashMap<String, Value>>;
|
||||
|
@ -45,6 +45,8 @@ pub struct Stack {
|
|||
pub active_overlays: Vec<String>,
|
||||
/// Cached register buffers for IR evaluation
|
||||
pub register_buf_cache: RegisterBufCache,
|
||||
/// Argument stack for IR evaluation
|
||||
pub argument_stack: ArgumentStack,
|
||||
pub recursion_count: u64,
|
||||
pub parent_stack: Option<Arc<Stack>>,
|
||||
/// Variables that have been deleted (this is used to hide values from parent stack lookups)
|
||||
|
@ -73,6 +75,7 @@ impl Stack {
|
|||
env_hidden: HashMap::new(),
|
||||
active_overlays: vec![DEFAULT_OVERLAY_NAME.to_string()],
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
recursion_count: 0,
|
||||
parent_stack: None,
|
||||
parent_deletions: vec![],
|
||||
|
@ -91,6 +94,7 @@ impl Stack {
|
|||
env_hidden: parent.env_hidden.clone(),
|
||||
active_overlays: parent.active_overlays.clone(),
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
recursion_count: parent.recursion_count,
|
||||
vars: vec![],
|
||||
parent_deletions: vec![],
|
||||
|
@ -261,6 +265,7 @@ impl Stack {
|
|||
env_hidden: self.env_hidden.clone(),
|
||||
active_overlays: self.active_overlays.clone(),
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
recursion_count: self.recursion_count,
|
||||
parent_stack: None,
|
||||
parent_deletions: vec![],
|
||||
|
@ -292,6 +297,7 @@ impl Stack {
|
|||
env_hidden: self.env_hidden.clone(),
|
||||
active_overlays: self.active_overlays.clone(),
|
||||
register_buf_cache: RegisterBufCache::new(),
|
||||
argument_stack: ArgumentStack::new(),
|
||||
recursion_count: self.recursion_count,
|
||||
parent_stack: None,
|
||||
parent_deletions: vec![],
|
||||
|
|
|
@ -1,61 +1,28 @@
|
|||
use crate::{PipelineData, RegId, ShellError, Span, Value};
|
||||
|
||||
use super::{CallArg, Instruction};
|
||||
use crate::{
|
||||
engine::{Argument, Stack},
|
||||
ShellError, Span, Value,
|
||||
};
|
||||
|
||||
/// Contains the information for a call being made to a declared command.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Call<'a> {
|
||||
pub registers: &'a [PipelineData],
|
||||
pub call_args: &'a [CallArg],
|
||||
pub instruction: &'a Instruction,
|
||||
pub head: &'a Span,
|
||||
pub struct Call {
|
||||
/// The declaration ID of the command to be invoked.
|
||||
pub decl_id: usize,
|
||||
/// The span encompassing the command name, before the arguments.
|
||||
pub head: Span,
|
||||
/// The base index of the arguments for this call within the
|
||||
/// [argument stack](crate::engine::ArgumentStack).
|
||||
pub args_base: usize,
|
||||
/// The number of [`Argument`]s for the call. Note that this just counts the number of
|
||||
/// `Argument` entries on the stack, and has nothing to do with the actual number of positional
|
||||
/// or spread arguments.
|
||||
pub args_len: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum ArgRef<'a> {
|
||||
Positional(&'a Value),
|
||||
Named(&'a str, Option<&'a Value>),
|
||||
Spread(&'a Value),
|
||||
}
|
||||
|
||||
impl<'a> ArgRef<'a> {
|
||||
fn span(self) -> Span {
|
||||
match self {
|
||||
ArgRef::Positional(v) => v.span(),
|
||||
// FIXME: Named without value needs a span!
|
||||
ArgRef::Named(_, v) => v.map(|v| v.span()).unwrap_or(Span::unknown()),
|
||||
ArgRef::Spread(v) => v.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Call<'a> {
|
||||
fn call_args(&self) -> impl Iterator<Item = &CallArg> {
|
||||
let Instruction::Call {
|
||||
args_start,
|
||||
args_len,
|
||||
..
|
||||
} = *self.instruction
|
||||
else {
|
||||
panic!("self.instruction is not Call")
|
||||
};
|
||||
self.call_args[args_start..(args_start + args_len)].iter()
|
||||
}
|
||||
|
||||
fn get_reg_val(&self, reg_id: RegId) -> &Value {
|
||||
match &self.registers[reg_id.0 as usize] {
|
||||
PipelineData::Value(value, _) => value,
|
||||
other => panic!("value in register {reg_id} for argument was not collected: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn arg_refs(&self) -> impl Iterator<Item = ArgRef<'_>> {
|
||||
self.call_args().map(|arg| match arg {
|
||||
CallArg::Positional(r) => ArgRef::Positional(self.get_reg_val(*r)),
|
||||
CallArg::Spread(r) => ArgRef::Spread(self.get_reg_val(*r)),
|
||||
CallArg::Flag(name) => ArgRef::Named(&name, None),
|
||||
CallArg::Named(name, r) => ArgRef::Named(&name, Some(self.get_reg_val(*r))),
|
||||
})
|
||||
impl Call {
|
||||
/// Get the arguments for this call from the arguments stack.
|
||||
pub fn arguments<'a>(&self, stack: &'a Stack) -> &'a [Argument] {
|
||||
stack.argument_stack.get_args(self.args_base, self.args_len)
|
||||
}
|
||||
|
||||
/// The span encompassing the arguments
|
||||
|
@ -64,72 +31,87 @@ impl<'a> Call<'a> {
|
|||
///
|
||||
/// If there are one or more arguments the span encompasses the start of the first argument to
|
||||
/// end of the last argument
|
||||
pub fn arguments_span(&self) -> Span {
|
||||
pub fn arguments_span(&self, stack: &Stack) -> Span {
|
||||
let past = self.head.past();
|
||||
|
||||
let start = self
|
||||
.arg_refs()
|
||||
.next()
|
||||
.map(|a| a.span())
|
||||
.unwrap_or(past)
|
||||
.start;
|
||||
let end = self.arg_refs().last().map(|a| a.span()).unwrap_or(past).end;
|
||||
let args = self.arguments(stack);
|
||||
|
||||
let start = args.first().map(|a| a.span()).unwrap_or(past).start;
|
||||
let end = args.last().map(|a| a.span()).unwrap_or(past).end;
|
||||
|
||||
Span::new(start, end)
|
||||
}
|
||||
|
||||
pub fn named_len(&self) -> usize {
|
||||
self.call_args()
|
||||
.filter(|arg| matches!(arg, CallArg::Named(..) | CallArg::Flag(..)))
|
||||
pub fn named_len(&self, stack: &Stack) -> usize {
|
||||
self.arguments(stack)
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg, Argument::Named { .. } | Argument::Flag { .. }))
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn named_iter(&self) -> impl Iterator<Item = (&str, Option<&Value>)> {
|
||||
self.arg_refs().filter_map(|arg| match arg {
|
||||
ArgRef::Named(name, value) => Some((name, value)),
|
||||
_ => None,
|
||||
})
|
||||
pub fn named_iter<'a>(
|
||||
&self,
|
||||
stack: &'a Stack,
|
||||
) -> impl Iterator<Item = (&'a str, Option<&'a Value>)> + 'a {
|
||||
self.arguments(stack).iter().filter_map(
|
||||
|arg: &Argument| -> Option<(&str, Option<&Value>)> {
|
||||
match arg {
|
||||
Argument::Flag { name, .. } => Some((&name, None)),
|
||||
Argument::Named { name, val, .. } => Some((&name, Some(val))),
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_named_arg(&self, flag_name: &str) -> Option<&Value> {
|
||||
self.arg_refs().find_map(|arg| match arg {
|
||||
ArgRef::Named(name, value) if name == flag_name => value,
|
||||
_ => None,
|
||||
})
|
||||
pub fn get_named_arg<'a>(&self, stack: &'a Stack, flag_name: &str) -> Option<&'a Value> {
|
||||
self.named_iter(stack)
|
||||
.find_map(|(name, val)| (name == flag_name).then_some(val))
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn positional_len(&self) -> usize {
|
||||
self.call_args()
|
||||
.filter(|arg| matches!(arg, CallArg::Positional(..)))
|
||||
pub fn positional_len(&self, stack: &Stack) -> usize {
|
||||
self.arguments(stack)
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg, Argument::Positional { .. }))
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn positional_iter(&self) -> impl Iterator<Item = &Value> {
|
||||
self.arg_refs().filter_map(|arg| match arg {
|
||||
ArgRef::Positional(value) => Some(value),
|
||||
pub fn positional_iter<'a>(&self, stack: &'a Stack) -> impl Iterator<Item = &'a Value> {
|
||||
self.arguments(stack).iter().filter_map(|arg| match arg {
|
||||
Argument::Positional { val, .. } => Some(val),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn positional_nth(&self, index: usize) -> Option<&Value> {
|
||||
self.positional_iter().nth(index)
|
||||
pub fn positional_nth<'a>(&self, stack: &'a Stack, index: usize) -> Option<&'a Value> {
|
||||
self.positional_iter(stack).nth(index)
|
||||
}
|
||||
|
||||
/// 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()
|
||||
pub fn rest_iter<'a>(
|
||||
&self,
|
||||
stack: &'a Stack,
|
||||
start: usize,
|
||||
) -> impl Iterator<Item = (&'a Value, bool)> + 'a {
|
||||
self.arguments(stack)
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
ArgRef::Positional(value) => Some((value, false)),
|
||||
ArgRef::Spread(value) => Some((value, true)),
|
||||
Argument::Positional { val, .. } => Some((val, false)),
|
||||
Argument::Spread { vals, .. } => Some((vals, true)),
|
||||
_ => None,
|
||||
})
|
||||
.skip(start)
|
||||
}
|
||||
|
||||
pub fn rest_iter_flattened(&self, start: usize) -> Result<Vec<Value>, ShellError> {
|
||||
pub fn rest_iter_flattened(
|
||||
&self,
|
||||
stack: &Stack,
|
||||
start: usize,
|
||||
) -> Result<Vec<Value>, ShellError> {
|
||||
let mut acc = vec![];
|
||||
for (rest_val, spread) in self.rest_iter(start) {
|
||||
for (rest_val, spread) in self.rest_iter(stack, start) {
|
||||
if spread {
|
||||
match rest_val {
|
||||
Value::List { vals, .. } => acc.extend(vals.iter().cloned()),
|
||||
|
@ -147,9 +129,9 @@ impl<'a> Call<'a> {
|
|||
Ok(acc)
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
let mut span = *self.head;
|
||||
for arg in self.arg_refs() {
|
||||
pub fn span(&self, stack: &Stack) -> Span {
|
||||
let mut span = self.head;
|
||||
for arg in self.arguments(stack).iter() {
|
||||
span.end = span.end.max(arg.span().end);
|
||||
}
|
||||
span
|
||||
|
|
Loading…
Reference in New Issue
Block a user