Skip to main content

sim_lib_lang_lua/
env.rs

1use sim_kernel::{Result, Symbol, Value};
2use std::{
3    collections::BTreeMap,
4    sync::{Arc, Mutex},
5};
6
7use sim_lib_binding::{BindingCell, LexicalEnv};
8use sim_lib_function::CapturedBinding;
9use sim_lib_gc_tracing::ManagedHeap;
10use sim_lib_mutation::{ManagedHandle, ManagedNode};
11
12const LUA_BINDING_LIMIT: usize = 4096;
13
14/// Lexical local environment used by the Lua core eval policy.
15#[derive(Clone)]
16pub struct LuaEnv {
17    lexical: LexicalEnv,
18    managed: Arc<Mutex<ManagedHeap<ManagedNode<()>>>>,
19    handles: Arc<ManagedBindingFrame>,
20}
21
22struct ManagedBindingFrame {
23    parent: Option<Arc<ManagedBindingFrame>>,
24    slots: Mutex<BTreeMap<Symbol, ManagedHandle>>,
25}
26
27impl Default for LuaEnv {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl LuaEnv {
34    /// Build an empty Lua local environment.
35    pub fn new() -> Self {
36        Self {
37            lexical: LexicalEnv::new(),
38            managed: Arc::new(Mutex::new(
39                ManagedHeap::retaining(LUA_BINDING_LIMIT)
40                    .expect("the Lua binding limit is nonzero"),
41            )),
42            handles: Arc::new(ManagedBindingFrame {
43                parent: None,
44                slots: Mutex::new(BTreeMap::new()),
45            }),
46        }
47    }
48
49    /// Open a nested scope whose lookups fall through to this one.
50    pub fn child(&self) -> Self {
51        Self {
52            lexical: self.lexical.child(),
53            managed: Arc::clone(&self.managed),
54            handles: Arc::new(ManagedBindingFrame {
55                parent: Some(Arc::clone(&self.handles)),
56                slots: Mutex::new(BTreeMap::new()),
57            }),
58        }
59    }
60
61    /// Bind a Lua local value in the current frame.
62    pub fn define(&mut self, name: Symbol, value: Value) -> Result<()> {
63        self.lexical.define(name.clone(), value)?;
64        let handle = self
65            .managed
66            .lock()
67            .map_err(|_| sim_kernel::Error::PoisonedLock("lua managed bindings"))?
68            .allocate(ManagedNode::new(()))
69            .map_err(|error| {
70                sim_kernel::Error::Eval(format!("cannot allocate Lua binding: {error}"))
71            })?;
72        self.handles
73            .slots
74            .lock()
75            .map_err(|_| sim_kernel::Error::PoisonedLock("lua managed binding frame"))?
76            .insert(name, handle);
77        Ok(())
78    }
79
80    /// Return whether a Lua local is bound.
81    pub fn contains(&self, name: &Symbol) -> bool {
82        self.lexical.lookup(name).is_ok()
83    }
84
85    /// Assign an existing Lua local.
86    pub fn assign(&mut self, name: &Symbol, value: Value) -> Result<Value> {
87        self.capture(name)?.set(value.clone())?;
88        Ok(value)
89    }
90
91    /// Look up a Lua local value.
92    pub fn get(&self, name: &Symbol) -> Result<Value> {
93        self.lexical.lookup(name)
94    }
95
96    /// Capture an existing Lua local as a shared upvalue cell.
97    pub fn capture(&self, name: &Symbol) -> Result<BindingCell> {
98        self.lexical.capture_cell(name)
99    }
100
101    /// Capture an existing local as one shared cell with its managed identity.
102    pub fn capture_managed(&self, name: &Symbol) -> Result<CapturedBinding> {
103        let cell = self.capture(name)?;
104        let mut frame = Some(Arc::clone(&self.handles));
105        while let Some(current) = frame {
106            if let Some(handle) = current
107                .slots
108                .lock()
109                .map_err(|_| sim_kernel::Error::PoisonedLock("lua managed binding frame"))?
110                .get(name)
111                .copied()
112            {
113                return Ok(CapturedBinding::new(cell, handle));
114            }
115            frame = current.parent.as_ref().map(Arc::clone);
116        }
117        Err(sim_kernel::Error::Eval(format!(
118            "lua binding {name} has no managed identity"
119        )))
120    }
121}