1use crate::builtins::form::form_to_value;
4use cljrs_gc::GcPtr;
5use cljrs_reader::{Form, FormKind};
6use cljrs_value::{
7 Atom, CljxFn, CljxFnArity, Delay, LazySeq, MapValue, PersistentList, Symbol, Thunk, Value,
8 Volatile,
9};
10use std::collections::HashMap;
11use std::sync::Arc;
12
13use crate::env::env::Env;
14use crate::env::error::{EvalError, EvalResult};
15use crate::interp::destructure::value_to_seq_vec;
16use crate::interp::eval::eval;
17
18#[allow(dead_code)]
21fn eval_error_to_value(e: EvalError) -> Value {
22 match e {
23 EvalError::Thrown(v) => v,
24 other => Value::string(format!("{other}")),
25 }
26}
27
28fn fire_watches(
34 watches: &std::sync::Mutex<Vec<(Value, Value)>>,
35 reference: &Value,
36 old: &Value,
37 new: &Value,
38 env: &mut Env,
39) {
40 let ws: Vec<(Value, Value)> = watches.lock().unwrap().clone();
41 for (key, f) in &ws {
42 let args = vec![key.clone(), reference.clone(), old.clone(), new.clone()];
43 if let Err(e) = crate::env::apply::apply_value(f, args, env) {
44 WATCH_ERROR.with(|cell| {
51 cell.borrow_mut().replace(e);
52 });
53 return;
54 }
55 }
56}
57
58thread_local! {
59 static WATCH_ERROR: std::cell::RefCell<Option<EvalError>> = const { std::cell::RefCell::new(None) };
60}
61
62fn check_watch_error() -> EvalResult<()> {
64 WATCH_ERROR.with(|cell| {
65 if let Some(e) = cell.borrow_mut().take() {
66 Err(e)
67 } else {
68 Ok(())
69 }
70 })
71}
72
73#[derive(Debug)]
77pub struct ClosureThunk {
78 pub f: CljxFn,
79 pub globals: std::sync::Arc<crate::env::env::GlobalEnv>,
80 pub ns: std::sync::Arc<str>,
81}
82
83struct CallableValueThunk {
89 callee: Value,
90 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
91 ns: std::sync::Arc<str>,
92}
93
94impl std::fmt::Debug for CallableValueThunk {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 f.debug_struct("CallableValueThunk")
97 .field("callee", &self.callee.type_name())
98 .field("ns", &self.ns)
99 .finish()
100 }
101}
102
103impl cljrs_gc::Trace for CallableValueThunk {
104 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
105 self.callee.trace(visitor);
106 }
107}
108
109impl Thunk for CallableValueThunk {
110 fn force(&self) -> Result<Value, String> {
111 let mut env = Env::new(self.globals.clone(), &self.ns);
112 crate::env::apply::apply_value(&self.callee, Vec::new(), &mut env)
113 .map_err(|e| format!("{e}"))
114 }
115}
116
117pub fn make_lazy_seq_from_fn(
130 f_val: &Value,
131 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
132 ns: std::sync::Arc<str>,
133) -> EvalResult {
134 let unwrapped = f_val.unwrap_meta();
135 if let Value::Fn(g) = unwrapped {
136 let thunk = ClosureThunk {
137 f: g.get().clone(),
138 globals,
139 ns,
140 };
141 return Ok(Value::LazySeq(GcPtr::new(LazySeq::new(Box::new(thunk)))));
142 }
143 if unwrapped.type_name() != "fn" {
146 return Err(EvalError::Runtime(format!(
147 "make-lazy-seq requires a fn, got {}",
148 unwrapped.type_name(),
149 )));
150 }
151 let thunk = CallableValueThunk {
152 callee: unwrapped.clone(),
153 globals,
154 ns,
155 };
156 Ok(Value::LazySeq(GcPtr::new(LazySeq::new(Box::new(thunk)))))
157}
158
159impl cljrs_gc::Trace for ClosureThunk {
160 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
161 self.f.trace(visitor);
162 }
163}
164
165impl Thunk for ClosureThunk {
166 fn force(&self) -> Result<Value, String> {
167 let _closed_root = crate::env::gc_roots::root_values(&self.f.closed_over_vals);
171 let mut env = Env::with_closure(self.globals.clone(), &self.ns, &self.f);
172 call_cljrs_fn(&self.f, &[], &mut env).map_err(|e| format!("{e}"))
173 }
174}
175
176pub fn eval_call(func_form: &Form, arg_forms: &[Form], env: &mut Env) -> EvalResult {
184 if let FormKind::Symbol(s) = &func_form.kind
186 && let Some(method) = s.strip_prefix('.')
187 && !method.is_empty()
188 && method != "."
189 {
190 return eval_method_call(method, arg_forms, env);
191 }
192
193 let callee = eval(func_form, env)?;
195
196 let _callee_root = crate::env::gc_roots::root_value(&callee);
198
199 if let Value::Macro(mfn) = &callee {
201 let expanded = macro_apply(mfn.get(), func_form, arg_forms, env)?;
202 return eval(&expanded, env);
203 }
204
205 if let Value::NativeFunction(nf) = &callee {
207 crate::env::policy::check_native(&nf.get().name)?;
208 match nf.get().name.as_ref() {
209 "apply" => return handle_apply_call(arg_forms, env),
210 "atom" => return handle_atom_call(arg_forms, env),
211 "reset!" => return handle_reset_bang(arg_forms, env),
212 "swap!" => return handle_swap_call(arg_forms, env),
213 "volatile!" => return handle_volatile(arg_forms, env),
214 "vreset!" => return handle_vreset(arg_forms, env),
215 "agent" => return handle_agent_call(arg_forms, env),
216 "make-lazy-seq" => return handle_make_lazy_seq(arg_forms, env),
217 "make-delay" => return handle_make_delay(arg_forms, env),
218 "vswap!" => return handle_vswap(arg_forms, env),
219 "send" | "send-off" => return handle_send(arg_forms, env),
220 "with-bindings*" => return handle_with_bindings(arg_forms, env),
221 "alter-var-root" => return handle_alter_var_root(arg_forms, env),
222 "vary-meta" => return handle_vary_meta(arg_forms, env),
223 "find-ns" | "the-ns" => return handle_find_ns(arg_forms, env),
224 "ns-interns" | "ns-publics" => return handle_ns_interns(arg_forms, env),
225 "ns-refers" => return handle_ns_refers(arg_forms, env),
226 "ns-map" => return handle_ns_map(arg_forms, env),
227 "all-ns" => return handle_all_ns(arg_forms, env),
228 "create-ns" => return handle_create_ns(arg_forms, env),
229 "ns-aliases" => return handle_ns_aliases(arg_forms, env),
230 "remove-ns" => return handle_remove_ns(arg_forms, env),
231 "alter-meta!" => return handle_alter_meta(arg_forms, env),
232 "ns-resolve" => return handle_ns_resolve(arg_forms, env),
233 "resolve" => return handle_resolve(arg_forms, env),
234 "intern" => return handle_intern(arg_forms, env),
235 "bound-fn*" => return handle_bound_fn_star(arg_forms, env),
236 _ => {}
237 }
238 }
239
240 let mut args: Vec<Value> = Vec::with_capacity(arg_forms.len());
243 for f in arg_forms {
244 let _args_root = crate::env::gc_roots::root_values(&args);
246 args.push(eval(f, env)?);
247 }
248
249 if let Value::Fn(f) = &callee {
254 if let Some(fut) = crate::env::apply::dispatch_if_async(&callee, &args, env) {
257 return Ok(fut);
258 }
259 let _args_root = crate::env::gc_roots::root_values(&args);
260 crate::env::gc_roots::gc_safepoint(env);
261 return env.call_cljrs_fn(f.get(), &args);
262 }
263
264 crate::env::apply::apply_value(&callee, args, env)
265}
266
267fn eval_method_call(method: &str, arg_forms: &[Form], env: &mut Env) -> EvalResult {
277 if arg_forms.is_empty() {
278 return Err(EvalError::Runtime(format!(
279 ".{method} requires a target object"
280 )));
281 }
282 let target = eval(&arg_forms[0], env)?;
283 let args: Vec<Value> = arg_forms[1..]
284 .iter()
285 .map(|f| eval(f, env))
286 .collect::<EvalResult<_>>()?;
287
288 dispatch_method(method, &target, &args)
289}
290
291pub fn dispatch_method(method: &str, target: &Value, args: &[Value]) -> EvalResult {
297 match target {
298 Value::Str(s) => dispatch_string_method(method, s.get(), args),
299 Value::Vector(v) => dispatch_vector_method(method, v, args),
300 Value::List(_) | Value::Cons(_) | Value::LazySeq(_) => {
301 dispatch_seq_method(method, target, args)
302 }
303 _ => Err(EvalError::Runtime(format!(
304 ".{method} not supported on type {}",
305 target.type_name()
306 ))),
307 }
308}
309
310fn dispatch_string_method(method: &str, s: &str, args: &[Value]) -> EvalResult {
311 match method {
312 "indexOf" => {
313 let needle = match args.first() {
314 Some(Value::Str(s)) => s.get().to_string(),
315 Some(Value::Char(c)) => c.to_string(),
316 Some(v) => {
317 return Err(EvalError::Runtime(format!(
318 ".indexOf expects string or char argument, got {}",
319 v.type_name()
320 )));
321 }
322 None => return Err(EvalError::Runtime(".indexOf requires an argument".into())),
323 };
324 match s.find(&needle) {
325 Some(pos) => Ok(Value::Long(pos as i64)),
326 None => Ok(Value::Long(-1)),
327 }
328 }
329 "lastIndexOf" => {
330 let needle = match args.first() {
331 Some(Value::Str(s)) => s.get().to_string(),
332 Some(Value::Char(c)) => c.to_string(),
333 _ => {
334 return Err(EvalError::Runtime(
335 ".lastIndexOf requires a string or char argument".into(),
336 ));
337 }
338 };
339 match s.rfind(&needle) {
340 Some(pos) => Ok(Value::Long(pos as i64)),
341 None => Ok(Value::Long(-1)),
342 }
343 }
344 "startsWith" => {
345 let prefix = require_str_arg(args, ".startsWith")?;
346 Ok(Value::Bool(s.starts_with(&prefix)))
347 }
348 "endsWith" => {
349 let suffix = require_str_arg(args, ".endsWith")?;
350 Ok(Value::Bool(s.ends_with(&suffix)))
351 }
352 "contains" => {
353 let sub = require_str_arg(args, ".contains")?;
354 Ok(Value::Bool(s.contains(&sub)))
355 }
356 "length" => Ok(Value::Long(s.len() as i64)),
357 "isEmpty" => Ok(Value::Bool(s.is_empty())),
358 "charAt" => {
359 let idx = require_long_arg(args, ".charAt")? as usize;
360 s.chars()
361 .nth(idx)
362 .map(Value::Char)
363 .ok_or_else(|| EvalError::Runtime(format!(".charAt index {idx} out of bounds")))
364 }
365 "substring" => {
366 let start = require_long_arg(args, ".substring")? as usize;
367 let end = args
368 .get(1)
369 .map(|v| match v {
370 Value::Long(n) => Ok(*n as usize),
371 _ => Err(EvalError::Runtime(
372 ".substring end must be an integer".into(),
373 )),
374 })
375 .transpose()?;
376 let result = match end {
377 Some(e) => &s[start..e.min(s.len())],
378 None => &s[start..],
379 };
380 Ok(Value::Str(GcPtr::new(result.to_string())))
381 }
382 "toUpperCase" => Ok(Value::Str(GcPtr::new(s.to_uppercase()))),
383 "toLowerCase" => Ok(Value::Str(GcPtr::new(s.to_lowercase()))),
384 "trim" => Ok(Value::Str(GcPtr::new(s.trim().to_string()))),
385 "replace" => {
386 let from = require_str_arg(args, ".replace")?;
387 let to = match args.get(1) {
388 Some(Value::Str(s)) => s.get().to_string(),
389 Some(Value::Char(c)) => c.to_string(),
390 _ => {
391 return Err(EvalError::Runtime(
392 ".replace requires two string arguments".into(),
393 ));
394 }
395 };
396 Ok(Value::Str(GcPtr::new(s.replace(&from, &to))))
397 }
398 "split" => {
399 let sep = require_str_arg(args, ".split")?;
400 let parts: Vec<Value> = s
401 .split(&sep)
402 .map(|p| Value::Str(GcPtr::new(p.to_string())))
403 .collect();
404 Ok(Value::Vector(GcPtr::new(
405 cljrs_value::PersistentVector::from_iter(parts),
406 )))
407 }
408 _ => Err(EvalError::Runtime(format!(
409 ".{method} not supported on String"
410 ))),
411 }
412}
413
414fn dispatch_vector_method(
415 method: &str,
416 v: &GcPtr<cljrs_value::PersistentVector>,
417 args: &[Value],
418) -> EvalResult {
419 match method {
420 "indexOf" => {
421 let needle = args
422 .first()
423 .ok_or_else(|| EvalError::Runtime(".indexOf requires an argument".into()))?;
424 for (i, item) in v.get().iter().enumerate() {
425 if item == needle {
426 return Ok(Value::Long(i as i64));
427 }
428 }
429 Ok(Value::Long(-1))
430 }
431 "size" | "count" => Ok(Value::Long(v.get().count() as i64)),
432 _ => Err(EvalError::Runtime(format!(
433 ".{method} not supported on Vector"
434 ))),
435 }
436}
437
438fn dispatch_seq_method(method: &str, target: &Value, args: &[Value]) -> EvalResult {
439 match method {
440 "indexOf" => {
441 let needle = args
442 .first()
443 .ok_or_else(|| EvalError::Runtime(".indexOf requires an argument".into()))?;
444 let items = crate::interp::destructure::value_to_seq_vec(target);
445 for (i, item) in items.iter().enumerate() {
446 if item == needle {
447 return Ok(Value::Long(i as i64));
448 }
449 }
450 Ok(Value::Long(-1))
451 }
452 _ => Err(EvalError::Runtime(format!(
453 ".{method} not supported on {}",
454 target.type_name()
455 ))),
456 }
457}
458
459fn require_str_arg(args: &[Value], method: &str) -> Result<String, EvalError> {
460 match args.first() {
461 Some(Value::Str(s)) => Ok(s.get().to_string()),
462 Some(Value::Char(c)) => Ok(c.to_string()),
463 _ => Err(EvalError::Runtime(format!(
464 "{method} requires a string argument"
465 ))),
466 }
467}
468
469fn require_long_arg(args: &[Value], method: &str) -> Result<i64, EvalError> {
470 match args.first() {
471 Some(Value::Long(n)) => Ok(*n),
472 _ => Err(EvalError::Runtime(format!(
473 "{method} requires an integer argument"
474 ))),
475 }
476}
477
478pub fn resolve_type_tag(sym: &str) -> Arc<str> {
481 Arc::from(sym)
482}
483
484pub fn call_cljrs_fn(f: &CljxFn, args: &[Value], caller_env: &mut Env) -> EvalResult {
486 let arity = select_arity(f, args.len())?;
487
488 let _caller_root = crate::env::gc_roots::push_env_root(caller_env);
491
492 let mut env = Env::with_closure(caller_env.globals.clone(), &f.defining_ns, f);
495
496 let mut current_args = Vec::from(args);
497 loop {
498 let _args_root = crate::env::gc_roots::root_values(¤t_args);
501
502 crate::env::gc_roots::gc_safepoint(&env);
504
505 env.push_frame();
506
507 #[cfg(not(feature = "no-gc"))]
517 let _call_frame = cljrs_gc::push_alloc_frame();
518
519 bind_fn_params(arity, ¤t_args, &mut env)?;
521
522 if let Some(ref name) = f.name {
525 let self_val = if let Some(ref p) = f.self_ptr {
526 Value::Fn(p.clone())
527 } else {
528 Value::Fn(GcPtr::new(f.clone()))
529 };
530 env.bind(name.clone(), self_val);
531 }
532
533 #[cfg(not(feature = "no-gc"))]
538 let result = eval_body_recur_fn(&arity.body, &mut env);
539 #[cfg(feature = "no-gc")]
540 let result = {
541 let mut scratch = cljrs_gc::alloc_ctx::ScratchGuard::new();
542 eval_body_with_scratch(&arity.body, &mut scratch, &mut env)
544 };
545 env.pop_frame();
546 match result {
550 Ok(v) => return Ok(v),
551 Err(EvalError::Recur(new_args)) => {
552 if arity.rest_param.is_some() {
557 let n = arity.params.len();
558 if new_args.len() == n + 1 {
559 let mut flat = new_args[..n].to_vec();
560 let rest_val = &new_args[n];
562 match rest_val {
563 Value::Nil => {} _ => {
565 let rest_items = value_to_seq_vec(rest_val);
566 flat.extend(rest_items);
567 }
568 }
569 current_args = flat;
570 } else {
571 current_args = new_args;
572 }
573 } else {
574 current_args = new_args;
575 }
576 }
577 Err(e) => return Err(e),
578 }
579 }
580}
581
582pub fn bind_fn_params(arity: &CljxFnArity, args: &[Value], env: &mut Env) -> EvalResult<()> {
584 let n = arity.params.len();
585 for (i, name) in arity.params.iter().enumerate() {
587 let val = args.get(i).cloned().unwrap_or(Value::Nil);
588 env.bind(name.clone(), val);
589 }
590 if let Some(ref rest) = arity.rest_param {
592 let rest_items = args[n..].to_vec();
593 let rest_val = if rest_items.is_empty() {
594 Value::Nil
595 } else {
596 Value::List(GcPtr::new(PersistentList::from_iter(rest_items)))
597 };
598 env.bind(rest.clone(), rest_val.clone());
599 if let Some(ref pattern) = arity.destructure_rest {
601 let destructure_val = if matches!(pattern.kind, FormKind::Map(_)) {
605 let items = value_to_seq_vec(&rest_val);
606 Value::Map(MapValue::from_flat_entries(items))
607 } else {
608 rest_val
609 };
610 crate::interp::destructure::bind_pattern(pattern, destructure_val, env)?;
611 }
612 }
613 for (idx, pattern) in &arity.destructure_params {
615 let val = args.get(*idx).cloned().unwrap_or(Value::Nil);
616 crate::interp::destructure::bind_pattern(pattern, val, env)?;
617 }
618 Ok(())
619}
620
621#[cfg(not(feature = "no-gc"))]
623fn eval_body_recur_fn(body: &[cljrs_reader::Form], env: &mut Env) -> EvalResult {
624 let mut result = Value::Nil;
625 for form in body {
626 result = eval(form, env)?;
627 }
628 Ok(result)
629}
630
631#[cfg(feature = "no-gc")]
635fn eval_body_with_scratch(
636 body: &[cljrs_reader::Form],
637 scratch: &mut cljrs_gc::alloc_ctx::ScratchGuard,
638 env: &mut Env,
639) -> EvalResult {
640 if body.is_empty() {
641 scratch.pop_for_return();
642 return Ok(Value::Nil);
643 }
644 for form in &body[..body.len() - 1] {
646 eval(form, env)?;
647 }
648 scratch.pop_for_return();
650 eval(&body[body.len() - 1], env)
651}
652
653pub fn select_arity(f: &CljxFn, argc: usize) -> EvalResult<&CljxFnArity> {
655 let name = f.name.as_deref().unwrap_or("fn");
656 for arity in &f.arities {
658 if arity.rest_param.is_none() && arity.params.len() == argc {
659 return Ok(arity);
660 }
661 }
662 for arity in &f.arities {
664 if arity.rest_param.is_some() && argc >= arity.params.len() {
665 return Ok(arity);
666 }
667 }
668 let expected: Vec<String> = f
670 .arities
671 .iter()
672 .map(|a| {
673 if a.rest_param.is_some() {
674 format!("{}+", a.params.len())
675 } else {
676 a.params.len().to_string()
677 }
678 })
679 .collect();
680 Err(EvalError::Arity {
681 name: name.to_string(),
682 expected: expected.join(" or "),
683 got: argc,
684 })
685}
686
687fn macro_apply(
694 mfn: &CljxFn,
695 func_form: &Form,
696 arg_forms: &[Form],
697 env: &mut Env,
698) -> EvalResult<Form> {
699 let resolved_args: Vec<Form> = arg_forms
704 .iter()
705 .map(|f| crate::builtins::form::resolve_auto_forms(f, env))
706 .collect::<EvalResult<Vec<Form>>>()?;
707
708 let form_val = {
710 let mut items = vec![form_to_value(func_form)?];
711 for f in &resolved_args {
712 items.push(form_to_value(f)?);
713 }
714 Value::List(GcPtr::new(PersistentList::from_iter(items)))
715 };
716
717 let env_val = {
719 let (names, vals) = env.all_local_bindings();
720 let mut m = MapValue::empty();
721 for (name, val) in names.iter().zip(vals.iter()) {
722 m = m.assoc(Value::symbol(Symbol::simple(name.as_ref())), val.clone());
723 }
724 Value::Map(m)
725 };
726
727 let mut args = vec![form_val, env_val];
729 for f in &resolved_args {
730 args.push(form_to_value(f)?);
731 }
732
733 let expanded_val = call_cljrs_fn(mfn, args.as_ref(), env)?;
734 let dummy_span = cljrs_types::span::Span::new(Arc::new("<macro>".to_string()), 0, 0, 1, 1);
735 crate::interp::macros::value_to_form(&expanded_val, dummy_span)
736}
737
738fn handle_apply_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
740 let mut evaled: Vec<Value> = Vec::with_capacity(arg_forms.len());
741 for f in arg_forms {
742 let _root = crate::env::gc_roots::root_values(&evaled);
743 evaled.push(eval(f, env)?);
744 }
745
746 if evaled.len() < 2 {
747 return Err(EvalError::Arity {
748 name: "apply".into(),
749 expected: "2+".into(),
750 got: evaled.len(),
751 });
752 }
753
754 let f = evaled.remove(0);
755 let last = evaled.pop().unwrap();
756 let _f_root = crate::env::gc_roots::root_value(&f);
758 let _last_root = crate::env::gc_roots::root_value(&last);
759 let _evaled_root = crate::env::gc_roots::root_values(&evaled);
760 let spread = value_to_seq_vec(&last);
762 evaled.extend(spread);
763 crate::env::apply::apply_value(&f, evaled, env)
764}
765
766pub fn handle_make_lazy_seq(arg_forms: &[Form], env: &mut Env) -> EvalResult {
768 if arg_forms.len() != 1 {
769 return Err(EvalError::Arity {
770 name: "make-lazy-seq".into(),
771 expected: "1".into(),
772 got: arg_forms.len(),
773 });
774 }
775 let f_val = eval(&arg_forms[0], env)?;
776 let f = match f_val {
777 Value::Fn(f) => f.get().clone(),
778 other => {
779 return Err(EvalError::Runtime(format!(
780 "make-lazy-seq requires a fn, got {}",
781 other.type_name()
782 )));
783 }
784 };
785 let thunk = ClosureThunk {
786 f,
787 globals: env.globals.clone(),
788 ns: env.current_ns.clone(),
789 };
790 Ok(Value::LazySeq(GcPtr::new(LazySeq::new(Box::new(thunk)))))
791}
792
793fn handle_make_delay(arg_forms: &[Form], env: &mut Env) -> EvalResult {
795 if arg_forms.len() != 1 {
796 return Err(EvalError::Arity {
797 name: "make-delay".into(),
798 expected: "1".into(),
799 got: arg_forms.len(),
800 });
801 }
802 let f_val = eval(&arg_forms[0], env)?;
803 let f = match f_val {
804 Value::Fn(f) => f.get().clone(),
805 other => {
806 return Err(EvalError::Runtime(format!(
807 "make-delay requires a fn, got {}",
808 other.type_name()
809 )));
810 }
811 };
812 let thunk = ClosureThunk {
813 f,
814 globals: env.globals.clone(),
815 ns: env.current_ns.clone(),
816 };
817 Ok(Value::Delay(GcPtr::new(Delay::new(Box::new(thunk)))))
818}
819
820fn handle_vswap(arg_forms: &[Form], env: &mut Env) -> EvalResult {
822 if arg_forms.len() < 2 {
823 return Err(EvalError::Arity {
824 name: "vswap!".into(),
825 expected: "2+".into(),
826 got: arg_forms.len(),
827 });
828 }
829 let vol_val = eval(&arg_forms[0], env)?;
830 let f = eval(&arg_forms[1], env)?;
831 let extra: Vec<Value> = arg_forms[2..]
832 .iter()
833 .map(|a| eval(a, env))
834 .collect::<EvalResult<_>>()?;
835
836 match vol_val {
837 Value::Volatile(v) => {
838 let cur = v.get().deref();
839 let mut call_args = vec![cur];
840 call_args.extend(extra);
841 #[cfg(feature = "no-gc")]
844 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
845 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
846 v.get().reset(new_val.clone());
847 Ok(new_val)
848 }
849 other => Err(EvalError::Runtime(format!(
850 "vswap!: expected volatile, got {}",
851 other.type_name()
852 ))),
853 }
854}
855
856fn handle_volatile(arg_forms: &[Form], env: &mut Env) -> EvalResult {
860 if arg_forms.is_empty() {
861 return Err(EvalError::Arity {
862 name: "volatile!".into(),
863 expected: "1".into(),
864 got: 0,
865 });
866 }
867 #[cfg(feature = "no-gc")]
870 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
871 let initial = eval(&arg_forms[0], env)?;
872 Ok(Value::Volatile(GcPtr::new(Volatile::new(initial))))
873}
874
875fn handle_vreset(arg_forms: &[Form], env: &mut Env) -> EvalResult {
879 if arg_forms.len() < 2 {
880 return Err(EvalError::Arity {
881 name: "vreset!".into(),
882 expected: "2".into(),
883 got: arg_forms.len(),
884 });
885 }
886 let vol_val = eval(&arg_forms[0], env)?;
887 #[cfg(feature = "no-gc")]
890 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
891 let new_val = eval(&arg_forms[1], env)?;
892 match &vol_val {
893 Value::Volatile(v) => {
894 v.get().reset(new_val.clone());
895 Ok(new_val)
896 }
897 other => Err(EvalError::Runtime(format!(
898 "vreset!: expected volatile, got {}",
899 other.type_name()
900 ))),
901 }
902}
903
904fn handle_agent_call(_arg_forms: &[Form], _env: &mut Env) -> EvalResult {
908 Err(EvalError::Runtime("agent is not yet implemented".into()))
909}
910
911fn handle_send(_arg_forms: &[Form], _env: &mut Env) -> EvalResult {
913 Err(EvalError::Runtime(
914 "send/send-off: agents are not yet implemented".into(),
915 ))
916}
917
918fn handle_atom_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
922 if arg_forms.is_empty() {
923 return Err(EvalError::Arity {
924 name: "atom".into(),
925 expected: "1+".into(),
926 got: 0,
927 });
928 }
929 #[cfg(feature = "no-gc")]
932 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
933 let initial = eval(&arg_forms[0], env)?;
934
935 let options: Vec<Value> = arg_forms[1..]
937 .iter()
938 .map(|f| eval(f, env))
939 .collect::<EvalResult<_>>()?;
940
941 let mut meta_opt: Option<Value> = None;
942 let mut validator_opt: Option<Value> = None;
943 let mut i = 0;
944 while i + 1 < options.len() {
945 match &options[i] {
946 Value::Keyword(k) if k.get().name.as_ref() == "meta" => {
947 meta_opt = Some(options[i + 1].clone());
948 i += 2;
949 }
950 Value::Keyword(k) if k.get().name.as_ref() == "validator" => {
951 let vf = options[i + 1].clone();
952 validator_opt = if vf == Value::Nil { None } else { Some(vf) };
953 i += 2;
954 }
955 _ => {
956 i += 2;
957 }
958 }
959 }
960
961 if let Some(ref m) = meta_opt
963 && !matches!(m, Value::Nil | Value::Map(_))
964 {
965 return Err(EvalError::Thrown(Value::string(
966 "Atom metadata must be a map or nil".to_string(),
967 )));
968 }
969
970 if let Some(ref vf) = validator_opt {
972 let result = crate::env::apply::apply_value(vf, vec![initial.clone()], env)?;
973 if result == Value::Nil || result == Value::Bool(false) {
974 return Err(EvalError::Thrown(Value::string(
975 "Invalid initial value for atom".to_string(),
976 )));
977 }
978 }
979
980 let atom = GcPtr::new(Atom::new(initial));
981 if let Some(m) = meta_opt {
982 atom.get()
983 .set_meta(if m == Value::Nil { None } else { Some(m) });
984 }
985 if let Some(vf) = validator_opt {
986 atom.get().set_validator(Some(vf));
987 }
988 Ok(Value::Atom(atom))
989}
990
991fn shared_atom_reset(sa: &Arc<cljrs_value::SharedAtom>, new_val: Value) -> EvalResult {
1003 let promoted = cljrs_value::promote(&new_val).map_err(|e| EvalError::Runtime(e.to_string()))?;
1004 sa.reset(promoted);
1005 Ok(new_val)
1006}
1007
1008fn shared_atom_swap(
1013 sa: &Arc<cljrs_value::SharedAtom>,
1014 f: &Value,
1015 extra: Vec<Value>,
1016 env: &mut Env,
1017) -> EvalResult {
1018 loop {
1019 let cur = sa.deref_val();
1020 let old_val = cljrs_value::demote(&cur);
1021 let mut call_args = Vec::with_capacity(1 + extra.len());
1022 call_args.push(old_val);
1023 call_args.extend(extra.iter().cloned());
1024 let new_val = crate::env::apply::apply_value(f, call_args, env)?;
1025 let promoted =
1026 cljrs_value::promote(&new_val).map_err(|e| EvalError::Runtime(e.to_string()))?;
1027 if sa.compare_and_set(&cur, promoted) {
1028 return Ok(new_val);
1029 }
1030 }
1032}
1033
1034fn handle_reset_bang(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1037 if arg_forms.len() < 2 {
1038 return Err(EvalError::Arity {
1039 name: "reset!".into(),
1040 expected: "2".into(),
1041 got: arg_forms.len(),
1042 });
1043 }
1044 let atom_val = eval(&arg_forms[0], env)?;
1045 #[cfg(feature = "no-gc")]
1048 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1049 let new_val = eval(&arg_forms[1], env)?;
1050
1051 let atom = match &atom_val {
1052 Value::Atom(a) => a.clone(),
1053 Value::SharedAtom(sa) => return shared_atom_reset(sa, new_val),
1054 v => {
1055 return Err(EvalError::Runtime(format!(
1056 "reset! requires an atom, got {}",
1057 v.type_name()
1058 )));
1059 }
1060 };
1061
1062 validate_atom_value(&atom, &new_val, env)?;
1063 let old_val = atom.get().deref();
1064 atom.get().reset(new_val.clone());
1065 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1066 check_watch_error()?;
1067 Ok(new_val)
1068}
1069
1070fn validate_atom_value(atom: &GcPtr<Atom>, new_val: &Value, env: &mut Env) -> EvalResult<()> {
1072 if let Some(vf) = atom.get().get_validator() {
1073 let result = crate::env::apply::apply_value(&vf, vec![new_val.clone()], env)?;
1074 if result == Value::Nil || result == Value::Bool(false) {
1075 return Err(EvalError::Thrown(Value::string(
1076 "Invalid value for atom".to_string(),
1077 )));
1078 }
1079 }
1080 Ok(())
1081}
1082
1083fn handle_swap_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1086 let mut evaled: Vec<Value> = arg_forms
1087 .iter()
1088 .map(|f| eval(f, env))
1089 .collect::<EvalResult<_>>()?;
1090
1091 if evaled.len() < 2 {
1092 return Err(EvalError::Arity {
1093 name: "swap!".into(),
1094 expected: "2+".into(),
1095 got: evaled.len(),
1096 });
1097 }
1098
1099 let atom_val = evaled.remove(0);
1100 let f = evaled.remove(0);
1101
1102 let atom = match &atom_val {
1103 Value::Atom(a) => a.clone(),
1104 Value::SharedAtom(sa) => return shared_atom_swap(sa, &f, evaled, env),
1105 v => {
1106 return Err(EvalError::Runtime(format!(
1107 "swap! requires an atom, got {}",
1108 v.type_name()
1109 )));
1110 }
1111 };
1112
1113 let old_val = atom.get().deref();
1114 let mut args = vec![old_val.clone()];
1115 args.extend(evaled);
1116 #[cfg(feature = "no-gc")]
1119 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1120 let new_val = crate::env::apply::apply_value(&f, args, env)?;
1121 validate_atom_value(&atom, &new_val, env)?;
1122 atom.get().reset(new_val.clone());
1123 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1124 check_watch_error()?;
1125 Ok(new_val)
1126}
1127
1128fn handle_with_bindings(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1133 if arg_forms.len() < 2 {
1134 return Err(EvalError::Arity {
1135 name: "with-bindings*".into(),
1136 expected: "2".into(),
1137 got: arg_forms.len(),
1138 });
1139 }
1140 let map_val = eval(&arg_forms[0], env)?;
1141 let func_val = eval(&arg_forms[1], env)?;
1142
1143 let mut frame: HashMap<usize, Value> = HashMap::new();
1144 if let Value::Map(m) = &map_val {
1145 m.for_each(|k, v| {
1146 if let Value::Var(vp) = k {
1147 frame.insert(crate::env::dynamics::var_key_of(vp), v.clone());
1148 }
1149 });
1151 } else {
1152 return Err(EvalError::Runtime(
1153 "with-bindings*: first arg must be a map".into(),
1154 ));
1155 }
1156
1157 let _guard = crate::env::dynamics::push_frame(frame);
1158 crate::env::apply::apply_value(&func_val, vec![], env)
1159}
1160
1161fn handle_alter_var_root(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1165 if arg_forms.len() < 2 {
1166 return Err(EvalError::Arity {
1167 name: "alter-var-root".into(),
1168 expected: "2+".into(),
1169 got: arg_forms.len(),
1170 });
1171 }
1172 let var_val = eval(&arg_forms[0], env)?;
1173 let f = eval(&arg_forms[1], env)?;
1174 let extra: Vec<Value> = arg_forms[2..]
1175 .iter()
1176 .map(|form| eval(form, env))
1177 .collect::<EvalResult<_>>()?;
1178
1179 let vp = match &var_val {
1180 Value::Var(vp) => vp.clone(),
1181 v => {
1182 return Err(EvalError::Runtime(format!(
1183 "alter-var-root: expected var, got {}",
1184 v.type_name()
1185 )));
1186 }
1187 };
1188 let old_val = vp.get().deref().unwrap_or(Value::Nil);
1189 let mut call_args = vec![old_val.clone()];
1190 call_args.extend(extra);
1191 #[cfg(feature = "no-gc")]
1194 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1195 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1196 vp.get().bind(new_val.clone());
1197 fire_watches(&vp.get().watches, &var_val, &old_val, &new_val, env);
1198 check_watch_error()?;
1199 Ok(new_val)
1200}
1201
1202fn handle_vary_meta(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1206 if arg_forms.len() < 2 {
1207 return Err(EvalError::Arity {
1208 name: "vary-meta".into(),
1209 expected: "2+".into(),
1210 got: arg_forms.len(),
1211 });
1212 }
1213 let obj = eval(&arg_forms[0], env)?;
1214 let f = eval(&arg_forms[1], env)?;
1215 let extra: Vec<Value> = arg_forms[2..]
1216 .iter()
1217 .map(|form| eval(form, env))
1218 .collect::<EvalResult<_>>()?;
1219
1220 let current_meta = match &obj {
1221 Value::Var(vp) => vp.get().get_meta().unwrap_or(Value::Nil),
1222 _ => Value::Nil,
1223 };
1224 let mut call_args = vec![current_meta];
1225 call_args.extend(extra);
1226 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1227 if let Value::Var(vp) = &obj {
1228 vp.get().set_meta(new_meta);
1229 }
1230 Ok(obj)
1231}
1232
1233pub fn eval_reset_bang(args: Vec<Value>, env: &mut Env) -> EvalResult {
1241 if args.len() < 2 {
1242 return Err(EvalError::Arity {
1243 name: "reset!".into(),
1244 expected: "2".into(),
1245 got: args.len(),
1246 });
1247 }
1248 let atom_val = args[0].clone();
1249 let new_val = args[1].clone();
1250 let atom = match &atom_val {
1251 Value::Atom(a) => a.clone(),
1252 Value::SharedAtom(sa) => return shared_atom_reset(sa, new_val),
1253 v => {
1254 return Err(EvalError::Runtime(format!(
1255 "reset! requires an atom, got {}",
1256 v.type_name()
1257 )));
1258 }
1259 };
1260 #[cfg(feature = "no-gc")]
1261 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1262 validate_atom_value(&atom, &new_val, env)?;
1263 let old_val = atom.get().deref();
1264 atom.get().reset(new_val.clone());
1265 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1266 check_watch_error()?;
1267 Ok(new_val)
1268}
1269
1270pub fn eval_swap_bang(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1272 if args.len() < 2 {
1273 return Err(EvalError::Arity {
1274 name: "swap!".into(),
1275 expected: "2+".into(),
1276 got: args.len(),
1277 });
1278 }
1279 let atom_val = args.remove(0);
1280 let f = args.remove(0);
1281 let atom = match &atom_val {
1282 Value::Atom(a) => a.clone(),
1283 Value::SharedAtom(sa) => return shared_atom_swap(sa, &f, args, env),
1284 v => {
1285 return Err(EvalError::Runtime(format!(
1286 "swap! requires an atom, got {}",
1287 v.type_name()
1288 )));
1289 }
1290 };
1291 let old_val = atom.get().deref();
1292 let mut call_args = vec![old_val.clone()];
1293 call_args.extend(args);
1294 #[cfg(feature = "no-gc")]
1295 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1296 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1297 validate_atom_value(&atom, &new_val, env)?;
1298 atom.get().reset(new_val.clone());
1299 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1300 check_watch_error()?;
1301 Ok(new_val)
1302}
1303
1304pub fn eval_volatile(args: Vec<Value>) -> EvalResult {
1306 if args.is_empty() {
1307 return Err(EvalError::Arity {
1308 name: "volatile!".into(),
1309 expected: "1".into(),
1310 got: 0,
1311 });
1312 }
1313 #[cfg(feature = "no-gc")]
1314 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1315 Ok(Value::Volatile(GcPtr::new(Volatile::new(
1316 args.into_iter().next().unwrap(),
1317 ))))
1318}
1319
1320pub fn eval_vreset_bang(args: Vec<Value>) -> EvalResult {
1322 if args.len() < 2 {
1323 return Err(EvalError::Arity {
1324 name: "vreset!".into(),
1325 expected: "2".into(),
1326 got: args.len(),
1327 });
1328 }
1329 #[cfg(feature = "no-gc")]
1330 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1331 let new_val = args[1].clone();
1332 match &args[0] {
1333 Value::Volatile(v) => {
1334 v.get().reset(new_val.clone());
1335 Ok(new_val)
1336 }
1337 other => Err(EvalError::Runtime(format!(
1338 "vreset!: expected volatile, got {}",
1339 other.type_name()
1340 ))),
1341 }
1342}
1343
1344pub fn eval_vswap_bang(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1346 if args.len() < 2 {
1347 return Err(EvalError::Arity {
1348 name: "vswap!".into(),
1349 expected: "2+".into(),
1350 got: args.len(),
1351 });
1352 }
1353 let vol_val = args.remove(0);
1354 let f = args.remove(0);
1355 match vol_val {
1356 Value::Volatile(v) => {
1357 let cur = v.get().deref();
1358 let mut call_args = vec![cur];
1359 call_args.extend(args);
1360 #[cfg(feature = "no-gc")]
1361 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1362 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1363 v.get().reset(new_val.clone());
1364 Ok(new_val)
1365 }
1366 other => Err(EvalError::Runtime(format!(
1367 "vswap!: expected volatile, got {}",
1368 other.type_name()
1369 ))),
1370 }
1371}
1372
1373pub fn make_delay_from_fn(
1378 f_val: &Value,
1379 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
1380 ns: std::sync::Arc<str>,
1381) -> EvalResult {
1382 let f = match f_val {
1383 Value::Fn(f) => f.get().clone(),
1384 other => {
1385 return Err(EvalError::Runtime(format!(
1386 "make-delay requires a fn, got {}",
1387 other.type_name()
1388 )));
1389 }
1390 };
1391 let thunk = ClosureThunk { f, globals, ns };
1392 Ok(Value::Delay(GcPtr::new(Delay::new(Box::new(thunk)))))
1393}
1394
1395pub fn eval_alter_var_root(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1397 if args.len() < 2 {
1398 return Err(EvalError::Arity {
1399 name: "alter-var-root".into(),
1400 expected: "2+".into(),
1401 got: args.len(),
1402 });
1403 }
1404 let var_val = args.remove(0);
1405 let f = args.remove(0);
1406 let vp = match &var_val {
1407 Value::Var(vp) => vp.clone(),
1408 v => {
1409 return Err(EvalError::Runtime(format!(
1410 "alter-var-root: expected var, got {}",
1411 v.type_name()
1412 )));
1413 }
1414 };
1415 let old_val = vp.get().deref().unwrap_or(Value::Nil);
1416 let mut call_args = vec![old_val.clone()];
1417 call_args.extend(args);
1418 #[cfg(feature = "no-gc")]
1419 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1420 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1421 vp.get().bind(new_val.clone());
1422 fire_watches(&vp.get().watches, &var_val, &old_val, &new_val, env);
1423 check_watch_error()?;
1424 Ok(new_val)
1425}
1426
1427pub fn eval_vary_meta(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1429 if args.len() < 2 {
1430 return Err(EvalError::Arity {
1431 name: "vary-meta".into(),
1432 expected: "2+".into(),
1433 got: args.len(),
1434 });
1435 }
1436 let obj = args.remove(0);
1437 let f = args.remove(0);
1438 let current_meta = match &obj {
1439 Value::Var(vp) => vp.get().get_meta().unwrap_or(Value::Nil),
1440 _ => Value::Nil,
1441 };
1442 let mut call_args = vec![current_meta];
1443 call_args.extend(args);
1444 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1445 if let Value::Var(vp) = &obj {
1446 vp.get().set_meta(new_meta);
1447 }
1448 Ok(obj)
1449}
1450
1451pub fn eval_with_bindings_star(args: Vec<Value>, env: &mut Env) -> EvalResult {
1453 if args.len() < 2 {
1454 return Err(EvalError::Arity {
1455 name: "with-bindings*".into(),
1456 expected: "2".into(),
1457 got: args.len(),
1458 });
1459 }
1460 let mut frame: HashMap<usize, Value> = HashMap::new();
1461 if let Value::Map(m) = &args[0] {
1462 m.for_each(|k, v| {
1463 if let Value::Var(vp) = k {
1464 frame.insert(crate::env::dynamics::var_key_of(vp), v.clone());
1465 }
1466 });
1467 } else {
1468 return Err(EvalError::Runtime(
1469 "with-bindings*: first arg must be a map".into(),
1470 ));
1471 }
1472 let _guard = crate::env::dynamics::push_frame(frame);
1473 crate::env::apply::apply_value(&args[1], vec![], env)
1474}
1475
1476pub fn eval_send_to_agent(_args: Vec<Value>, _env: &mut Env) -> EvalResult {
1478 Err(EvalError::Runtime(
1479 "send/send-off: agents are not yet implemented".into(),
1480 ))
1481}
1482
1483fn ns_name_from_val(v: &Value) -> Result<String, EvalError> {
1486 match v {
1487 Value::Symbol(s) => Ok(s.get().name.as_ref().to_string()),
1488 Value::Str(s) => Ok(s.get().clone()),
1489 Value::Namespace(ns) => Ok(ns.get().name.as_ref().to_string()),
1490 Value::Keyword(k) => Ok(k.get().name.as_ref().to_string()),
1491 other => Err(EvalError::Runtime(format!(
1492 "expected symbol, string, or namespace, got {}",
1493 other.type_name()
1494 ))),
1495 }
1496}
1497
1498fn the_ns(v: &Value, env: &Env) -> Result<GcPtr<cljrs_value::Namespace>, EvalError> {
1503 if let Value::Namespace(ns) = v {
1504 return Ok(ns.clone());
1505 }
1506 let name = ns_name_from_val(v)?;
1507 let map = env.globals.namespaces.read().unwrap();
1508 match map.get(name.as_str()) {
1509 Some(ns) => Ok(ns.clone()),
1510 None => Err(EvalError::Runtime(format!("No namespace: {name} found"))),
1511 }
1512}
1513
1514fn handle_ns_interns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1517 if arg_forms.is_empty() {
1518 return Err(EvalError::Arity {
1519 name: "ns-interns".into(),
1520 expected: "1".into(),
1521 got: 0,
1522 });
1523 }
1524 let arg = eval(&arg_forms[0], env)?;
1525 let ns = the_ns(&arg, env)?;
1526 crate::builtins::builtins::builtin_ns_interns(&[Value::Namespace(ns)])
1527 .map_err(crate::env::error::value_error_to_eval_error)
1528}
1529
1530fn handle_ns_refers(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1532 if arg_forms.is_empty() {
1533 return Err(EvalError::Arity {
1534 name: "ns-refers".into(),
1535 expected: "1".into(),
1536 got: 0,
1537 });
1538 }
1539 let arg = eval(&arg_forms[0], env)?;
1540 let ns = the_ns(&arg, env)?;
1541 crate::builtins::builtins::builtin_ns_refers(&[Value::Namespace(ns)])
1542 .map_err(crate::env::error::value_error_to_eval_error)
1543}
1544
1545fn handle_ns_map(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1547 if arg_forms.is_empty() {
1548 return Err(EvalError::Arity {
1549 name: "ns-map".into(),
1550 expected: "1".into(),
1551 got: 0,
1552 });
1553 }
1554 let arg = eval(&arg_forms[0], env)?;
1555 let ns = the_ns(&arg, env)?;
1556 crate::builtins::builtins::builtin_ns_map(&[Value::Namespace(ns)])
1557 .map_err(crate::env::error::value_error_to_eval_error)
1558}
1559
1560fn handle_find_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1562 if arg_forms.is_empty() {
1563 return Err(EvalError::Arity {
1564 name: "find-ns".into(),
1565 expected: "1".into(),
1566 got: 0,
1567 });
1568 }
1569 let arg = eval(&arg_forms[0], env)?;
1570 let name = ns_name_from_val(&arg)?;
1571 let map = env.globals.namespaces.read().unwrap();
1572 match map.get(name.as_str()) {
1573 Some(ns) => Ok(Value::Namespace(ns.clone())),
1574 None => Ok(Value::Nil),
1575 }
1576}
1577
1578fn handle_all_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1580 if !arg_forms.is_empty() {
1581 let _ = eval(&arg_forms[0], env)?; }
1583 let map = env.globals.namespaces.read().unwrap();
1584 let items: Vec<Value> = map
1585 .values()
1586 .map(|ns| Value::Namespace(ns.clone()))
1587 .collect();
1588 drop(map);
1589 Ok(Value::List(cljrs_gc::GcPtr::new(
1590 cljrs_value::PersistentList::from_iter(items),
1591 )))
1592}
1593
1594fn handle_create_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1596 if arg_forms.is_empty() {
1597 return Err(EvalError::Arity {
1598 name: "create-ns".into(),
1599 expected: "1".into(),
1600 got: 0,
1601 });
1602 }
1603 let arg = eval(&arg_forms[0], env)?;
1604 let name = ns_name_from_val(&arg)?;
1605 let ns = env.globals.get_or_create_ns(&name);
1606 Ok(Value::Namespace(ns))
1607}
1608
1609fn handle_ns_aliases(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1611 if arg_forms.is_empty() {
1612 return Err(EvalError::Arity {
1613 name: "ns-aliases".into(),
1614 expected: "1".into(),
1615 got: 0,
1616 });
1617 }
1618 let ns_val = eval(&arg_forms[0], env)?;
1619 let ns_name = ns_name_from_val(&ns_val)?;
1620 let map = env.globals.namespaces.read().unwrap();
1621 let ns = match map.get(ns_name.as_str()) {
1622 Some(ns) => ns.clone(),
1623 None => return Ok(Value::Map(cljrs_value::MapValue::empty())),
1624 };
1625 let aliases = ns.get().aliases.lock().unwrap().clone();
1626 drop(map);
1627 let mut m = cljrs_value::MapValue::empty();
1628 for (alias, full_ns_name) in &aliases {
1629 let sym = Value::symbol(cljrs_value::Symbol::simple(alias.clone()));
1630 let nsmap = env.globals.namespaces.read().unwrap();
1631 if let Some(target_ns) = nsmap.get(full_ns_name.as_ref()) {
1632 m = m.assoc(sym, Value::Namespace(target_ns.clone()));
1633 }
1634 }
1635 Ok(Value::Map(m))
1636}
1637
1638fn handle_remove_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1640 if arg_forms.is_empty() {
1641 return Err(EvalError::Arity {
1642 name: "remove-ns".into(),
1643 expected: "1".into(),
1644 got: 0,
1645 });
1646 }
1647 let arg = eval(&arg_forms[0], env)?;
1648 let name = ns_name_from_val(&arg)?;
1649 env.globals
1650 .namespaces
1651 .write()
1652 .unwrap()
1653 .remove(name.as_str());
1654 Ok(Value::Nil)
1655}
1656
1657fn handle_alter_meta(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1659 if arg_forms.len() < 2 {
1660 return Err(EvalError::Arity {
1661 name: "alter-meta!".into(),
1662 expected: "2+".into(),
1663 got: arg_forms.len(),
1664 });
1665 }
1666 let obj = eval(&arg_forms[0], env)?;
1667 let f = eval(&arg_forms[1], env)?;
1668 let extra: Vec<Value> = arg_forms[2..]
1669 .iter()
1670 .map(|form| eval(form, env))
1671 .collect::<EvalResult<_>>()?;
1672
1673 let current_meta = match &obj {
1674 Value::Var(vp) => vp
1675 .get()
1676 .get_meta()
1677 .unwrap_or(Value::Map(cljrs_value::MapValue::empty())),
1678 _ => Value::Map(cljrs_value::MapValue::empty()),
1679 };
1680 let mut call_args = vec![current_meta];
1681 call_args.extend(extra);
1682 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1683 if let Value::Var(vp) = &obj {
1684 vp.get().set_meta(new_meta.clone());
1685 }
1686 Ok(new_meta)
1687}
1688
1689fn handle_ns_resolve(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1691 if arg_forms.len() < 2 {
1692 return Err(EvalError::Arity {
1693 name: "ns-resolve".into(),
1694 expected: "2".into(),
1695 got: arg_forms.len(),
1696 });
1697 }
1698 let ns_arg = eval(&arg_forms[0], env)?;
1699 let sym_arg = eval(&arg_forms[1], env)?;
1700 let ns_name = ns_name_from_val(&ns_arg)?;
1701 let sym_name = match &sym_arg {
1702 Value::Symbol(s) => s.get().name.as_ref().to_string(),
1703 Value::Str(s) => s.get().clone(),
1704 other => {
1705 return Err(EvalError::Runtime(format!(
1706 "ns-resolve: second arg must be symbol or string, got {}",
1707 other.type_name()
1708 )));
1709 }
1710 };
1711 match env.globals.lookup_var(&ns_name, &sym_name) {
1712 Some(var_ptr) => Ok(Value::Var(var_ptr)),
1713 None => Ok(Value::Nil),
1714 }
1715}
1716
1717fn resolve_current_ns(env: &Env) -> Arc<str> {
1721 if let Some(var) = env.globals.lookup_var("clojure.core", "*ns*") {
1722 let val = crate::env::dynamics::deref_var(&var);
1723 if let Some(Value::Namespace(ns_ptr)) = val {
1724 return ns_ptr.get().name.clone();
1725 }
1726 }
1727 env.current_ns.clone()
1728}
1729
1730fn handle_resolve(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1732 if arg_forms.len() != 1 {
1733 return Err(EvalError::Arity {
1734 name: "resolve".into(),
1735 expected: "1".into(),
1736 got: arg_forms.len(),
1737 });
1738 }
1739 let resolve_ns = resolve_current_ns(env);
1740 let sym_arg = eval(&arg_forms[0], env)?;
1741 let sym_name = match &sym_arg {
1742 Value::Symbol(s) => {
1743 let sym = s.get();
1744 if let Some(ns) = &sym.namespace {
1746 let full_ns = env
1747 .globals
1748 .resolve_alias(&resolve_ns, ns.as_ref())
1749 .unwrap_or_else(|| ns.clone());
1750 return Ok(
1751 match env.globals.lookup_var_in_ns(&full_ns, sym.name.as_ref()) {
1752 Some(var_ptr) => Value::Var(var_ptr),
1753 None => Value::Nil,
1754 },
1755 );
1756 }
1757 sym.name.as_ref().to_string()
1758 }
1759 Value::Str(s) => s.get().clone(),
1760 other => {
1761 return Err(EvalError::Runtime(format!(
1762 "resolve: arg must be symbol or string, got {}",
1763 other.type_name()
1764 )));
1765 }
1766 };
1767 Ok(match env.globals.lookup_var_in_ns(&resolve_ns, &sym_name) {
1768 Some(var_ptr) => Value::Var(var_ptr),
1769 None => Value::Nil,
1770 })
1771}
1772
1773fn handle_intern(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1774 if arg_forms.len() < 2 || arg_forms.len() > 3 {
1775 return Err(EvalError::Runtime("intern expects 2 or 3 arguments".into()));
1776 }
1777 let ns_val = eval(&arg_forms[0], env)?;
1778 let ns_name: Arc<str> = match &ns_val {
1779 Value::Symbol(s) => s.get().name.clone(),
1780 Value::Namespace(ns) => ns.get().name.clone(),
1781 other => {
1782 return Err(EvalError::Runtime(format!(
1783 "intern: first arg must be namespace or symbol, got {}",
1784 other.type_name()
1785 )));
1786 }
1787 };
1788 let var_name: Arc<str> = match eval(&arg_forms[1], env)? {
1789 Value::Symbol(s) => s.get().name.clone(),
1790 other => {
1791 return Err(EvalError::Runtime(format!(
1792 "intern: second arg must be symbol, got {}",
1793 other.type_name()
1794 )));
1795 }
1796 };
1797 let ns = {
1799 let map = env.globals.namespaces.read().unwrap();
1800 map.get(ns_name.as_ref()).cloned()
1801 };
1802 let ns = ns.ok_or_else(|| EvalError::Runtime(format!("No namespace: {ns_name} found")))?;
1803 let var = if arg_forms.len() == 3 {
1804 #[cfg(feature = "no-gc")]
1807 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1808 let val = eval(&arg_forms[2], env)?;
1809 let mut interns = ns.get().interns.lock().unwrap();
1810 if let Some(var) = interns.get(&var_name) {
1811 var.get().bind(val);
1812 var.clone()
1813 } else {
1814 let var =
1815 cljrs_gc::GcPtr::new(cljrs_value::Var::new(ns_name.clone(), var_name.clone()));
1816 var.get().bind(val);
1817 interns.insert(var_name, var.clone());
1818 var
1819 }
1820 } else {
1821 let mut interns = ns.get().interns.lock().unwrap();
1822 if let Some(var) = interns.get(&var_name) {
1823 var.clone()
1824 } else {
1825 let var =
1826 cljrs_gc::GcPtr::new(cljrs_value::Var::new(ns_name.clone(), var_name.clone()));
1827 interns.insert(var_name, var.clone());
1828 var
1829 }
1830 };
1831 Ok(Value::Var(var))
1832}
1833
1834fn handle_bound_fn_star(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1839 if arg_forms.len() != 1 {
1840 return Err(EvalError::Arity {
1841 name: "bound-fn*".into(),
1842 expected: "1".into(),
1843 got: arg_forms.len(),
1844 });
1845 }
1846 let f = eval(&arg_forms[0], env)?;
1847 let frames = crate::env::dynamics::capture_current();
1849 let mut merged = std::collections::HashMap::new();
1850 for frame in &frames {
1851 merged.extend(frame.iter().map(|(k, v)| (*k, v.clone())));
1852 }
1853 Ok(Value::BoundFn(cljrs_gc::GcPtr::new(cljrs_value::BoundFn {
1854 wrapped: f,
1855 captured_bindings: merged,
1856 })))
1857}