nu_protocol/engine/
argument.rs

1use std::sync::Arc;
2
3use crate::{ast::Expression, ir::DataSlice, Span, Value};
4
5/// Represents a fully evaluated argument to a call.
6#[derive(Debug, Clone)]
7pub enum Argument {
8    /// A positional argument
9    Positional {
10        span: Span,
11        val: Value,
12        ast: Option<Arc<Expression>>,
13    },
14    /// A spread argument, e.g. `...$args`
15    Spread {
16        span: Span,
17        vals: Value,
18        ast: Option<Arc<Expression>>,
19    },
20    /// A named argument with no value, e.g. `--flag`
21    Flag {
22        data: Arc<[u8]>,
23        name: DataSlice,
24        short: DataSlice,
25        span: Span,
26    },
27    /// A named argument with a value, e.g. `--flag value` or `--flag=`
28    Named {
29        data: Arc<[u8]>,
30        name: DataSlice,
31        short: DataSlice,
32        span: Span,
33        val: Value,
34        ast: Option<Arc<Expression>>,
35    },
36    /// Information generated by the parser for use by certain keyword commands
37    ParserInfo {
38        data: Arc<[u8]>,
39        name: DataSlice,
40        // TODO: rather than `Expression`, this would probably be best served by a specific enum
41        // type for this purpose.
42        info: Box<Expression>,
43    },
44}
45
46impl Argument {
47    /// The span encompassing the argument's usage within the call, distinct from the span of the
48    /// actual value of the argument.
49    pub fn span(&self) -> Option<Span> {
50        match self {
51            Argument::Positional { span, .. } => Some(*span),
52            Argument::Spread { span, .. } => Some(*span),
53            Argument::Flag { span, .. } => Some(*span),
54            Argument::Named { span, .. } => Some(*span),
55            // Because `ParserInfo` is generated, its span shouldn't be used
56            Argument::ParserInfo { .. } => None,
57        }
58    }
59
60    /// The original AST [`Expression`] for the argument's value. This is not usually available;
61    /// declarations have to opt-in if they require this.
62    pub fn ast_expression(&self) -> Option<&Arc<Expression>> {
63        match self {
64            Argument::Positional { ast, .. } => ast.as_ref(),
65            Argument::Spread { ast, .. } => ast.as_ref(),
66            Argument::Flag { .. } => None,
67            Argument::Named { ast, .. } => ast.as_ref(),
68            Argument::ParserInfo { .. } => None,
69        }
70    }
71}
72
73/// Stores the argument context for calls in IR evaluation.
74#[derive(Debug, Clone, Default)]
75pub struct ArgumentStack {
76    arguments: Vec<Argument>,
77}
78
79impl ArgumentStack {
80    /// Create a new, empty argument stack.
81    pub const fn new() -> Self {
82        ArgumentStack { arguments: vec![] }
83    }
84
85    /// Returns the index of the end of the argument stack. Call and save this before adding
86    /// arguments.
87    pub fn get_base(&self) -> usize {
88        self.arguments.len()
89    }
90
91    /// Calculates the number of arguments past the given [previously retrieved](.get_base) base
92    /// pointer.
93    pub fn get_len(&self, base: usize) -> usize {
94        self.arguments.len().checked_sub(base).unwrap_or_else(|| {
95            panic!(
96                "base ({}) is beyond the end of the arguments stack ({})",
97                base,
98                self.arguments.len()
99            );
100        })
101    }
102
103    /// Push an argument onto the end of the argument stack.
104    pub fn push(&mut self, argument: Argument) {
105        self.arguments.push(argument);
106    }
107
108    /// Clear all of the arguments after the given base index, to prepare for the next frame.
109    pub fn leave_frame(&mut self, base: usize) {
110        self.arguments.truncate(base);
111    }
112
113    /// Get arguments for the frame based on the given [`base`](`.get_base()`) and
114    /// [`len`](`.get_len()`) parameters.
115    pub fn get_args(&self, base: usize, len: usize) -> &[Argument] {
116        &self.arguments[base..(base + len)]
117    }
118
119    /// Move arguments for the frame based on the given [`base`](`.get_base()`) and
120    /// [`len`](`.get_len()`) parameters.
121    pub fn drain_args(&mut self, base: usize, len: usize) -> impl Iterator<Item = Argument> + '_ {
122        self.arguments.drain(base..(base + len))
123    }
124}