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#[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 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 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 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 pub fn contains(&self, name: &Symbol) -> bool {
82 self.lexical.lookup(name).is_ok()
83 }
84
85 pub fn assign(&mut self, name: &Symbol, value: Value) -> Result<Value> {
87 self.capture(name)?.set(value.clone())?;
88 Ok(value)
89 }
90
91 pub fn get(&self, name: &Symbol) -> Result<Value> {
93 self.lexical.lookup(name)
94 }
95
96 pub fn capture(&self, name: &Symbol) -> Result<BindingCell> {
98 self.lexical.capture_cell(name)
99 }
100
101 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}