rune/core/
env.rs

1use super::gc::{Context, ObjectMap, Rto, Slot};
2use super::object::{LispBuffer, Object, OpenBuffer, Symbol, WithLifetime};
3use anyhow::{Result, anyhow};
4use rune_macros::Trace;
5use std::cell::OnceCell;
6
7mod stack;
8mod symbol_map;
9pub(crate) use stack::*;
10pub(crate) use symbol_map::*;
11
12type PropertyMap<'a> = ObjectMap<Slot<Symbol<'a>>, Vec<(Slot<Symbol<'a>>, Slot<Object<'a>>)>>;
13#[derive(Debug, Default, Trace)]
14pub(crate) struct Env<'a> {
15    pub(crate) vars: ObjectMap<Slot<Symbol<'a>>, Slot<Object<'a>>>,
16    pub(crate) props: PropertyMap<'a>,
17    pub(crate) catch_stack: Vec<Slot<Object<'a>>>,
18    exception: (Slot<Object<'a>>, Slot<Object<'a>>),
19    #[no_trace]
20    exception_id: u32,
21    binding_stack: Vec<(Slot<Symbol<'a>>, Option<Slot<Object<'a>>>)>,
22    pub(crate) match_data: Slot<Object<'a>>,
23    #[no_trace]
24    pub(crate) current_buffer: CurrentBuffer<'a>,
25    pub(crate) stack: LispStack<'a>,
26}
27
28#[derive(Debug)]
29pub(crate) struct CurrentBuffer<'a> {
30    buffer: OnceCell<OpenBuffer<'a>>,
31    pub(crate) buf_ref: &'a LispBuffer,
32}
33
34impl Default for CurrentBuffer<'_> {
35    fn default() -> Self {
36        let name = crate::buffer::generate_new_buffer_name("*scratch*", None);
37        let buffer = {
38            // // need to drop global to avoid deadlocks
39            let global = INTERNED_SYMBOLS.lock().unwrap();
40            unsafe { global.create_buffer(&name).with_lifetime() }
41        };
42        crate::buffer::BUFFERS.lock().unwrap().insert(name, buffer);
43        Self { buffer: Default::default(), buf_ref: buffer }
44    }
45}
46
47impl<'a> CurrentBuffer<'a> {
48    fn lock(&self) -> OpenBuffer<'a> {
49        unsafe { self.buf_ref.lock().unwrap().with_lifetime() }
50    }
51
52    pub(crate) fn get(&self) -> &OpenBuffer<'a> {
53        self.buffer.get_or_init(|| self.lock())
54    }
55
56    pub(crate) fn get_mut(&mut self) -> &mut OpenBuffer<'a> {
57        // there is no get_or_init_mut
58        if self.buffer.get().is_none() {
59            let locked = self.lock();
60            let _ = self.buffer.set(locked);
61        }
62        self.buffer.get_mut().unwrap()
63    }
64
65    pub(crate) fn set(&mut self, buffer: &LispBuffer) {
66        let buffer = unsafe { buffer.with_lifetime() };
67        self.buf_ref = buffer;
68        self.release();
69    }
70
71    pub(crate) fn release(&mut self) {
72        self.buffer.take();
73    }
74}
75
76impl PartialEq<LispBuffer> for CurrentBuffer<'_> {
77    fn eq(&self, other: &LispBuffer) -> bool {
78        self.buf_ref == other
79    }
80}
81
82// RootedEnv created by #[derive(Trace)]
83impl<'a> RootedEnv<'a> {
84    pub(crate) fn set_var(&mut self, sym: Symbol, value: Object) -> Result<()> {
85        if sym.is_const() {
86            Err(anyhow!("Attempt to set a constant symbol: {sym}"))
87        } else {
88            self.vars.insert(sym, value);
89            Ok(())
90        }
91    }
92
93    pub(crate) fn set_prop(&mut self, symbol: Symbol, propname: Symbol, value: Object) {
94        match self.props.get_mut(symbol) {
95            Some(plist) => match plist.iter_mut().find(|x| x.0 == propname) {
96                Some(x) => x.1.set(value),
97                None => plist.push((propname, value)),
98            },
99            None => {
100                self.props.insert(symbol, vec![(propname, value)]);
101            }
102        }
103    }
104
105    pub(crate) fn set_exception(&mut self, tag: Object, data: Object) -> u32 {
106        self.exception.0.set(tag);
107        self.exception.1.set(data);
108        self.exception_id += 1;
109        self.exception_id
110    }
111
112    pub(crate) fn get_exception(&self, id: u32) -> Option<(&Rto<Object<'a>>, &Rto<Object<'a>>)> {
113        (id == self.exception_id).then_some((&self.exception.0, &self.exception.1))
114    }
115
116    pub(crate) fn varbind(&mut self, var: Symbol, value: Object, cx: &Context) {
117        let prev_value = self.vars.get(var).map(|x| x.bind(cx));
118        self.binding_stack.push((var, prev_value));
119        self.vars.insert(var, value);
120    }
121
122    pub(crate) fn unbind(&mut self, count: u16, cx: &Context) {
123        for _ in 0..count {
124            match self.binding_stack.bind_mut(cx).pop() {
125                Some((sym, val)) => match val {
126                    Some(val) => self.vars.insert(*sym, *val),
127                    None => self.vars.remove(*sym),
128                },
129                None => panic!("Binding stack was empty"),
130            }
131        }
132    }
133
134    pub(crate) fn defvar(&mut self, var: Symbol, value: Object) -> Result<()> {
135        // TOOD: Handle `eval-sexp` on defvar, which should always update the
136        // value
137        if self.vars.get(var).is_none() {
138            self.set_var(var, value)?;
139            var.make_special();
140        }
141
142        // If this variable was unbound previously in the binding stack,
143        // we will bind it to the new value
144        for binding in &mut *self.binding_stack {
145            if binding.0 == var && binding.1.is_none() {
146                binding.1.set(Some(value));
147            }
148        }
149        Ok(())
150    }
151
152    pub(crate) fn set_buffer(&mut self, buffer: &LispBuffer) {
153        if buffer == self.current_buffer.buf_ref {
154            return;
155        }
156        self.current_buffer.set(buffer);
157    }
158
159    pub(crate) fn with_buffer<T>(
160        &self,
161        buffer: &LispBuffer,
162        mut func: impl FnMut(&OpenBuffer) -> T,
163    ) -> Result<T> {
164        if self.current_buffer == *buffer {
165            Ok(func(self.current_buffer.get()))
166        } else {
167            let buffer = buffer.lock()?;
168            Ok(func(&buffer))
169        }
170    }
171
172    pub(crate) fn with_buffer_mut<T>(
173        &mut self,
174        buffer: &LispBuffer,
175        mut func: impl FnMut(&mut OpenBuffer) -> T,
176    ) -> Result<T> {
177        if self.current_buffer == *buffer {
178            Ok(func(self.current_buffer.get_mut()))
179        } else {
180            let mut buffer = buffer.lock()?;
181            Ok(func(&mut buffer))
182        }
183    }
184}