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
10use crate::BindingCell;
11
12type BindingSlot = Arc<Mutex<Option<Value>>>;
13
14pub type BindingInitializer =
19 Box<dyn Fn(&mut Cx, &LexicalEnv) -> Result<Value> + Send + Sync + 'static>;
20
21type LexicalBody =
22 Arc<dyn Fn(&mut Cx, &LexicalEnv, Vec<Value>) -> Result<Value> + Send + Sync + 'static>;
23
24#[derive(Clone, Debug)]
30pub struct LexicalEnv {
31 frame: Arc<LexicalFrame>,
32}
33
34#[derive(Debug)]
35struct LexicalFrame {
36 parent: Option<LexicalEnv>,
37 slots: Mutex<BTreeMap<Symbol, BindingSlot>>,
38}
39
40impl Default for LexicalEnv {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl LexicalEnv {
47 pub fn new() -> Self {
49 Self {
50 frame: Arc::new(LexicalFrame {
51 parent: None,
52 slots: Mutex::new(BTreeMap::new()),
53 }),
54 }
55 }
56
57 pub fn child(&self) -> Self {
59 Self {
60 frame: Arc::new(LexicalFrame {
61 parent: Some(self.clone()),
62 slots: Mutex::new(BTreeMap::new()),
63 }),
64 }
65 }
66
67 pub fn define(&self, name: Symbol, value: Value) -> Result<()> {
72 self.define_slot(name, Some(value))
73 }
74
75 pub fn lookup(&self, name: &Symbol) -> Result<Value> {
79 let Some(slot) = self.lookup_slot(name)? else {
80 return Err(Error::Eval(format!(
81 "lexical binding {name} is not defined"
82 )));
83 };
84 slot.lock()
85 .map_err(|_| Error::Eval(format!("lexical binding {name} lock is poisoned")))?
86 .clone()
87 .ok_or_else(|| Error::Eval(format!("lexical binding {name} is not initialized")))
88 }
89
90 pub fn capture_cell(&self, name: &Symbol) -> Result<BindingCell> {
95 let Some(slot) = self.lookup_slot(name)? else {
96 return Err(Error::Eval(format!(
97 "lexical binding {name} is not defined"
98 )));
99 };
100 Ok(BindingCell::from_slot(name.clone(), slot))
101 }
102
103 fn predefine(&self, name: Symbol) -> Result<()> {
104 self.define_slot(name, None)
105 }
106
107 fn set(&self, name: &Symbol, value: Value) -> Result<()> {
108 let Some(slot) = self.lookup_slot(name)? else {
109 return Err(Error::Eval(format!(
110 "lexical binding {name} is not defined"
111 )));
112 };
113 *slot
114 .lock()
115 .map_err(|_| Error::Eval(format!("lexical binding {name} lock is poisoned")))? =
116 Some(value);
117 Ok(())
118 }
119
120 fn define_slot(&self, name: Symbol, value: Option<Value>) -> Result<()> {
121 let mut slots = self.slots()?;
122 if slots.contains_key(&name) {
123 return Err(Error::Eval(format!(
124 "lexical binding {name} is already defined in this frame"
125 )));
126 }
127 slots.insert(name, Arc::new(Mutex::new(value)));
128 Ok(())
129 }
130
131 fn lookup_slot(&self, name: &Symbol) -> Result<Option<BindingSlot>> {
132 if let Some(slot) = self.slots()?.get(name).cloned() {
133 return Ok(Some(slot));
134 }
135 match &self.frame.parent {
136 Some(parent) => parent.lookup_slot(name),
137 None => Ok(None),
138 }
139 }
140
141 fn slots(&self) -> Result<MutexGuard<'_, BTreeMap<Symbol, BindingSlot>>> {
142 self.frame
143 .slots
144 .lock()
145 .map_err(|_| Error::Eval("lexical binding frame lock is poisoned".to_owned()))
146 }
147}
148
149pub fn eval_let(
154 cx: &mut Cx,
155 outer: &LexicalEnv,
156 bindings: Vec<(Symbol, Value)>,
157 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
158) -> Result<Value> {
159 let env = outer.child();
160 for (name, value) in bindings {
161 env.define(name, value)?;
162 }
163 body(cx, &env)
164}
165
166pub fn eval_let_star(
171 cx: &mut Cx,
172 outer: &LexicalEnv,
173 bindings: Vec<(Symbol, BindingInitializer)>,
174 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
175) -> Result<Value> {
176 let env = outer.child();
177 for (name, initializer) in bindings {
178 let value = initializer(cx, &env)?;
179 env.define(name, value)?;
180 }
181 body(cx, &env)
182}
183
184pub fn eval_letrec(
190 cx: &mut Cx,
191 outer: &LexicalEnv,
192 bindings: Vec<(Symbol, BindingInitializer)>,
193 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
194) -> Result<Value> {
195 let env = outer.child();
196 let names = bindings
197 .iter()
198 .map(|(name, _)| name.clone())
199 .collect::<Vec<_>>();
200 for name in &names {
201 env.predefine(name.clone())?;
202 }
203 for ((_, initializer), name) in bindings.into_iter().zip(names.iter()) {
204 let value = initializer(cx, &env)?;
205 env.set(name, value)?;
206 }
207 body(cx, &env)
208}
209
210#[derive(Clone)]
216pub struct LexicalFunction {
217 name: Symbol,
218 env: LexicalEnv,
219 body: LexicalBody,
220}
221
222impl LexicalFunction {
223 pub fn new(name: Symbol, env: LexicalEnv, body: LexicalBody) -> Self {
225 Self { name, env, body }
226 }
227
228 pub fn name(&self) -> &Symbol {
230 &self.name
231 }
232}
233
234impl Object for LexicalFunction {
235 fn display(&self, _cx: &mut Cx) -> Result<String> {
236 Ok(format!("#<binding-function {}>", self.name))
237 }
238
239 fn as_any(&self) -> &dyn std::any::Any {
240 self
241 }
242}
243
244impl ObjectCompat for LexicalFunction {
245 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
246 cx.resolve_class(&Symbol::qualified("core", "Function"))
247 }
248
249 fn as_callable(&self) -> Option<&dyn Callable> {
250 Some(self)
251 }
252}
253
254impl Callable for LexicalFunction {
255 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
256 (self.body)(cx, &self.env, args.into_vec())
257 }
258}
259
260pub fn lexical_function_value(
265 cx: &mut Cx,
266 name: Symbol,
267 env: LexicalEnv,
268 body: LexicalBody,
269) -> Result<Value> {
270 cx.factory()
271 .opaque(Arc::new(LexicalFunction::new(name, env, body)))
272}