1use std::{
2 collections::BTreeMap,
3 sync::{Arc, Mutex, MutexGuard},
4};
5
6use sim_kernel::{
7 Args, Callable, ClassRef, Cx, Error, Object, ObjectCompat, Result, Symbol, Value,
8};
9
10type BindingSlot = Arc<Mutex<Option<Value>>>;
11
12pub type BindingInitializer =
17 Box<dyn Fn(&mut Cx, &LexicalEnv) -> Result<Value> + Send + Sync + 'static>;
18
19type LexicalBody =
20 Arc<dyn Fn(&mut Cx, &LexicalEnv, Vec<Value>) -> Result<Value> + Send + Sync + 'static>;
21
22#[derive(Clone, Debug)]
28pub struct LexicalEnv {
29 frame: Arc<LexicalFrame>,
30}
31
32#[derive(Debug)]
33struct LexicalFrame {
34 parent: Option<LexicalEnv>,
35 slots: Mutex<BTreeMap<Symbol, BindingSlot>>,
36}
37
38impl Default for LexicalEnv {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl LexicalEnv {
45 pub fn new() -> Self {
47 Self {
48 frame: Arc::new(LexicalFrame {
49 parent: None,
50 slots: Mutex::new(BTreeMap::new()),
51 }),
52 }
53 }
54
55 pub fn child(&self) -> Self {
57 Self {
58 frame: Arc::new(LexicalFrame {
59 parent: Some(self.clone()),
60 slots: Mutex::new(BTreeMap::new()),
61 }),
62 }
63 }
64
65 pub fn define(&self, name: Symbol, value: Value) -> Result<()> {
70 self.define_slot(name, Some(value))
71 }
72
73 pub fn lookup(&self, name: &Symbol) -> Result<Value> {
77 let Some(slot) = self.lookup_slot(name)? else {
78 return Err(Error::Eval(format!(
79 "lexical binding {name} is not defined"
80 )));
81 };
82 slot.lock()
83 .map_err(|_| Error::Eval(format!("lexical binding {name} lock is poisoned")))?
84 .clone()
85 .ok_or_else(|| Error::Eval(format!("lexical binding {name} is not initialized")))
86 }
87
88 fn predefine(&self, name: Symbol) -> Result<()> {
89 self.define_slot(name, None)
90 }
91
92 fn set(&self, name: &Symbol, value: Value) -> Result<()> {
93 let Some(slot) = self.lookup_slot(name)? else {
94 return Err(Error::Eval(format!(
95 "lexical binding {name} is not defined"
96 )));
97 };
98 *slot
99 .lock()
100 .map_err(|_| Error::Eval(format!("lexical binding {name} lock is poisoned")))? =
101 Some(value);
102 Ok(())
103 }
104
105 fn define_slot(&self, name: Symbol, value: Option<Value>) -> Result<()> {
106 let mut slots = self.slots()?;
107 if slots.contains_key(&name) {
108 return Err(Error::Eval(format!(
109 "lexical binding {name} is already defined in this frame"
110 )));
111 }
112 slots.insert(name, Arc::new(Mutex::new(value)));
113 Ok(())
114 }
115
116 fn lookup_slot(&self, name: &Symbol) -> Result<Option<BindingSlot>> {
117 if let Some(slot) = self.slots()?.get(name).cloned() {
118 return Ok(Some(slot));
119 }
120 match &self.frame.parent {
121 Some(parent) => parent.lookup_slot(name),
122 None => Ok(None),
123 }
124 }
125
126 fn slots(&self) -> Result<MutexGuard<'_, BTreeMap<Symbol, BindingSlot>>> {
127 self.frame
128 .slots
129 .lock()
130 .map_err(|_| Error::Eval("lexical binding frame lock is poisoned".to_owned()))
131 }
132}
133
134pub fn eval_let(
139 cx: &mut Cx,
140 outer: &LexicalEnv,
141 bindings: Vec<(Symbol, Value)>,
142 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
143) -> Result<Value> {
144 let env = outer.child();
145 for (name, value) in bindings {
146 env.define(name, value)?;
147 }
148 body(cx, &env)
149}
150
151pub fn eval_let_star(
156 cx: &mut Cx,
157 outer: &LexicalEnv,
158 bindings: Vec<(Symbol, BindingInitializer)>,
159 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
160) -> Result<Value> {
161 let env = outer.child();
162 for (name, initializer) in bindings {
163 let value = initializer(cx, &env)?;
164 env.define(name, value)?;
165 }
166 body(cx, &env)
167}
168
169pub fn eval_letrec(
175 cx: &mut Cx,
176 outer: &LexicalEnv,
177 bindings: Vec<(Symbol, BindingInitializer)>,
178 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
179) -> Result<Value> {
180 let env = outer.child();
181 let names = bindings
182 .iter()
183 .map(|(name, _)| name.clone())
184 .collect::<Vec<_>>();
185 for name in &names {
186 env.predefine(name.clone())?;
187 }
188 for ((_, initializer), name) in bindings.into_iter().zip(names.iter()) {
189 let value = initializer(cx, &env)?;
190 env.set(name, value)?;
191 }
192 body(cx, &env)
193}
194
195#[derive(Clone)]
201pub struct LexicalFunction {
202 name: Symbol,
203 env: LexicalEnv,
204 body: LexicalBody,
205}
206
207impl LexicalFunction {
208 pub fn new(name: Symbol, env: LexicalEnv, body: LexicalBody) -> Self {
210 Self { name, env, body }
211 }
212
213 pub fn name(&self) -> &Symbol {
215 &self.name
216 }
217}
218
219impl Object for LexicalFunction {
220 fn display(&self, _cx: &mut Cx) -> Result<String> {
221 Ok(format!("#<binding-function {}>", self.name))
222 }
223
224 fn as_any(&self) -> &dyn std::any::Any {
225 self
226 }
227}
228
229impl ObjectCompat for LexicalFunction {
230 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
231 cx.resolve_class(&Symbol::qualified("core", "Function"))
232 }
233
234 fn as_callable(&self) -> Option<&dyn Callable> {
235 Some(self)
236 }
237}
238
239impl Callable for LexicalFunction {
240 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
241 (self.body)(cx, &self.env, args.into_vec())
242 }
243}
244
245pub fn lexical_function_value(
250 cx: &mut Cx,
251 name: Symbol,
252 env: LexicalEnv,
253 body: LexicalBody,
254) -> Result<Value> {
255 cx.factory()
256 .opaque(Arc::new(LexicalFunction::new(name, env, body)))
257}