brush_core/
functions.rs

1//! Structures for managing function registrations and calls.
2
3use std::{
4    collections::{HashMap, VecDeque},
5    sync::Arc,
6};
7
8use brush_parser::ast;
9
10/// An environment for defined, named functions.
11#[derive(Clone, Default)]
12pub struct FunctionEnv {
13    functions: HashMap<String, Registration>,
14}
15
16impl FunctionEnv {
17    /// Tries to retrieve the registration for a function by name.
18    ///
19    /// # Arguments
20    ///
21    /// * `name` - The name of the function to retrieve.
22    pub fn get(&self, name: &str) -> Option<&Registration> {
23        self.functions.get(name)
24    }
25
26    /// Tries to retrieve a mutable reference to the registration for a
27    /// function by name.
28    ///
29    /// # Arguments
30    ///
31    /// * `name` - The name of the function to retrieve.
32    pub fn get_mut(&mut self, name: &str) -> Option<&mut Registration> {
33        self.functions.get_mut(name)
34    }
35
36    /// Unregisters a function from the environment.
37    ///
38    /// # Arguments
39    ///
40    /// * `name` - The name of the function to remove.
41    pub fn remove(&mut self, name: &str) -> Option<Registration> {
42        self.functions.remove(name)
43    }
44
45    /// Updates a function registration in this environment.
46    ///
47    /// # Arguments
48    ///
49    /// * `name` - The name of the function to update.
50    /// * `registration` - The new registration for the function.
51    pub fn update(&mut self, name: String, registration: Registration) {
52        self.functions.insert(name, registration);
53    }
54
55    /// Clear all functions in this environment.
56    pub fn clear(&mut self) {
57        self.functions.clear();
58    }
59
60    /// Returns an iterator over the functions registered in this environment.
61    pub fn iter(&self) -> impl Iterator<Item = (&String, &Registration)> {
62        self.functions.iter()
63    }
64}
65
66/// Encapsulates a registration for a defined function.
67#[derive(Clone)]
68pub struct Registration {
69    /// The definition of the function.
70    pub(crate) definition: Arc<brush_parser::ast::FunctionDefinition>,
71    /// Whether or not this function definition should be exported to children.
72    exported: bool,
73}
74
75impl From<brush_parser::ast::FunctionDefinition> for Registration {
76    fn from(definition: brush_parser::ast::FunctionDefinition) -> Self {
77        Self {
78            definition: Arc::new(definition),
79            exported: false,
80        }
81    }
82}
83
84impl Registration {
85    /// Returns a reference to the function definition.
86    pub fn definition(&self) -> &brush_parser::ast::FunctionDefinition {
87        &self.definition
88    }
89
90    /// Marks the function for export.
91    pub const fn export(&mut self) {
92        self.exported = true;
93    }
94
95    /// Unmarks the function for export.
96    pub const fn unexport(&mut self) {
97        self.exported = false;
98    }
99
100    /// Returns whether this function is exported.
101    pub const fn is_exported(&self) -> bool {
102        self.exported
103    }
104}
105
106/// Represents an active shell function call.
107#[derive(Clone, Debug)]
108pub struct FunctionCall {
109    /// The name of the function invoked.
110    pub function_name: String,
111    /// The definition of the invoked function.
112    pub function_definition: Arc<brush_parser::ast::FunctionDefinition>,
113}
114
115/// Encapsulates a function call stack.
116#[derive(Clone, Debug, Default)]
117pub struct CallStack {
118    frames: VecDeque<FunctionCall>,
119}
120
121impl std::fmt::Display for CallStack {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        if self.is_empty() {
124            return Ok(());
125        }
126
127        writeln!(f, "Function call stack (most recent first):")?;
128
129        for (index, frame) in self.iter().enumerate() {
130            writeln!(f, "  #{}| {}", index, frame.function_name)?;
131        }
132
133        Ok(())
134    }
135}
136
137impl CallStack {
138    /// Creates a new empty function call stack.
139    pub fn new() -> Self {
140        Self::default()
141    }
142
143    /// Removes the top from from the stack. If the stack is empty, does nothing and
144    /// returns `None`; otherwise, returns the removed call frame.
145    pub fn pop(&mut self) -> Option<FunctionCall> {
146        self.frames.pop_front()
147    }
148
149    /// Pushes a new frame onto the stack.
150    ///
151    /// # Arguments
152    ///
153    /// * `name` - The name of the function being called.
154    /// * `function_def` - The definition of the function being called.
155    pub fn push(&mut self, name: impl Into<String>, function_def: &Arc<ast::FunctionDefinition>) {
156        self.frames.push_front(FunctionCall {
157            function_name: name.into(),
158            function_definition: function_def.clone(),
159        });
160    }
161
162    /// Returns the current depth of the function call stack.
163    pub fn depth(&self) -> usize {
164        self.frames.len()
165    }
166
167    /// Returns whether or not the function call stack is empty.
168    pub fn is_empty(&self) -> bool {
169        self.frames.is_empty()
170    }
171
172    /// Returns an iterator over the function call frames, starting from the most
173    /// recent.
174    pub fn iter(&self) -> impl Iterator<Item = &FunctionCall> {
175        self.frames.iter()
176    }
177}