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