Skip to main content

cl_interpret/
env.rs

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