1use std::collections::HashMap;
4use std::sync::{Arc, Condvar, Mutex, RwLock};
5
6use crate::error::EvalResult;
7use cljrs_gc::{GcConfig, GcPtr};
8use cljrs_logging::feat_trace;
9use cljrs_reader::Form;
10use cljrs_value::{CljxFn, Namespace, Value, Var};
11#[derive(Debug, Clone)]
15pub enum RequireRefer {
16 None,
17 All,
18 Named(Vec<Arc<str>>),
19}
20
21#[derive(Debug, Clone)]
23pub struct RequireSpec {
24 pub ns: Arc<str>,
25 pub alias: Option<Arc<str>>,
26 pub refer: RequireRefer,
27}
28
29pub struct Frame {
33 pub bindings: Vec<(Arc<str>, Value)>,
34}
35
36impl Default for Frame {
37 fn default() -> Self {
38 Self::new()
39 }
40}
41
42impl Frame {
43 pub fn new() -> Self {
44 Self {
45 bindings: Vec::new(),
46 }
47 }
48
49 pub fn bind(&mut self, name: Arc<str>, val: Value) {
50 self.bindings.push((name, val));
52 }
53
54 pub fn lookup(&self, name: &str) -> Option<&Value> {
55 feat_trace!("env", "lookup {}", name);
57 for (n, v) in self.bindings.iter().rev() {
58 if n.as_ref() == name {
59 return Some(v);
60 }
61 }
62 None
63 }
64}
65
66pub struct GlobalEnv {
70 pub namespaces: RwLock<HashMap<Arc<str>, GcPtr<Namespace>>>,
71 pub source_paths: RwLock<Vec<std::path::PathBuf>>,
73 pub loaded: Mutex<std::collections::HashSet<Arc<str>>>,
75 pub loading: Mutex<HashMap<Arc<str>, std::thread::ThreadId>>,
79 pub loading_done: Condvar,
81 pub builtin_sources: RwLock<HashMap<Arc<str>, &'static str>>,
84 pub gc_config: RwLock<Option<Arc<GcConfig>>>,
86 pub compiler_ready: std::sync::atomic::AtomicBool,
89 pub eval_fn: fn(&Form, &mut Env) -> EvalResult,
91 pub call_cljrs_fn: fn(&CljxFn, &[Value], &mut Env) -> EvalResult,
93 on_fn_defined: Option<fn(&CljxFn, &mut Env)>,
95}
96
97impl std::fmt::Debug for GlobalEnv {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 write!(f, "GlobalEnv {{ ... }}")
100 }
101}
102
103impl GlobalEnv {
104 pub fn new(
105 eval_fn: fn(&Form, &mut Env) -> EvalResult,
106 call_cljrs_fn: fn(&CljxFn, &[Value], &mut Env) -> EvalResult,
107 on_fn_defined: Option<fn(&CljxFn, &mut Env)>,
108 ) -> Arc<Self> {
109 Arc::new(Self {
110 namespaces: RwLock::new(HashMap::new()),
111 source_paths: RwLock::new(Vec::new()),
112 loaded: Mutex::new(std::collections::HashSet::new()),
113 loading: Mutex::new(HashMap::new()),
114 loading_done: Condvar::new(),
115 builtin_sources: RwLock::new(HashMap::new()),
116 gc_config: RwLock::new(None),
117 compiler_ready: std::sync::atomic::AtomicBool::new(false),
118 eval_fn,
119 call_cljrs_fn,
120 on_fn_defined,
121 })
122 }
123
124 pub fn set_source_paths(&self, paths: Vec<std::path::PathBuf>) {
126 *self.source_paths.write().unwrap() = paths;
127 }
128
129 pub fn register_builtin_source(&self, ns: &str, src: &'static str) {
131 self.builtin_sources
132 .write()
133 .unwrap()
134 .insert(Arc::from(ns), src);
135 }
136
137 pub fn builtin_source(&self, ns: &str) -> Option<&'static str> {
139 self.builtin_sources.read().unwrap().get(ns).copied()
140 }
141
142 pub fn mark_loaded(&self, ns: &str) {
144 self.loaded.lock().unwrap().insert(Arc::from(ns));
145 }
146
147 pub fn is_loaded(&self, ns: &str) -> bool {
149 self.loaded.lock().unwrap().contains(ns)
150 }
151
152 pub fn set_gc_config(&self, config: Arc<GcConfig>) {
154 *self.gc_config.write().unwrap() = Some(config);
155 }
156
157 pub fn gc_config(&self) -> Option<Arc<GcConfig>> {
159 self.gc_config.read().unwrap().clone()
160 }
161
162 pub fn resolve_alias(&self, current_ns: &str, alias: &str) -> Option<Arc<str>> {
164 let map = self.namespaces.read().unwrap();
165 let ns = map.get(current_ns)?;
166 let aliases = ns.get().aliases.lock().unwrap();
167 aliases.get(alias).cloned()
168 }
169
170 pub fn get_or_create_ns(&self, name: &str) -> GcPtr<Namespace> {
172 {
174 let map = self.namespaces.read().unwrap();
175 if let Some(ns) = map.get(name) {
176 return ns.clone();
177 }
178 }
179 let mut map = self.namespaces.write().unwrap();
181 if let Some(ns) = map.get(name) {
183 return ns.clone();
184 }
185 let ns = GcPtr::new(Namespace::new(name));
186 map.insert(Arc::from(name), ns.clone());
187 ns
188 }
189
190 pub fn intern(&self, ns_name: &str, name: Arc<str>, val: Value) -> GcPtr<Var> {
192 let ns = self.get_or_create_ns(ns_name);
193 let mut interns = ns.get().interns.lock().unwrap();
194 if let Some(var) = interns.get(&name) {
195 var.get().bind(val);
197 return var.clone();
198 }
199 let var = GcPtr::new(Var::new(ns_name, name.as_ref()));
200 var.get().bind(val);
201 interns.insert(name, var.clone());
202 var
203 }
204
205 pub fn lookup_var(&self, ns_name: &str, sym_name: &str) -> Option<GcPtr<Var>> {
207 let map = self.namespaces.read().unwrap();
208 let ns = map.get(ns_name)?;
209 let interns = ns.get().interns.lock().unwrap();
210 interns.get(sym_name).cloned()
211 }
212
213 pub fn lookup_in_ns(&self, ns_name: &str, sym_name: &str) -> Option<Value> {
216 let map = self.namespaces.read().unwrap();
217 let ns = map.get(ns_name)?;
218 let ns_ref = ns.get();
219 {
221 let interns = ns_ref.interns.lock().unwrap();
222 if let Some(var) = interns.get(sym_name) {
223 return crate::dynamics::deref_var(var);
224 }
225 }
226 {
228 let refers = ns_ref.refers.lock().unwrap();
229 if let Some(var) = refers.get(sym_name) {
230 return crate::dynamics::deref_var(var);
231 }
232 }
233 None
234 }
235
236 pub fn lookup_var_in_ns(&self, ns_name: &str, sym_name: &str) -> Option<GcPtr<Var>> {
238 let map = self.namespaces.read().unwrap();
239 let ns = map.get(ns_name)?;
240 let ns_ref = ns.get();
241 {
242 let interns = ns_ref.interns.lock().unwrap();
243 if let Some(var) = interns.get(sym_name) {
244 return Some(var.clone());
245 }
246 }
247 {
248 let refers = ns_ref.refers.lock().unwrap();
249 if let Some(var) = refers.get(sym_name) {
250 return Some(var.clone());
251 }
252 }
253 None
254 }
255
256 pub fn refer_all(&self, dst_ns: &str, src_ns: &str) {
258 let map = self.namespaces.read().unwrap();
259 let src = match map.get(src_ns) {
260 Some(ns) => ns.clone(),
261 None => return,
262 };
263 let dst = match map.get(dst_ns) {
264 Some(ns) => ns.clone(),
265 None => return,
266 };
267 let src_interns = src.get().interns.lock().unwrap();
268 let mut dst_refers = dst.get().refers.lock().unwrap();
269 for (name, var) in src_interns.iter() {
270 dst_refers.insert(name.clone(), var.clone());
271 }
272 }
273
274 pub fn refer_named(&self, dst_ns: &str, src_ns: &str, names: &[Arc<str>]) {
276 let map = self.namespaces.read().unwrap();
277 let src = match map.get(src_ns) {
278 Some(ns) => ns.clone(),
279 None => return,
280 };
281 let dst = match map.get(dst_ns) {
282 Some(ns) => ns.clone(),
283 None => return,
284 };
285 let src_interns = src.get().interns.lock().unwrap();
286 let mut dst_refers = dst.get().refers.lock().unwrap();
287 for name in names {
288 if let Some(var) = src_interns.get(name) {
289 dst_refers
290 .entry(name.clone())
291 .or_insert_with(|| var.clone());
292 }
293 }
294 }
295
296 pub fn add_alias(&self, current_ns: &str, alias: &str, full_ns: &str) {
298 let ns_ptr = self.get_or_create_ns(current_ns);
299 let mut aliases = ns_ptr.get().aliases.lock().unwrap();
300 aliases.insert(Arc::from(alias), Arc::from(full_ns));
301 }
302
303 #[inline(always)]
305 pub fn eval(&self, form: &Form, env: &mut Env) -> EvalResult {
306 (self.eval_fn)(form, env)
307 }
308
309 #[inline(always)]
311 pub fn call_cljrs_fn(&self, func: &CljxFn, args: &[Value], env: &mut Env) -> EvalResult {
312 (self.call_cljrs_fn)(func, args, env)
313 }
314
315 #[inline(always)]
317 pub fn on_fn_defined(&self, f: &CljxFn, env: &mut Env) {
318 if let Some(hook) = self.on_fn_defined {
319 hook(f, env);
320 }
321 }
322
323 pub fn set_on_fn_defined(&mut self, hook: fn(&CljxFn, &mut Env)) {
325 self.on_fn_defined = Some(hook);
326 }
327}
328
329pub struct Env {
333 pub frames: Vec<Frame>,
334 pub current_ns: Arc<str>,
335 pub globals: Arc<GlobalEnv>,
336}
337
338impl Env {
339 pub fn new(globals: Arc<GlobalEnv>, ns: &str) -> Self {
340 Self {
341 frames: Vec::new(),
342 current_ns: Arc::from(ns),
343 globals,
344 }
345 }
346
347 pub fn with_closure(globals: Arc<GlobalEnv>, ns: &str, f: &CljxFn) -> Self {
349 let mut env = Self::new(globals, ns);
350 if !f.closed_over_names.is_empty() {
351 env.push_frame();
352 for (name, val) in f.closed_over_names.iter().zip(f.closed_over_vals.iter()) {
353 env.bind(name.clone(), val.clone());
354 }
355 }
356 env
357 }
358
359 pub fn push_frame(&mut self) {
360 self.frames.push(Frame::new());
361 }
362
363 pub fn pop_frame(&mut self) {
364 self.frames.pop();
365 }
366
367 pub fn bind(&mut self, name: Arc<str>, val: Value) {
369 if let Some(frame) = self.frames.last_mut() {
370 frame.bind(name, val);
371 }
372 }
375
376 pub fn lookup(&self, name: &str) -> Option<Value> {
378 feat_trace!("env", "lookup {} in {} frames", name, self.frames.len());
379 for frame in self.frames.iter().rev() {
380 if let Some(v) = frame.lookup(name) {
381 return Some(v.clone());
382 }
383 }
384 self.globals.lookup_in_ns(&self.current_ns, name)
385 }
386
387 pub fn lookup_var(&self, name: &str) -> Option<GcPtr<Var>> {
389 self.globals.lookup_var_in_ns(&self.current_ns, name)
390 }
391
392 pub fn all_local_bindings(&self) -> (Vec<Arc<str>>, Vec<Value>) {
395 let mut names = Vec::new();
396 let mut vals = Vec::new();
397 for frame in &self.frames {
399 for (n, v) in &frame.bindings {
400 names.push(n.clone());
401 vals.push(v.clone());
402 }
403 }
404 (names, vals)
405 }
406
407 pub fn child(&self) -> Self {
409 let (names, vals) = self.all_local_bindings();
410 let mut child = Self::new(self.globals.clone(), &self.current_ns);
411 if !names.is_empty() {
412 child.push_frame();
413 for (n, v) in names.into_iter().zip(vals) {
414 child.bind(n, v);
415 }
416 }
417 child
418 }
419
420 #[inline(always)]
421 pub fn eval(&mut self, form: &Form) -> EvalResult {
422 let globals = self.globals.clone();
423 globals.eval(form, self)
424 }
425
426 #[inline(always)]
427 pub fn call_cljrs_fn(&mut self, func: &CljxFn, args: &[Value]) -> EvalResult {
428 let globals = self.globals.clone();
429 globals.call_cljrs_fn(func, args, self)
430 }
431
432 #[inline(always)]
433 pub fn on_fn_defined(&mut self, func: &CljxFn) {
434 let globals = self.globals.clone();
435 globals.on_fn_defined(func, self);
436 }
437}