1use std::collections::{HashMap, HashSet};
4use std::sync::{Arc, 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<HashSet<Arc<str>>>,
75 pub loading: Mutex<HashSet<Arc<str>>>,
77 pub builtin_sources: RwLock<HashMap<Arc<str>, &'static str>>,
80 pub gc_config: RwLock<Option<Arc<GcConfig>>>,
82 pub compiler_ready: std::sync::atomic::AtomicBool,
85 pub eval_fn: fn(&Form, &mut Env) -> EvalResult,
87 pub call_cljrs_fn: fn(&CljxFn, &[Value], &mut Env) -> EvalResult,
89 on_fn_defined: Option<fn(&CljxFn, &mut Env)>,
91}
92
93impl std::fmt::Debug for GlobalEnv {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 write!(f, "GlobalEnv {{ ... }}")
96 }
97}
98
99impl GlobalEnv {
100 pub fn new(
101 eval_fn: fn(&Form, &mut Env) -> EvalResult,
102 call_cljrs_fn: fn(&CljxFn, &[Value], &mut Env) -> EvalResult,
103 on_fn_defined: Option<fn(&CljxFn, &mut Env)>,
104 ) -> Arc<Self> {
105 Arc::new(Self {
106 namespaces: RwLock::new(HashMap::new()),
107 source_paths: RwLock::new(Vec::new()),
108 loaded: Mutex::new(HashSet::new()),
109 loading: Mutex::new(HashSet::new()),
110 builtin_sources: RwLock::new(HashMap::new()),
111 gc_config: RwLock::new(None),
112 compiler_ready: std::sync::atomic::AtomicBool::new(false),
113 eval_fn,
114 call_cljrs_fn,
115 on_fn_defined,
116 })
117 }
118
119 pub fn set_source_paths(&self, paths: Vec<std::path::PathBuf>) {
121 *self.source_paths.write().unwrap() = paths;
122 }
123
124 pub fn register_builtin_source(&self, ns: &str, src: &'static str) {
126 self.builtin_sources
127 .write()
128 .unwrap()
129 .insert(Arc::from(ns), src);
130 }
131
132 pub fn builtin_source(&self, ns: &str) -> Option<&'static str> {
134 self.builtin_sources.read().unwrap().get(ns).copied()
135 }
136
137 pub fn mark_loaded(&self, ns: &str) {
139 self.loaded.lock().unwrap().insert(Arc::from(ns));
140 }
141
142 pub fn is_loaded(&self, ns: &str) -> bool {
144 self.loaded.lock().unwrap().contains(ns)
145 }
146
147 pub fn set_gc_config(&self, config: Arc<GcConfig>) {
149 *self.gc_config.write().unwrap() = Some(config);
150 }
151
152 pub fn gc_config(&self) -> Option<Arc<GcConfig>> {
154 self.gc_config.read().unwrap().clone()
155 }
156
157 pub fn resolve_alias(&self, current_ns: &str, alias: &str) -> Option<Arc<str>> {
159 let map = self.namespaces.read().unwrap();
160 let ns = map.get(current_ns)?;
161 let aliases = ns.get().aliases.lock().unwrap();
162 aliases.get(alias).cloned()
163 }
164
165 pub fn get_or_create_ns(&self, name: &str) -> GcPtr<Namespace> {
167 {
169 let map = self.namespaces.read().unwrap();
170 if let Some(ns) = map.get(name) {
171 return ns.clone();
172 }
173 }
174 let mut map = self.namespaces.write().unwrap();
176 if let Some(ns) = map.get(name) {
178 return ns.clone();
179 }
180 let ns = GcPtr::new(Namespace::new(name));
181 map.insert(Arc::from(name), ns.clone());
182 ns
183 }
184
185 pub fn intern(&self, ns_name: &str, name: Arc<str>, val: Value) -> GcPtr<Var> {
187 let ns = self.get_or_create_ns(ns_name);
188 let mut interns = ns.get().interns.lock().unwrap();
189 if let Some(var) = interns.get(&name) {
190 var.get().bind(val);
192 return var.clone();
193 }
194 let var = GcPtr::new(Var::new(ns_name, name.as_ref()));
195 var.get().bind(val);
196 interns.insert(name, var.clone());
197 var
198 }
199
200 pub fn lookup_var(&self, ns_name: &str, sym_name: &str) -> Option<GcPtr<Var>> {
202 let map = self.namespaces.read().unwrap();
203 let ns = map.get(ns_name)?;
204 let interns = ns.get().interns.lock().unwrap();
205 interns.get(sym_name).cloned()
206 }
207
208 pub fn lookup_in_ns(&self, ns_name: &str, sym_name: &str) -> Option<Value> {
211 let map = self.namespaces.read().unwrap();
212 let ns = map.get(ns_name)?;
213 let ns_ref = ns.get();
214 {
216 let interns = ns_ref.interns.lock().unwrap();
217 if let Some(var) = interns.get(sym_name) {
218 return crate::dynamics::deref_var(var);
219 }
220 }
221 {
223 let refers = ns_ref.refers.lock().unwrap();
224 if let Some(var) = refers.get(sym_name) {
225 return crate::dynamics::deref_var(var);
226 }
227 }
228 None
229 }
230
231 pub fn lookup_var_in_ns(&self, ns_name: &str, sym_name: &str) -> Option<GcPtr<Var>> {
233 let map = self.namespaces.read().unwrap();
234 let ns = map.get(ns_name)?;
235 let ns_ref = ns.get();
236 {
237 let interns = ns_ref.interns.lock().unwrap();
238 if let Some(var) = interns.get(sym_name) {
239 return Some(var.clone());
240 }
241 }
242 {
243 let refers = ns_ref.refers.lock().unwrap();
244 if let Some(var) = refers.get(sym_name) {
245 return Some(var.clone());
246 }
247 }
248 None
249 }
250
251 pub fn refer_all(&self, dst_ns: &str, src_ns: &str) {
253 let map = self.namespaces.read().unwrap();
254 let src = match map.get(src_ns) {
255 Some(ns) => ns.clone(),
256 None => return,
257 };
258 let dst = match map.get(dst_ns) {
259 Some(ns) => ns.clone(),
260 None => return,
261 };
262 let src_interns = src.get().interns.lock().unwrap();
263 let mut dst_refers = dst.get().refers.lock().unwrap();
264 for (name, var) in src_interns.iter() {
265 dst_refers.insert(name.clone(), var.clone());
266 }
267 }
268
269 pub fn refer_named(&self, dst_ns: &str, src_ns: &str, names: &[Arc<str>]) {
271 let map = self.namespaces.read().unwrap();
272 let src = match map.get(src_ns) {
273 Some(ns) => ns.clone(),
274 None => return,
275 };
276 let dst = match map.get(dst_ns) {
277 Some(ns) => ns.clone(),
278 None => return,
279 };
280 let src_interns = src.get().interns.lock().unwrap();
281 let mut dst_refers = dst.get().refers.lock().unwrap();
282 for name in names {
283 if let Some(var) = src_interns.get(name) {
284 dst_refers
285 .entry(name.clone())
286 .or_insert_with(|| var.clone());
287 }
288 }
289 }
290
291 pub fn add_alias(&self, current_ns: &str, alias: &str, full_ns: &str) {
293 let ns_ptr = self.get_or_create_ns(current_ns);
294 let mut aliases = ns_ptr.get().aliases.lock().unwrap();
295 aliases.insert(Arc::from(alias), Arc::from(full_ns));
296 }
297
298 #[inline(always)]
300 pub fn eval(&self, form: &Form, env: &mut Env) -> EvalResult {
301 (self.eval_fn)(form, env)
302 }
303
304 #[inline(always)]
306 pub fn call_cljrs_fn(&self, func: &CljxFn, args: &[Value], env: &mut Env) -> EvalResult {
307 (self.call_cljrs_fn)(func, args, env)
308 }
309
310 #[inline(always)]
312 pub fn on_fn_defined(&self, f: &CljxFn, env: &mut Env) {
313 if let Some(hook) = self.on_fn_defined {
314 hook(f, env);
315 }
316 }
317
318 pub fn set_on_fn_defined(&mut self, hook: fn(&CljxFn, &mut Env)) {
320 self.on_fn_defined = Some(hook);
321 }
322}
323
324pub struct Env {
328 pub frames: Vec<Frame>,
329 pub current_ns: Arc<str>,
330 pub globals: Arc<GlobalEnv>,
331}
332
333impl Env {
334 pub fn new(globals: Arc<GlobalEnv>, ns: &str) -> Self {
335 Self {
336 frames: Vec::new(),
337 current_ns: Arc::from(ns),
338 globals,
339 }
340 }
341
342 pub fn with_closure(globals: Arc<GlobalEnv>, ns: &str, f: &CljxFn) -> Self {
344 let mut env = Self::new(globals, ns);
345 if !f.closed_over_names.is_empty() {
346 env.push_frame();
347 for (name, val) in f.closed_over_names.iter().zip(f.closed_over_vals.iter()) {
348 env.bind(name.clone(), val.clone());
349 }
350 }
351 env
352 }
353
354 pub fn push_frame(&mut self) {
355 self.frames.push(Frame::new());
356 }
357
358 pub fn pop_frame(&mut self) {
359 self.frames.pop();
360 }
361
362 pub fn bind(&mut self, name: Arc<str>, val: Value) {
364 if let Some(frame) = self.frames.last_mut() {
365 frame.bind(name, val);
366 }
367 }
370
371 pub fn lookup(&self, name: &str) -> Option<Value> {
373 feat_trace!("env", "lookup {} in {} frames", name, self.frames.len());
374 for frame in self.frames.iter().rev() {
375 if let Some(v) = frame.lookup(name) {
376 return Some(v.clone());
377 }
378 }
379 self.globals.lookup_in_ns(&self.current_ns, name)
380 }
381
382 pub fn lookup_var(&self, name: &str) -> Option<GcPtr<Var>> {
384 self.globals.lookup_var_in_ns(&self.current_ns, name)
385 }
386
387 pub fn all_local_bindings(&self) -> (Vec<Arc<str>>, Vec<Value>) {
390 let mut names = Vec::new();
391 let mut vals = Vec::new();
392 for frame in &self.frames {
394 for (n, v) in &frame.bindings {
395 names.push(n.clone());
396 vals.push(v.clone());
397 }
398 }
399 (names, vals)
400 }
401
402 pub fn child(&self) -> Self {
404 let (names, vals) = self.all_local_bindings();
405 let mut child = Self::new(self.globals.clone(), &self.current_ns);
406 if !names.is_empty() {
407 child.push_frame();
408 for (n, v) in names.into_iter().zip(vals) {
409 child.bind(n, v);
410 }
411 }
412 child
413 }
414
415 #[inline(always)]
416 pub fn eval(&mut self, form: &Form) -> EvalResult {
417 let globals = self.globals.clone();
418 globals.eval(form, self)
419 }
420
421 #[inline(always)]
422 pub fn call_cljrs_fn(&mut self, func: &CljxFn, args: &[Value]) -> EvalResult {
423 let globals = self.globals.clone();
424 globals.call_cljrs_fn(func, args, self)
425 }
426
427 #[inline(always)]
428 pub fn on_fn_defined(&mut self, func: &CljxFn) {
429 let globals = self.globals.clone();
430 globals.on_fn_defined(func, self);
431 }
432}