use std::sync::Arc; use crate::{ast::Expression, ir::DataSlice, Span, Value}; /// Represents a fully evaluated argument to a call. #[derive(Debug, Clone)] pub enum Argument { /// A positional argument Positional { span: Span, val: Value, ast: Option>, }, /// A spread argument, e.g. `...$args` Spread { span: Span, vals: Value, ast: Option>, }, /// A named argument with no value, e.g. `--flag` Flag { data: Arc<[u8]>, name: DataSlice, short: DataSlice, span: Span, }, /// A named argument with a value, e.g. `--flag value` or `--flag=` Named { data: Arc<[u8]>, name: DataSlice, short: DataSlice, span: Span, val: Value, ast: Option>, }, /// Information generated by the parser for use by certain keyword commands ParserInfo { data: Arc<[u8]>, name: DataSlice, // TODO: rather than `Expression`, this would probably be best served by a specific enum // type for this purpose. info: Box, }, } 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) -> Option { match self { Argument::Positional { span, .. } => Some(*span), Argument::Spread { span, .. } => Some(*span), Argument::Flag { span, .. } => Some(*span), Argument::Named { span, .. } => Some(*span), // Because `ParserInfo` is generated, its span shouldn't be used Argument::ParserInfo { .. } => None, } } /// The original AST [`Expression`] for the argument's value. This is not usually available; /// declarations have to opt-in if they require this. pub fn ast_expression(&self) -> Option<&Arc> { match self { Argument::Positional { ast, .. } => ast.as_ref(), Argument::Spread { ast, .. } => ast.as_ref(), Argument::Flag { .. } => None, Argument::Named { ast, .. } => ast.as_ref(), Argument::ParserInfo { .. } => None, } } } /// Stores the argument context for calls in IR evaluation. #[derive(Debug, Clone, Default)] pub struct ArgumentStack { arguments: Vec, } 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)] } /// Move arguments for the frame based on the given [`base`](`.get_base()`) and /// [`len`](`.get_len()`) parameters. pub fn drain_args(&mut self, base: usize, len: usize) -> impl Iterator + '_ { self.arguments.drain(base..(base + len)) } }