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_mutation::{HardCappedRetainPolicy, ManagedArena, ManagedHandle, ManagedNode};
10
11const LUA_BINDING_LIMIT: usize = 4096;
12
13#[derive(Clone)]
15pub struct LuaEnv {
16 lexical: LexicalEnv,
17 managed: Arc<Mutex<ManagedArena<ManagedNode<()>>>>,
18 handles: Arc<ManagedBindingFrame>,
19}
20
21struct ManagedBindingFrame {
22 parent: Option<Arc<ManagedBindingFrame>>,
23 slots: Mutex<BTreeMap<Symbol, ManagedHandle>>,
24}
25
26impl Default for LuaEnv {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl LuaEnv {
33 pub fn new() -> Self {
35 Self {
36 lexical: LexicalEnv::new(),
37 managed: Arc::new(Mutex::new(ManagedArena::new(
38 HardCappedRetainPolicy::new(LUA_BINDING_LIMIT)
39 .expect("the Lua binding limit is nonzero"),
40 ))),
41 handles: Arc::new(ManagedBindingFrame {
42 parent: None,
43 slots: Mutex::new(BTreeMap::new()),
44 }),
45 }
46 }
47
48 pub fn child(&self) -> Self {
50 Self {
51 lexical: self.lexical.child(),
52 managed: Arc::clone(&self.managed),
53 handles: Arc::new(ManagedBindingFrame {
54 parent: Some(Arc::clone(&self.handles)),
55 slots: Mutex::new(BTreeMap::new()),
56 }),
57 }
58 }
59
60 pub fn define(&mut self, name: Symbol, value: Value) -> Result<()> {
62 self.lexical.define(name.clone(), value)?;
63 let handle = self
64 .managed
65 .lock()
66 .map_err(|_| sim_kernel::Error::PoisonedLock("lua managed bindings"))?
67 .allocate(ManagedNode::new(()))
68 .map_err(|error| {
69 sim_kernel::Error::Eval(format!("cannot allocate Lua binding: {error}"))
70 })?;
71 self.handles
72 .slots
73 .lock()
74 .map_err(|_| sim_kernel::Error::PoisonedLock("lua managed binding frame"))?
75 .insert(name, handle);
76 Ok(())
77 }
78
79 pub fn contains(&self, name: &Symbol) -> bool {
81 self.lexical.lookup(name).is_ok()
82 }
83
84 pub fn assign(&mut self, name: &Symbol, value: Value) -> Result<Value> {
86 self.capture(name)?.set(value.clone())?;
87 Ok(value)
88 }
89
90 pub fn get(&self, name: &Symbol) -> Result<Value> {
92 self.lexical.lookup(name)
93 }
94
95 pub fn capture(&self, name: &Symbol) -> Result<BindingCell> {
97 self.lexical.capture_cell(name)
98 }
99
100 pub fn capture_managed(&self, name: &Symbol) -> Result<CapturedBinding> {
102 let cell = self.capture(name)?;
103 let mut frame = Some(Arc::clone(&self.handles));
104 while let Some(current) = frame {
105 if let Some(handle) = current
106 .slots
107 .lock()
108 .map_err(|_| sim_kernel::Error::PoisonedLock("lua managed binding frame"))?
109 .get(name)
110 .copied()
111 {
112 return Ok(CapturedBinding::new(cell, handle));
113 }
114 frame = current.parent.as_ref().map(Arc::clone);
115 }
116 Err(sim_kernel::Error::Eval(format!(
117 "lua binding {name} has no managed identity"
118 )))
119 }
120}