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, BindingCellState};
11
12type BindingSlot = Arc<Mutex<BindingCellState>>;
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 BindingCell::from_slot(name.clone(), slot)
85 .get()
86 .map_err(|error| match error {
87 Error::Eval(message) if message.contains("is not initialized") => {
88 Error::Eval(format!("lexical binding {name} is not initialized"))
89 }
90 other => other,
91 })
92 }
93
94 pub fn capture_cell(&self, name: &Symbol) -> Result<BindingCell> {
99 let Some(slot) = self.lookup_slot(name)? else {
100 return Err(Error::Eval(format!(
101 "lexical binding {name} is not defined"
102 )));
103 };
104 Ok(BindingCell::from_slot(name.clone(), slot))
105 }
106
107 fn predefine(&self, name: Symbol) -> Result<()> {
108 self.define_slot(name, None)
109 }
110
111 fn set(&self, name: &Symbol, value: Value) -> Result<()> {
112 let Some(slot) = self.lookup_slot(name)? else {
113 return Err(Error::Eval(format!(
114 "lexical binding {name} is not defined"
115 )));
116 };
117 BindingCell::from_slot(name.clone(), slot).set(value)
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 let state = value.map_or(
128 BindingCellState::Uninitialized,
129 BindingCellState::Initialized,
130 );
131 slots.insert(name, Arc::new(Mutex::new(state)));
132 Ok(())
133 }
134
135 fn lookup_slot(&self, name: &Symbol) -> Result<Option<BindingSlot>> {
136 if let Some(slot) = self.slots()?.get(name).cloned() {
137 return Ok(Some(slot));
138 }
139 match &self.frame.parent {
140 Some(parent) => parent.lookup_slot(name),
141 None => Ok(None),
142 }
143 }
144
145 fn slots(&self) -> Result<MutexGuard<'_, BTreeMap<Symbol, BindingSlot>>> {
146 self.frame
147 .slots
148 .lock()
149 .map_err(|_| Error::Eval("lexical binding frame lock is poisoned".to_owned()))
150 }
151}
152
153pub fn eval_let(
158 cx: &mut Cx,
159 outer: &LexicalEnv,
160 bindings: Vec<(Symbol, Value)>,
161 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
162) -> Result<Value> {
163 let env = outer.child();
164 for (name, value) in bindings {
165 env.define(name, value)?;
166 }
167 body(cx, &env)
168}
169
170pub fn eval_let_star(
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 for (name, initializer) in bindings {
182 let value = initializer(cx, &env)?;
183 env.define(name, value)?;
184 }
185 body(cx, &env)
186}
187
188pub fn eval_letrec(
194 cx: &mut Cx,
195 outer: &LexicalEnv,
196 bindings: Vec<(Symbol, BindingInitializer)>,
197 body: impl FnOnce(&mut Cx, &LexicalEnv) -> Result<Value>,
198) -> Result<Value> {
199 let env = outer.child();
200 let names = bindings
201 .iter()
202 .map(|(name, _)| name.clone())
203 .collect::<Vec<_>>();
204 for name in &names {
205 env.predefine(name.clone())?;
206 }
207 for ((_, initializer), name) in bindings.into_iter().zip(names.iter()) {
208 let value = initializer(cx, &env)?;
209 env.set(name, value)?;
210 }
211 body(cx, &env)
212}
213
214#[derive(Clone)]
220pub struct LexicalFunction {
221 name: Symbol,
222 env: LexicalEnv,
223 body: LexicalBody,
224}
225
226impl LexicalFunction {
227 pub fn new(name: Symbol, env: LexicalEnv, body: LexicalBody) -> Self {
229 Self { name, env, body }
230 }
231
232 pub fn name(&self) -> &Symbol {
234 &self.name
235 }
236}
237
238impl Object for LexicalFunction {
239 fn display(&self, _cx: &mut Cx) -> Result<String> {
240 Ok(format!("#<binding-function {}>", self.name))
241 }
242
243 fn as_any(&self) -> &dyn std::any::Any {
244 self
245 }
246}
247
248impl ObjectCompat for LexicalFunction {
249 fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
250 cx.resolve_class(&Symbol::qualified("core", "Function"))
251 }
252
253 fn as_callable(&self) -> Option<&dyn Callable> {
254 Some(self)
255 }
256}
257
258impl Callable for LexicalFunction {
259 fn call(&self, cx: &mut Cx, args: Args) -> Result<Value> {
260 (self.body)(cx, &self.env, args.into_vec())
261 }
262}
263
264pub fn lexical_function_value(
269 cx: &mut Cx,
270 name: Symbol,
271 env: LexicalEnv,
272 body: LexicalBody,
273) -> Result<Value> {
274 cx.factory()
275 .opaque(Arc::new(LexicalFunction::new(name, env, body)))
276}