cl_interpret/
env.rs

1//! Lexical and non-lexical scoping for variables
2
3use crate::{builtin::Builtin, constructor::Constructor, modules::ModuleTree};
4
5use super::{
6    Callable, Interpret,
7    builtin::{Builtins, Math},
8    convalue::ConValue,
9    error::{Error, IResult},
10    function::Function,
11};
12use cl_ast::{Function as FnDecl, Sym};
13use std::{
14    collections::HashMap,
15    fmt::Display,
16    ops::{Deref, DerefMut},
17    rc::Rc,
18};
19
20pub type StackFrame = HashMap<Sym, ConValue>;
21
22pub type StackBinds = HashMap<Sym, usize>;
23
24#[derive(Clone, Debug, Default)]
25pub(crate) struct EnvFrame {
26    pub name: Option<&'static str>,
27    /// The length of the array when this stack frame was constructed
28    pub base: usize,
29    /// The bindings of name to stack position
30    pub binds: StackBinds,
31}
32
33/// Implements a nested lexical scope
34#[derive(Clone, Debug)]
35pub struct Environment {
36    values: Vec<ConValue>,
37    frames: Vec<EnvFrame>,
38    modules: ModuleTree,
39}
40
41impl Display for Environment {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        for EnvFrame { name, base: _, binds } in self.frames.iter().rev() {
44            writeln!(
45                f,
46                "--- {}[{}] ---",
47                if let Some(name) = name { name } else { "" },
48                binds.len(),
49            )?;
50            let mut binds: Vec<_> = binds.iter().collect();
51            binds.sort_by(|(_, a), (_, b)| a.cmp(b));
52            for (name, idx) in binds {
53                write!(f, "{idx:4} {name}: ")?;
54                match self.values.get(*idx) {
55                    Some(value) => writeln!(f, "\t{value}"),
56                    None => writeln!(f, "ERROR: {name}'s address blows the stack!"),
57                }?
58            }
59        }
60        Ok(())
61    }
62}
63
64impl Default for Environment {
65    fn default() -> Self {
66        let mut this = Self::no_builtins();
67        this.add_builtins(Builtins).add_builtins(Math);
68        this
69    }
70}
71
72impl Environment {
73    pub fn new() -> Self {
74        Self::default()
75    }
76    /// Creates an [Environment] with no [builtins](super::builtin)
77    pub fn no_builtins() -> Self {
78        Self {
79            values: Vec::new(),
80            frames: vec![EnvFrame::default()],
81            modules: ModuleTree::default(),
82        }
83    }
84
85    /// Reflexively evaluates a node
86    pub fn eval(&mut self, node: &impl Interpret) -> IResult<ConValue> {
87        node.interpret(self)
88    }
89
90    /// Calls a function inside the Environment's scope,
91    /// and returns the result
92    pub fn call(&mut self, name: Sym, args: &[ConValue]) -> IResult<ConValue> {
93        let function = self.get(name)?;
94        function.call(self, args)
95    }
96
97    pub fn modules_mut(&mut self) -> &mut ModuleTree {
98        &mut self.modules
99    }
100
101    pub fn modules(&self) -> &ModuleTree {
102        &self.modules
103    }
104
105    /// Binds a value to the given name in the current scope.
106    pub fn bind(&mut self, name: impl Into<Sym>, value: impl Into<ConValue>) {
107        self.insert(name.into(), value.into());
108    }
109
110    pub fn bind_raw(&mut self, name: Sym, id: usize) -> Option<()> {
111        let EnvFrame { name: _, base: _, binds } = self.frames.last_mut()?;
112        binds.insert(name, id);
113        Some(())
114    }
115
116    /// Gets all registered globals, bound or unbound.
117    pub(crate) fn globals(&self) -> &EnvFrame {
118        self.frames.first().unwrap()
119    }
120
121    /// Adds builtins
122    ///
123    /// # Panics
124    ///
125    /// Will panic if stack contains more than the globals frame!
126    pub fn add_builtins(&mut self, builtins: &'static [Builtin]) -> &mut Self {
127        if self.frames.len() != 1 {
128            panic!("Cannot add builtins to full stack: {self}")
129        }
130
131        for builtin in builtins {
132            self.insert(builtin.name(), builtin.into());
133        }
134
135        self
136    }
137
138    pub fn push_frame(&mut self, name: &'static str, frame: StackFrame) {
139        self.frames.push(EnvFrame {
140            name: Some(name),
141            base: self.values.len(),
142            binds: HashMap::new(),
143        });
144        for (k, v) in frame {
145            self.insert(k, v);
146        }
147    }
148
149    pub fn pop_frame(&mut self) -> Option<(StackFrame, &'static str)> {
150        let mut out = HashMap::new();
151        let EnvFrame { name, base, binds } = self.frames.pop()?;
152        for (k, v) in binds {
153            out.insert(k, self.values.get_mut(v).map(std::mem::take)?);
154        }
155        self.values.truncate(base);
156        Some((out, name.unwrap_or("")))
157    }
158
159    /// Enters a nested scope, returning a [`Frame`] stack-guard.
160    ///
161    /// [`Frame`] implements Deref/DerefMut for [`Environment`].
162    pub fn frame(&mut self, name: &'static str) -> Frame<'_> {
163        Frame::new(self, name)
164    }
165
166    /// Enters a nested scope, assigning the contents of `frame`,
167    /// and returning a [`Frame`] stack-guard.
168    ///
169    /// [`Frame`] implements Deref/DerefMut for [`Environment`].
170    pub fn with_frame<'e>(&'e mut self, name: &'static str, frame: StackFrame) -> Frame<'e> {
171        let mut scope = self.frame(name);
172        for (k, v) in frame {
173            scope.insert(k, v);
174        }
175        scope
176    }
177
178    /// Resolves a variable mutably.
179    ///
180    /// Returns a mutable reference to the variable's record, if it exists.
181    pub fn get_mut(&mut self, name: Sym) -> IResult<&mut ConValue> {
182        let at = self.id_of(name)?;
183        self.get_id_mut(at).ok_or(Error::NotDefined(name))
184    }
185
186    /// Resolves a variable immutably.
187    ///
188    /// Returns a reference to the variable's contents, if it is defined and initialized.
189    pub fn get(&self, name: Sym) -> IResult<ConValue> {
190        let id = self.id_of(name)?;
191        let res = self.values.get(id);
192        Ok(res.ok_or(Error::NotDefined(name))?.clone())
193    }
194
195    /// Resolves the index associated with a [Sym]
196    pub fn id_of(&self, name: Sym) -> IResult<usize> {
197        for EnvFrame { binds, .. } in self.frames.iter().rev() {
198            if let Some(id) = binds.get(&name).copied() {
199                return Ok(id);
200            }
201        }
202        Err(Error::NotDefined(name))
203    }
204
205    pub fn get_id(&self, id: usize) -> Option<&ConValue> {
206        self.values.get(id)
207    }
208
209    pub fn get_id_mut(&mut self, id: usize) -> Option<&mut ConValue> {
210        self.values.get_mut(id)
211    }
212
213    pub fn get_slice(&self, start: usize, len: usize) -> Option<&[ConValue]> {
214        self.values.get(start..start + len)
215    }
216
217    pub fn get_slice_mut(&mut self, start: usize, len: usize) -> Option<&mut [ConValue]> {
218        self.values.get_mut(start..start + len)
219    }
220
221    /// Inserts a new [ConValue] into this [Environment]
222    pub fn insert(&mut self, k: Sym, v: ConValue) {
223        if self.bind_raw(k, self.values.len()).is_some() {
224            self.values.push(v);
225        }
226    }
227
228    /// A convenience function for registering a [FnDecl] as a [Function]
229    pub fn insert_fn(&mut self, decl: &FnDecl) {
230        let FnDecl { name, .. } = decl;
231        let (name, function) = (*name, Rc::new(Function::new(decl)));
232        self.insert(name, ConValue::Function(function.clone()));
233        // Tell the function to lift its upvars now, after it's been declared
234        function.lift_upvars(self);
235    }
236
237    pub fn insert_tup_constructor(&mut self, name: Sym, arity: usize) {
238        let cs = Constructor { arity: arity as _, name };
239        self.insert(name, ConValue::TupleConstructor(cs));
240    }
241
242    /// Gets the current stack top position
243    pub fn pos(&self) -> usize {
244        self.values.len()
245    }
246
247    /// Allocates a local variable
248    pub fn stack_alloc(&mut self, value: ConValue) -> IResult<usize> {
249        let adr = self.values.len();
250        self.values.push(value);
251        Ok(adr)
252    }
253
254    /// Allocates some space on the stack
255    pub fn alloca(&mut self, value: ConValue, len: usize) -> ConValue {
256        let idx = self.values.len();
257        self.values.extend(std::iter::repeat_n(value, len));
258        ConValue::Slice(idx, len)
259    }
260}
261
262/// Represents a stack frame
263#[derive(Debug)]
264pub struct Frame<'scope> {
265    scope: &'scope mut Environment,
266}
267impl<'scope> Frame<'scope> {
268    fn new(scope: &'scope mut Environment, name: &'static str) -> Self {
269        scope.frames.push(EnvFrame {
270            name: Some(name),
271            base: scope.values.len(),
272            binds: HashMap::new(),
273        });
274
275        Self { scope }
276    }
277
278    pub fn pop_values(mut self) -> Option<StackFrame> {
279        let mut out = HashMap::new();
280        let binds = std::mem::take(&mut self.frames.last_mut()?.binds);
281        for (k, v) in binds {
282            out.insert(k, self.values.get_mut(v).map(std::mem::take)?);
283        }
284        Some(out)
285    }
286
287    pub fn into_binds(mut self) -> Option<StackBinds> {
288        let EnvFrame { name: _, base: _, binds } = self.frames.pop()?;
289        std::mem::forget(self);
290        Some(binds)
291    }
292}
293impl Deref for Frame<'_> {
294    type Target = Environment;
295    fn deref(&self) -> &Self::Target {
296        self.scope
297    }
298}
299impl DerefMut for Frame<'_> {
300    fn deref_mut(&mut self) -> &mut Self::Target {
301        self.scope
302    }
303}
304impl Drop for Frame<'_> {
305    fn drop(&mut self) {
306        if let Some(frame) = self.frames.pop() {
307            self.values.truncate(frame.base);
308        }
309    }
310}