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, value_error_to_eval_error};
15use crate::interp::destructure::value_to_seq_vec;
16use crate::interp::eval::eval_unscoped as 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: &cljrs_gc::mutator::TrackedMutex<Vec<(Value, Value)>>,
35 reference: &Value,
36 old: &Value,
37 new: &Value,
38 env: &mut Env,
39) {
40 match reference {
41 Value::Atom(atom) => atom.get().protect_watches(),
42 Value::Var(var) => var.get().protect_watches(),
43 _ => {}
44 }
45 let ws: Vec<(Value, Value)> = watches.lock().unwrap().clone();
46 for (key, f) in &ws {
47 let args = vec![key.clone(), reference.clone(), old.clone(), new.clone()];
48 if let Err(e) = crate::env::apply::apply_value(f, args, env) {
49 WATCH_ERROR.with(|cell| {
56 cell.borrow_mut().replace(e);
57 });
58 return;
59 }
60 }
61}
62
63thread_local! {
64 static WATCH_ERROR: std::cell::RefCell<Option<EvalError>> = const { std::cell::RefCell::new(None) };
65}
66cljrs_gc::mutator_slot!("cljrs-runtime/WATCH_ERROR", refcell WATCH_ERROR: Option<EvalError>, trace trace_saved_watch_error);
67
68fn check_watch_error() -> EvalResult<()> {
70 WATCH_ERROR.with(|cell| {
71 if let Some(e) = cell.borrow_mut().take() {
72 Err(e)
73 } else {
74 Ok(())
75 }
76 })
77}
78
79#[derive(Debug)]
83pub struct ClosureThunk {
84 pub f: CljxFn,
85 pub globals: std::sync::Arc<crate::env::env::GlobalEnv>,
86 pub ns: std::sync::Arc<str>,
87}
88
89struct CallableValueThunk {
95 callee: Value,
96 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
97 ns: std::sync::Arc<str>,
98}
99
100impl std::fmt::Debug for CallableValueThunk {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 f.debug_struct("CallableValueThunk")
103 .field("callee", &self.callee.type_name())
104 .field("ns", &self.ns)
105 .finish()
106 }
107}
108
109impl cljrs_gc::Trace for CallableValueThunk {
110 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
111 self.callee.trace(visitor);
112 }
113}
114
115impl Thunk for CallableValueThunk {
116 fn force(&self) -> cljrs_value::ValueResult<Value> {
117 let mut env = Env::new(self.globals.clone(), &self.ns);
118 crate::env::apply::apply_value(&self.callee, Vec::new(), &mut env)
119 .map_err(crate::env::error::eval_error_to_thunk_error)
120 }
121}
122
123pub fn make_lazy_seq_from_fn(
136 f_val: &Value,
137 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
138 ns: std::sync::Arc<str>,
139) -> EvalResult {
140 let unwrapped = f_val.unwrap_meta();
141 if let Value::Fn(g) = unwrapped {
142 let thunk = ClosureThunk {
143 f: g.get().clone(),
144 globals,
145 ns,
146 };
147 return Ok(Value::LazySeq(GcPtr::new_isolated(LazySeq::new(Box::new(
148 thunk,
149 )))));
150 }
151 if unwrapped.type_name() != "fn" {
154 return Err(EvalError::Runtime(format!(
155 "make-lazy-seq requires a fn, got {}",
156 unwrapped.type_name(),
157 )));
158 }
159 let thunk = CallableValueThunk {
160 callee: unwrapped.clone(),
161 globals,
162 ns,
163 };
164 Ok(Value::LazySeq(GcPtr::new_isolated(LazySeq::new(Box::new(
165 thunk,
166 )))))
167}
168
169impl cljrs_gc::Trace for ClosureThunk {
170 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
171 self.f.trace(visitor);
172 }
173}
174
175impl Thunk for ClosureThunk {
176 fn force(&self) -> cljrs_value::ValueResult<Value> {
177 let _closed_root = crate::env::gc_roots::root_values(&self.f.closed_over_vals);
181 let mut env = Env::with_closure(self.globals.clone(), &self.ns, &self.f);
182 call_cljrs_fn(&self.f, &[], &mut env).map_err(crate::env::error::eval_error_to_thunk_error)
183 }
184}
185
186pub fn is_form_intercepted(name: &str) -> bool {
193 matches!(
194 name,
195 "apply"
196 | "atom"
197 | "reset!"
198 | "swap!"
199 | "volatile!"
200 | "vreset!"
201 | "agent"
202 | "make-lazy-seq"
203 | "make-delay"
204 | "vswap!"
205 | "send"
206 | "send-off"
207 | "with-bindings*"
208 | "alter-var-root"
209 | "vary-meta"
210 | "eval"
211 | "find-ns"
212 | "the-ns"
213 | "ns-interns"
214 | "ns-publics"
215 | "ns-refers"
216 | "ns-map"
217 | "all-ns"
218 | "create-ns"
219 | "ns-aliases"
220 | "remove-ns"
221 | "alter-meta!"
222 | "ns-resolve"
223 | "resolve"
224 | "intern"
225 | "bound-fn*"
226 )
227}
228
229pub fn eval_call(
241 site: Option<&Form>,
242 func_form: &Form,
243 arg_forms: &[Form],
244 env: &mut Env,
245) -> EvalResult {
246 if let FormKind::Symbol(s) = &func_form.kind
248 && is_method_sugar(s)
249 {
250 return eval_method_call(&s[1..], arg_forms, env);
251 }
252
253 let callee = eval(func_form, env)?;
255
256 let _callee_root = crate::env::gc_roots::root_value(&callee);
258
259 if let Value::Macro(mfn) = &callee {
261 let mfn = mfn.get();
262 if let (Some(site), Some(macro_id)) = (site, mfn.arities.first().map(|a| a.ir_arity_id)) {
266 if let Some(expanded) = site.expansion.get(macro_id, &env.current_ns) {
267 return eval(&expanded, env);
268 }
269 let ns = env.current_ns.clone();
270 let expanded = macro_apply(mfn, func_form, arg_forms, env)?;
271 let expanded = site.expansion.store(macro_id, ns, expanded);
272 return eval(&expanded, env);
273 }
274 let expanded = macro_apply(mfn, func_form, arg_forms, env)?;
275 return eval(&expanded, env);
276 }
277
278 if let Value::NativeFunction(nf) = &callee {
280 crate::env::policy::check_native(&nf.get().name)?;
281 match nf.get().name.as_ref() {
282 "apply" => return handle_apply_call(arg_forms, env),
283 "atom" => return handle_atom_call(arg_forms, env),
284 "reset!" => return handle_reset_bang(arg_forms, env),
285 "swap!" => return handle_swap_call(arg_forms, env),
286 "volatile!" => return handle_volatile(arg_forms, env),
287 "vreset!" => return handle_vreset(arg_forms, env),
288 "agent" => return handle_agent_call(arg_forms, env),
289 "make-lazy-seq" => return handle_make_lazy_seq(arg_forms, env),
290 "make-delay" => return handle_make_delay(arg_forms, env),
291 "vswap!" => return handle_vswap(arg_forms, env),
292 "send" | "send-off" => return handle_send(arg_forms, env),
293 "with-bindings*" => return handle_with_bindings(arg_forms, env),
294 "alter-var-root" => return handle_alter_var_root(arg_forms, env),
295 "vary-meta" => return handle_vary_meta(arg_forms, env),
296 "eval" => return handle_eval(arg_forms, env),
297 "find-ns" | "the-ns" => return handle_find_ns(arg_forms, env),
298 "ns-interns" | "ns-publics" => return handle_ns_interns(arg_forms, env),
299 "ns-refers" => return handle_ns_refers(arg_forms, env),
300 "ns-map" => return handle_ns_map(arg_forms, env),
301 "all-ns" => return handle_all_ns(arg_forms, env),
302 "create-ns" => return handle_create_ns(arg_forms, env),
303 "ns-aliases" => return handle_ns_aliases(arg_forms, env),
304 "remove-ns" => return handle_remove_ns(arg_forms, env),
305 "alter-meta!" => return handle_alter_meta(arg_forms, env),
306 "ns-resolve" => return handle_ns_resolve(arg_forms, env),
307 "resolve" => return handle_resolve(arg_forms, env),
308 "intern" => return handle_intern(arg_forms, env),
309 "bound-fn*" => return handle_bound_fn_star(arg_forms, env),
310 _ => {}
311 }
312 }
313
314 let mut args: Vec<Value> = Vec::with_capacity(arg_forms.len());
317 for f in arg_forms {
318 let _args_root = crate::env::gc_roots::root_values(&args);
320 args.push(eval(f, env)?);
321 }
322
323 if let Value::Fn(f) = &callee {
328 if let Some(fut) = crate::env::apply::dispatch_if_async(&callee, &args, env) {
331 return Ok(fut);
332 }
333 let _args_root = crate::env::gc_roots::root_values(&args);
334 crate::env::gc_roots::gc_safepoint(env)?;
335 return env.call_cljrs_fn(f.get(), &args);
336 }
337
338 crate::env::apply::apply_value(&callee, args, env)
339}
340
341fn eval_method_call(method: &str, arg_forms: &[Form], env: &mut Env) -> EvalResult {
351 if arg_forms.is_empty() {
352 return Err(EvalError::Runtime(format!(
353 ".{method} requires a target object"
354 )));
355 }
356 let target = eval(&arg_forms[0], env)?;
357 let args: Vec<Value> = arg_forms[1..]
358 .iter()
359 .map(|f| eval(f, env))
360 .collect::<EvalResult<_>>()?;
361
362 dispatch_method(method, &target, &args)
363}
364
365pub use cljrs_ir::lower::is_method_sugar;
370
371pub fn dispatch_method(method: &str, target: &Value, args: &[Value]) -> EvalResult {
377 match target {
378 Value::Str(s) => dispatch_string_method(method, s.get(), args),
379 Value::Vector(v) => dispatch_vector_method(method, v, args),
380 Value::List(_) | Value::Cons(_) | Value::LazySeq(_) => {
381 dispatch_seq_method(method, target, args)
382 }
383 Value::TypeInstance(ti) => {
384 if ti.get().type_tag.as_ref() == "java.util.Date"
385 && method == "getTime"
386 && args.is_empty()
387 {
388 let key = Value::keyword(cljrs_value::Keyword::simple("millis"));
389 return Ok(ti.get().fields.get(&key).unwrap_or(Value::Nil));
390 }
391 if let Some(field) = method.strip_prefix('-') {
395 let key = Value::keyword(cljrs_value::Keyword::simple(field));
396 let inst = ti.get();
397 if let Some(atom) = &inst.mutable
400 && let Value::Map(m) = atom.get().deref()
401 && let Some(v) = m.get(&key)
402 {
403 return Ok(v);
404 }
405 Ok(inst.fields.get(&key).unwrap_or(Value::Nil))
406 } else {
407 Err(EvalError::Runtime(format!(
408 ".{method} not supported on {} (only .-field access is)",
409 target.type_name()
410 )))
411 }
412 }
413 _ => Err(EvalError::Runtime(format!(
414 ".{method} not supported on type {}",
415 target.type_name()
416 ))),
417 }
418}
419
420fn dispatch_string_method(method: &str, s: &str, args: &[Value]) -> EvalResult {
421 match method {
422 "indexOf" => {
423 let needle = match args.first() {
424 Some(Value::Str(s)) => s.get().to_string(),
425 Some(Value::Char(c)) => c.to_string(),
426 Some(v) => {
427 return Err(EvalError::Runtime(format!(
428 ".indexOf expects string or char argument, got {}",
429 v.type_name()
430 )));
431 }
432 None => return Err(EvalError::Runtime(".indexOf requires an argument".into())),
433 };
434 match s.find(&needle) {
435 Some(pos) => Ok(Value::Long(pos as i64)),
436 None => Ok(Value::Long(-1)),
437 }
438 }
439 "lastIndexOf" => {
440 let needle = match args.first() {
441 Some(Value::Str(s)) => s.get().to_string(),
442 Some(Value::Char(c)) => c.to_string(),
443 _ => {
444 return Err(EvalError::Runtime(
445 ".lastIndexOf requires a string or char argument".into(),
446 ));
447 }
448 };
449 match s.rfind(&needle) {
450 Some(pos) => Ok(Value::Long(pos as i64)),
451 None => Ok(Value::Long(-1)),
452 }
453 }
454 "startsWith" => {
455 let prefix = require_str_arg(args, ".startsWith")?;
456 Ok(Value::Bool(s.starts_with(&prefix)))
457 }
458 "endsWith" => {
459 let suffix = require_str_arg(args, ".endsWith")?;
460 Ok(Value::Bool(s.ends_with(&suffix)))
461 }
462 "contains" => {
463 let sub = require_str_arg(args, ".contains")?;
464 Ok(Value::Bool(s.contains(&sub)))
465 }
466 "length" => Ok(Value::Long(s.len() as i64)),
467 "isEmpty" => Ok(Value::Bool(s.is_empty())),
468 "charAt" => {
469 let idx = require_long_arg(args, ".charAt")? as usize;
470 s.chars()
471 .nth(idx)
472 .map(Value::Char)
473 .ok_or_else(|| EvalError::Runtime(format!(".charAt index {idx} out of bounds")))
474 }
475 "substring" => {
476 let start = require_long_arg(args, ".substring")? as usize;
477 let end = args
478 .get(1)
479 .map(|v| match v {
480 Value::Long(n) => Ok(*n as usize),
481 _ => Err(EvalError::Runtime(
482 ".substring end must be an integer".into(),
483 )),
484 })
485 .transpose()?;
486 let result = match end {
487 Some(e) => &s[start..e.min(s.len())],
488 None => &s[start..],
489 };
490 Ok(Value::Str(GcPtr::new(result.to_string())))
491 }
492 "toUpperCase" => Ok(Value::Str(GcPtr::new(s.to_uppercase()))),
493 "toLowerCase" => Ok(Value::Str(GcPtr::new(s.to_lowercase()))),
494 "trim" => Ok(Value::Str(GcPtr::new(s.trim().to_string()))),
495 "replace" => {
496 let from = require_str_arg(args, ".replace")?;
497 let to = match args.get(1) {
498 Some(Value::Str(s)) => s.get().to_string(),
499 Some(Value::Char(c)) => c.to_string(),
500 _ => {
501 return Err(EvalError::Runtime(
502 ".replace requires two string arguments".into(),
503 ));
504 }
505 };
506 Ok(Value::Str(GcPtr::new(s.replace(&from, &to))))
507 }
508 "split" => {
509 let sep = require_str_arg(args, ".split")?;
510 let parts: Vec<Value> = s
511 .split(&sep)
512 .map(|p| Value::Str(GcPtr::new(p.to_string())))
513 .collect();
514 Ok(Value::Vector(GcPtr::new(
515 cljrs_value::PersistentVector::from_iter(parts),
516 )))
517 }
518 _ => Err(EvalError::Runtime(format!(
519 ".{method} not supported on String"
520 ))),
521 }
522}
523
524fn dispatch_vector_method(
525 method: &str,
526 v: &GcPtr<cljrs_value::PersistentVector>,
527 args: &[Value],
528) -> EvalResult {
529 match method {
530 "indexOf" => {
531 let needle = args
532 .first()
533 .ok_or_else(|| EvalError::Runtime(".indexOf requires an argument".into()))?;
534 for (i, item) in v.get().iter().enumerate() {
535 if item == needle {
536 return Ok(Value::Long(i as i64));
537 }
538 }
539 Ok(Value::Long(-1))
540 }
541 "size" | "count" => Ok(Value::Long(v.get().count() as i64)),
542 _ => Err(EvalError::Runtime(format!(
543 ".{method} not supported on Vector"
544 ))),
545 }
546}
547
548fn dispatch_seq_method(method: &str, target: &Value, args: &[Value]) -> EvalResult {
549 match method {
550 "indexOf" => {
551 let needle = args
552 .first()
553 .ok_or_else(|| EvalError::Runtime(".indexOf requires an argument".into()))?;
554 let items = crate::interp::destructure::value_to_seq_vec(target)
555 .map_err(crate::env::error::value_error_to_eval_error)?;
556 for (i, item) in items.iter().enumerate() {
557 if item == needle {
558 return Ok(Value::Long(i as i64));
559 }
560 }
561 Ok(Value::Long(-1))
562 }
563 _ => Err(EvalError::Runtime(format!(
564 ".{method} not supported on {}",
565 target.type_name()
566 ))),
567 }
568}
569
570fn require_str_arg(args: &[Value], method: &str) -> Result<String, EvalError> {
571 match args.first() {
572 Some(Value::Str(s)) => Ok(s.get().to_string()),
573 Some(Value::Char(c)) => Ok(c.to_string()),
574 _ => Err(EvalError::Runtime(format!(
575 "{method} requires a string argument"
576 ))),
577 }
578}
579
580fn require_long_arg(args: &[Value], method: &str) -> Result<i64, EvalError> {
581 match args.first() {
582 Some(Value::Long(n)) => Ok(*n),
583 _ => Err(EvalError::Runtime(format!(
584 "{method} requires an integer argument"
585 ))),
586 }
587}
588
589pub fn resolve_type_tag(sym: &str) -> Arc<str> {
592 Arc::from(sym)
593}
594
595pub fn call_cljrs_fn(f: &CljxFn, args: &[Value], caller_env: &mut Env) -> EvalResult {
597 let arity = select_arity(f, args.len())?;
598
599 let _caller_root = crate::env::gc_roots::push_env_root(caller_env);
602
603 let mut env = Env::with_closure(caller_env.globals.clone(), &f.defining_ns, f);
606
607 let mut current_args = Vec::from(args);
608 #[cfg(feature = "no-gc")]
609 let mut recur_lease = cljrs_gc::region::RegionLease::default();
610 loop {
611 let _args_root = crate::env::gc_roots::root_values(¤t_args);
614
615 crate::env::gc_roots::gc_safepoint(&env)?;
617
618 env.push_frame();
619
620 #[cfg(not(feature = "no-gc"))]
630 let _call_frame = cljrs_gc::push_alloc_frame();
631
632 if let Some(ref name) = f.name {
641 let self_val = if let Some(ref p) = f.self_ptr {
642 Value::Fn(p.clone())
643 } else {
644 Value::Fn(GcPtr::new(f.clone()))
645 };
646 env.bind(name.clone(), self_val);
647 }
648
649 bind_fn_params(arity, ¤t_args, &mut env)?;
651
652 #[cfg(not(feature = "no-gc"))]
656 let result = eval_body_recur_fn(&arity.body, &mut env);
657 #[cfg(feature = "no-gc")]
658 let result = {
659 let mut scratch = cljrs_gc::alloc_ctx::ScratchGuard::new();
660 eval_body_with_scratch(&arity.body, &mut scratch, &mut recur_lease, &mut env)
662 };
663 env.pop_frame();
664 match result {
668 Ok(v) => return Ok(v),
669 Err(EvalError::Recur(new_args)) => {
670 if arity.rest_param.is_some() {
675 let n = arity.params.len();
676 if new_args.len() == n + 1 {
677 let mut flat = new_args[..n].to_vec();
678 let rest_val = &new_args[n];
680 match rest_val {
681 Value::Nil => {} _ => {
683 let rest_items = value_to_seq_vec(rest_val)
684 .map_err(crate::env::error::value_error_to_eval_error)?;
685 flat.extend(rest_items);
686 }
687 }
688 current_args = flat;
689 } else {
690 current_args = new_args;
691 }
692 } else {
693 current_args = new_args;
694 }
695 }
696 Err(e) => return Err(e),
697 }
698 }
699}
700
701pub fn bind_fn_params(arity: &CljxFnArity, args: &[Value], env: &mut Env) -> EvalResult<()> {
704 bind_fn_params_impl(arity, args, env, true)
705}
706
707pub fn bind_fn_params_positional(
718 arity: &CljxFnArity,
719 args: &[Value],
720 env: &mut Env,
721) -> EvalResult<()> {
722 bind_fn_params_impl(arity, args, env, false)
723}
724
725fn bind_fn_params_impl(
726 arity: &CljxFnArity,
727 args: &[Value],
728 env: &mut Env,
729 destructure: bool,
730) -> EvalResult<()> {
731 let n = arity.params.len();
732 for (i, name) in arity.params.iter().enumerate() {
734 let val = args.get(i).cloned().unwrap_or(Value::Nil);
735 env.bind(name.clone(), val);
736 }
737 if let Some(ref rest) = arity.rest_param {
739 let rest_items = args[n..].to_vec();
740 let rest_val = if rest_items.is_empty() {
741 Value::Nil
742 } else {
743 Value::List(GcPtr::new(PersistentList::from_iter(rest_items)))
744 };
745 env.bind(rest.clone(), rest_val.clone());
746 if destructure && let Some(ref pattern) = arity.destructure_rest {
748 let destructure_val = if pattern.is_kwargs_rest_pattern() {
752 let items = value_to_seq_vec(&rest_val)
753 .map_err(crate::env::error::value_error_to_eval_error)?;
754 Value::from_kwargs_rest(items).map_err(value_error_to_eval_error)?
755 } else {
756 rest_val
757 };
758 crate::interp::destructure::bind_pattern(pattern, destructure_val, env)?;
759 }
760 }
761 if destructure {
763 for (idx, pattern) in &arity.destructure_params {
764 let val = args.get(*idx).cloned().unwrap_or(Value::Nil);
765 crate::interp::destructure::bind_pattern(pattern, val, env)?;
766 }
767 }
768 Ok(())
769}
770
771#[cfg(not(feature = "no-gc"))]
773fn eval_body_recur_fn(body: &[cljrs_reader::Form], env: &mut Env) -> EvalResult {
774 let mut result = Value::Nil;
775 for form in body {
776 result = eval(form, env)?;
777 }
778 Ok(result)
779}
780
781#[cfg(feature = "no-gc")]
784pub(crate) fn eval_body_with_scratch(
785 body: &[cljrs_reader::Form],
786 scratch: &mut cljrs_gc::alloc_ctx::ScratchGuard,
787 recur_lease: &mut cljrs_gc::region::RegionLease,
788 env: &mut Env,
789) -> EvalResult {
790 let mut result = Ok(Value::Nil);
791 for form in body {
792 result = eval(form, env);
793 if result.is_err() {
794 break;
795 }
796 }
797 scratch.pop_for_return();
798 crate::interp::eval::publish_result(result, Some(recur_lease))
799}
800
801pub fn select_arity(f: &CljxFn, argc: usize) -> EvalResult<&CljxFnArity> {
803 let name = f.name.as_deref().unwrap_or("fn");
804 for arity in &f.arities {
806 if arity.rest_param.is_none() && arity.params.len() == argc {
807 return Ok(arity);
808 }
809 }
810 for arity in &f.arities {
812 if arity.rest_param.is_some() && argc >= arity.params.len() {
813 return Ok(arity);
814 }
815 }
816 let implicit = if f.is_macro { IMPLICIT_MACRO_ARGS } else { 0 };
821 let expected: Vec<String> = f
822 .arities
823 .iter()
824 .map(|a| {
825 let fixed = a.params.len().saturating_sub(implicit);
826 if a.rest_param.is_some() {
827 format!("{fixed}+")
828 } else {
829 fixed.to_string()
830 }
831 })
832 .collect();
833 Err(EvalError::Arity {
834 name: name.to_string(),
835 expected: expected.join(" or "),
836 got: argc.saturating_sub(implicit),
837 })
838}
839
840const IMPLICIT_MACRO_ARGS: usize = 2;
842
843fn macro_apply(
850 mfn: &CljxFn,
851 func_form: &Form,
852 arg_forms: &[Form],
853 env: &mut Env,
854) -> EvalResult<Form> {
855 let resolved_args: Vec<Form> = arg_forms
860 .iter()
861 .map(|f| crate::builtins::form::resolve_auto_forms(f, env))
862 .collect::<EvalResult<Vec<Form>>>()?;
863
864 let form_val = {
866 let mut items = vec![form_to_value(func_form)?];
867 for f in &resolved_args {
868 items.push(form_to_value(f)?);
869 }
870 Value::List(GcPtr::new(PersistentList::from_iter(items)))
871 };
872
873 let env_val = {
875 let (names, vals) = env.all_local_bindings();
876 let mut m = MapValue::empty();
877 for (name, val) in names.iter().zip(vals.iter()) {
878 m = m.assoc(Value::symbol(Symbol::simple(name.as_ref())), val.clone());
879 }
880 Value::Map(m)
881 };
882
883 let mut args = vec![form_val, env_val];
885 for f in &resolved_args {
886 args.push(form_to_value(f)?);
887 }
888
889 let expanded_val = call_cljrs_fn(mfn, args.as_ref(), env)?;
890 let _expanded_root = crate::env::gc_roots::root_value(&expanded_val);
893 let dummy_span = cljrs_types::span::Span::new(Arc::new("<macro>".to_string()), 0, 0, 1, 1);
894 crate::interp::macros::value_to_form(&expanded_val, dummy_span)
895}
896
897fn handle_apply_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
899 let mut evaled: Vec<Value> = Vec::with_capacity(arg_forms.len());
900 for f in arg_forms {
901 let _root = crate::env::gc_roots::root_values(&evaled);
902 evaled.push(eval(f, env)?);
903 }
904
905 if evaled.len() < 2 {
906 return Err(EvalError::Arity {
907 name: "apply".into(),
908 expected: "2+".into(),
909 got: evaled.len(),
910 });
911 }
912
913 let f = evaled.remove(0);
914 let last = evaled.pop().unwrap();
915 let _f_root = crate::env::gc_roots::root_value(&f);
917 let _last_root = crate::env::gc_roots::root_value(&last);
918 let _evaled_root = crate::env::gc_roots::root_values(&evaled);
919 let spread =
921 crate::builtins::builtins::value_to_seq(&last).map_err(value_error_to_eval_error)?;
922 evaled.extend(spread);
923 crate::env::apply::apply_value(&f, evaled, env)
924}
925
926pub fn handle_make_lazy_seq(arg_forms: &[Form], env: &mut Env) -> EvalResult {
928 if arg_forms.len() != 1 {
929 return Err(EvalError::Arity {
930 name: "make-lazy-seq".into(),
931 expected: "1".into(),
932 got: arg_forms.len(),
933 });
934 }
935 let f_val = eval(&arg_forms[0], env)?;
936 let f = match f_val {
937 Value::Fn(f) => f.get().clone(),
938 other => {
939 return Err(EvalError::Runtime(format!(
940 "make-lazy-seq requires a fn, got {}",
941 other.type_name()
942 )));
943 }
944 };
945 let thunk = ClosureThunk {
946 f,
947 globals: env.globals.clone(),
948 ns: env.current_ns.clone(),
949 };
950 Ok(Value::LazySeq(GcPtr::new_isolated(LazySeq::new(Box::new(
951 thunk,
952 )))))
953}
954
955fn handle_make_delay(arg_forms: &[Form], env: &mut Env) -> EvalResult {
957 if arg_forms.len() != 1 {
958 return Err(EvalError::Arity {
959 name: "make-delay".into(),
960 expected: "1".into(),
961 got: arg_forms.len(),
962 });
963 }
964 let f_val = eval(&arg_forms[0], env)?;
965 let f = match f_val {
966 Value::Fn(f) => f.get().clone(),
967 other => {
968 return Err(EvalError::Runtime(format!(
969 "make-delay requires a fn, got {}",
970 other.type_name()
971 )));
972 }
973 };
974 let thunk = ClosureThunk {
975 f,
976 globals: env.globals.clone(),
977 ns: env.current_ns.clone(),
978 };
979 Ok(Value::Delay(GcPtr::new_isolated(Delay::new(Box::new(
980 thunk,
981 )))))
982}
983
984fn handle_vswap(arg_forms: &[Form], env: &mut Env) -> EvalResult {
986 if arg_forms.len() < 2 {
987 return Err(EvalError::Arity {
988 name: "vswap!".into(),
989 expected: "2+".into(),
990 got: arg_forms.len(),
991 });
992 }
993 let vol_val = eval(&arg_forms[0], env)?;
994 let f = eval(&arg_forms[1], env)?;
995 let extra: Vec<Value> = arg_forms[2..]
996 .iter()
997 .map(|a| eval(a, env))
998 .collect::<EvalResult<_>>()?;
999
1000 match vol_val {
1001 Value::Volatile(v) => {
1002 let previous_payload = v.get().snapshot();
1003 let cur = previous_payload.value.clone();
1004 let mut call_args = vec![cur];
1005 call_args.extend(extra);
1006 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1007 let new_val = v.get().reset(new_val);
1008 Ok(new_val)
1009 }
1010 other => Err(EvalError::Runtime(format!(
1011 "vswap!: expected volatile, got {}",
1012 other.type_name()
1013 ))),
1014 }
1015}
1016
1017fn handle_volatile(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1021 if arg_forms.is_empty() {
1022 return Err(EvalError::Arity {
1023 name: "volatile!".into(),
1024 expected: "1".into(),
1025 got: 0,
1026 });
1027 }
1028 #[cfg(feature = "no-gc")]
1031 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1032 let initial = eval(&arg_forms[0], env)?;
1033 Ok(Value::Volatile(GcPtr::new(Volatile::new(initial))))
1034}
1035
1036fn handle_vreset(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1040 if arg_forms.len() < 2 {
1041 return Err(EvalError::Arity {
1042 name: "vreset!".into(),
1043 expected: "2".into(),
1044 got: arg_forms.len(),
1045 });
1046 }
1047 let vol_val = eval(&arg_forms[0], env)?;
1048 let new_val = eval(&arg_forms[1], env)?;
1049 match &vol_val {
1050 Value::Volatile(v) => {
1051 let new_val = v.get().reset(new_val);
1052 Ok(new_val)
1053 }
1054 other => Err(EvalError::Runtime(format!(
1055 "vreset!: expected volatile, got {}",
1056 other.type_name()
1057 ))),
1058 }
1059}
1060
1061fn handle_agent_call(_arg_forms: &[Form], _env: &mut Env) -> EvalResult {
1065 Err(EvalError::Runtime("agent is not yet implemented".into()))
1066}
1067
1068fn handle_send(_arg_forms: &[Form], _env: &mut Env) -> EvalResult {
1070 Err(EvalError::Runtime(
1071 "send/send-off: agents are not yet implemented".into(),
1072 ))
1073}
1074
1075fn handle_atom_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1079 if arg_forms.is_empty() {
1080 return Err(EvalError::Arity {
1081 name: "atom".into(),
1082 expected: "1+".into(),
1083 got: 0,
1084 });
1085 }
1086 #[cfg(feature = "no-gc")]
1089 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1090 let initial = eval(&arg_forms[0], env)?;
1091
1092 let options: Vec<Value> = arg_forms[1..]
1094 .iter()
1095 .map(|f| eval(f, env))
1096 .collect::<EvalResult<_>>()?;
1097
1098 let mut meta_opt: Option<Value> = None;
1099 let mut validator_opt: Option<Value> = None;
1100 let mut i = 0;
1101 while i + 1 < options.len() {
1102 match &options[i] {
1103 Value::Keyword(k) if k.get().name.as_ref() == "meta" => {
1104 meta_opt = Some(options[i + 1].clone());
1105 i += 2;
1106 }
1107 Value::Keyword(k) if k.get().name.as_ref() == "validator" => {
1108 let vf = options[i + 1].clone();
1109 validator_opt = if vf == Value::Nil { None } else { Some(vf) };
1110 i += 2;
1111 }
1112 _ => {
1113 i += 2;
1114 }
1115 }
1116 }
1117
1118 if let Some(ref m) = meta_opt
1120 && !matches!(m, Value::Nil | Value::Map(_))
1121 {
1122 return Err(EvalError::Thrown(Value::string(
1123 "Atom metadata must be a map or nil".to_string(),
1124 )));
1125 }
1126
1127 if let Some(ref vf) = validator_opt {
1129 let result = crate::env::apply::apply_value(vf, vec![initial.clone()], env)?;
1130 if result == Value::Nil || result == Value::Bool(false) {
1131 return Err(EvalError::Thrown(Value::string(
1132 "Invalid initial value for atom".to_string(),
1133 )));
1134 }
1135 }
1136
1137 let atom = GcPtr::new_isolated(Atom::new(initial));
1138 if let Some(m) = meta_opt {
1139 atom.get()
1140 .set_meta(if m == Value::Nil { None } else { Some(m) });
1141 }
1142 if let Some(vf) = validator_opt {
1143 atom.get().set_validator(Some(vf));
1144 }
1145 Ok(Value::Atom(atom))
1146}
1147
1148fn shared_atom_reset(sa: &Arc<cljrs_value::SharedAtom>, new_val: Value) -> EvalResult {
1160 let promoted = cljrs_value::promote(&new_val).map_err(promote_error)?;
1161 sa.try_reset(promoted)
1162 .map_err(EvalError::MemoryLimitExceeded)?;
1163 Ok(new_val)
1164}
1165
1166fn promote_error(e: cljrs_value::PromoteError) -> EvalError {
1168 match e.memory {
1169 Some(fault) => EvalError::MemoryLimitExceeded(fault),
1170 None => EvalError::Runtime(e.to_string()),
1171 }
1172}
1173
1174fn shared_atom_swap(
1179 sa: &Arc<cljrs_value::SharedAtom>,
1180 f: &Value,
1181 extra: Vec<Value>,
1182 env: &mut Env,
1183) -> EvalResult {
1184 loop {
1185 let cur = sa.deref_val();
1186 let old_val = cljrs_value::demote(&cur);
1187 let mut call_args = Vec::with_capacity(1 + extra.len());
1188 call_args.push(old_val);
1189 call_args.extend(extra.iter().cloned());
1190 let new_val = crate::env::apply::apply_value(f, call_args, env)?;
1191 let promoted = cljrs_value::promote(&new_val).map_err(promote_error)?;
1192 if sa
1193 .try_compare_and_set(&cur, promoted)
1194 .map_err(EvalError::MemoryLimitExceeded)?
1195 {
1196 return Ok(new_val);
1197 }
1198 }
1200}
1201
1202fn handle_reset_bang(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1205 if arg_forms.len() < 2 {
1206 return Err(EvalError::Arity {
1207 name: "reset!".into(),
1208 expected: "2".into(),
1209 got: arg_forms.len(),
1210 });
1211 }
1212 let atom_val = eval(&arg_forms[0], env)?;
1213 let new_val = eval(&arg_forms[1], env)?;
1214
1215 let atom = match &atom_val {
1216 Value::Atom(a) => a.clone(),
1217 Value::SharedAtom(sa) => return shared_atom_reset(sa, new_val),
1218 v => {
1219 return Err(EvalError::Runtime(format!(
1220 "reset! requires an atom, got {}",
1221 v.type_name()
1222 )));
1223 }
1224 };
1225
1226 validate_atom_value(&atom, &new_val, env)?;
1227 let previous_payload = atom.get().snapshot();
1228 let old_val = previous_payload.value.clone();
1229 let new_val = atom.get().reset(new_val);
1230 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1231 check_watch_error()?;
1232 Ok(new_val)
1233}
1234
1235fn validate_atom_value(atom: &GcPtr<Atom>, new_val: &Value, env: &mut Env) -> EvalResult<()> {
1237 if let Some(vf) = atom.get().get_validator() {
1238 let result = crate::env::apply::apply_value(&vf, vec![new_val.clone()], env)?;
1239 if result == Value::Nil || result == Value::Bool(false) {
1240 return Err(EvalError::Thrown(Value::string(
1241 "Invalid value for atom".to_string(),
1242 )));
1243 }
1244 }
1245 Ok(())
1246}
1247
1248fn handle_swap_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1251 let mut evaled: Vec<Value> = arg_forms
1252 .iter()
1253 .map(|f| eval(f, env))
1254 .collect::<EvalResult<_>>()?;
1255
1256 if evaled.len() < 2 {
1257 return Err(EvalError::Arity {
1258 name: "swap!".into(),
1259 expected: "2+".into(),
1260 got: evaled.len(),
1261 });
1262 }
1263
1264 let atom_val = evaled.remove(0);
1265 let f = evaled.remove(0);
1266
1267 let atom = match &atom_val {
1268 Value::Atom(a) => a.clone(),
1269 Value::SharedAtom(sa) => return shared_atom_swap(sa, &f, evaled, env),
1270 v => {
1271 return Err(EvalError::Runtime(format!(
1272 "swap! requires an atom, got {}",
1273 v.type_name()
1274 )));
1275 }
1276 };
1277
1278 let previous_payload = atom.get().snapshot();
1279 let old_val = previous_payload.value.clone();
1280 let mut args = vec![old_val.clone()];
1281 args.extend(evaled);
1282 let new_val = crate::env::apply::apply_value(&f, args, env)?;
1283 validate_atom_value(&atom, &new_val, env)?;
1284 let new_val = atom.get().reset(new_val);
1285 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1286 check_watch_error()?;
1287 Ok(new_val)
1288}
1289
1290fn handle_with_bindings(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1295 if arg_forms.len() < 2 {
1296 return Err(EvalError::Arity {
1297 name: "with-bindings*".into(),
1298 expected: "2".into(),
1299 got: arg_forms.len(),
1300 });
1301 }
1302 let map_val = eval(&arg_forms[0], env)?;
1303 let func_val = eval(&arg_forms[1], env)?;
1304
1305 let mut frame: HashMap<usize, Value> = HashMap::new();
1306 if let Value::Map(m) = &map_val {
1307 m.for_each(|k, v| {
1308 if let Value::Var(vp) = k {
1309 frame.insert(crate::env::dynamics::var_key_of(vp), v.clone());
1310 }
1311 });
1313 } else {
1314 return Err(EvalError::Runtime(
1315 "with-bindings*: first arg must be a map".into(),
1316 ));
1317 }
1318
1319 let _guard = crate::env::dynamics::push_frame(frame);
1320 crate::env::apply::apply_value(&func_val, vec![], env)
1321}
1322
1323fn handle_alter_var_root(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1327 if arg_forms.len() < 2 {
1328 return Err(EvalError::Arity {
1329 name: "alter-var-root".into(),
1330 expected: "2+".into(),
1331 got: arg_forms.len(),
1332 });
1333 }
1334 let var_val = eval(&arg_forms[0], env)?;
1335 let f = eval(&arg_forms[1], env)?;
1336 let extra: Vec<Value> = arg_forms[2..]
1337 .iter()
1338 .map(|form| eval(form, env))
1339 .collect::<EvalResult<_>>()?;
1340
1341 let vp = match &var_val {
1342 Value::Var(vp) => vp.clone(),
1343 v => {
1344 return Err(EvalError::Runtime(format!(
1345 "alter-var-root: expected var, got {}",
1346 v.type_name()
1347 )));
1348 }
1349 };
1350 let old_val = vp.get().deref().unwrap_or(Value::Nil);
1351 let mut call_args = vec![old_val.clone()];
1352 call_args.extend(extra);
1353 #[cfg(feature = "no-gc")]
1356 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1357 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1358 vp.get().bind(new_val.clone());
1359 fire_watches(&vp.get().watches, &var_val, &old_val, &new_val, env);
1360 check_watch_error()?;
1361 Ok(new_val)
1362}
1363
1364fn handle_vary_meta(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1368 if arg_forms.len() < 2 {
1369 return Err(EvalError::Arity {
1370 name: "vary-meta".into(),
1371 expected: "2+".into(),
1372 got: arg_forms.len(),
1373 });
1374 }
1375 let obj = eval(&arg_forms[0], env)?;
1376 let f = eval(&arg_forms[1], env)?;
1377 let extra: Vec<Value> = arg_forms[2..]
1378 .iter()
1379 .map(|form| eval(form, env))
1380 .collect::<EvalResult<_>>()?;
1381
1382 let current_meta = match &obj {
1383 Value::Var(vp) => vp.get().get_meta().unwrap_or(Value::Nil),
1384 _ => Value::Nil,
1385 };
1386 let mut call_args = vec![current_meta];
1387 call_args.extend(extra);
1388 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1389 if let Value::Var(vp) = &obj {
1390 vp.get().set_meta(new_meta);
1391 }
1392 Ok(obj)
1393}
1394
1395fn handle_eval(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1399 let [arg] = arg_forms else {
1400 return Err(EvalError::Arity {
1401 name: "eval".into(),
1402 expected: "1".into(),
1403 got: arg_forms.len(),
1404 });
1405 };
1406 let value = eval(arg, env)?;
1407 eval_eval(vec![value], env)
1408}
1409
1410pub fn eval_eval(args: Vec<Value>, env: &mut Env) -> EvalResult {
1415 let [value] = args.as_slice() else {
1416 return Err(EvalError::Arity {
1417 name: "eval".into(),
1418 expected: "1".into(),
1419 got: args.len(),
1420 });
1421 };
1422 if matches!(
1425 value.unwrap_meta(),
1426 Value::NativeFunction(_) | Value::Fn(_) | Value::Macro(_) | Value::BoundFn(_)
1427 ) {
1428 return Ok(value.clone());
1429 }
1430 let span = cljrs_types::span::Span::new(Arc::new("<eval>".to_string()), 0, 0, 1, 1);
1431 let form = crate::interp::macros::value_to_form(value, span)?;
1432 let mut top = Env::new(env.globals.clone(), &env.current_ns);
1433 eval(&form, &mut top)
1434}
1435
1436pub fn eval_reset_bang(args: Vec<Value>, env: &mut Env) -> EvalResult {
1444 if args.len() < 2 {
1445 return Err(EvalError::Arity {
1446 name: "reset!".into(),
1447 expected: "2".into(),
1448 got: args.len(),
1449 });
1450 }
1451 let atom_val = args[0].clone();
1452 let new_val = args[1].clone();
1453 let atom = match &atom_val {
1454 Value::Atom(a) => a.clone(),
1455 Value::SharedAtom(sa) => return shared_atom_reset(sa, new_val),
1456 v => {
1457 return Err(EvalError::Runtime(format!(
1458 "reset! requires an atom, got {}",
1459 v.type_name()
1460 )));
1461 }
1462 };
1463 validate_atom_value(&atom, &new_val, env)?;
1464 let previous_payload = atom.get().snapshot();
1465 let old_val = previous_payload.value.clone();
1466 let new_val = atom.get().reset(new_val);
1467 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1468 check_watch_error()?;
1469 Ok(new_val)
1470}
1471
1472pub fn eval_swap_bang(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1474 if args.len() < 2 {
1475 return Err(EvalError::Arity {
1476 name: "swap!".into(),
1477 expected: "2+".into(),
1478 got: args.len(),
1479 });
1480 }
1481 let atom_val = args.remove(0);
1482 let f = args.remove(0);
1483 let atom = match &atom_val {
1484 Value::Atom(a) => a.clone(),
1485 Value::SharedAtom(sa) => return shared_atom_swap(sa, &f, args, env),
1486 v => {
1487 return Err(EvalError::Runtime(format!(
1488 "swap! requires an atom, got {}",
1489 v.type_name()
1490 )));
1491 }
1492 };
1493 let previous_payload = atom.get().snapshot();
1494 let old_val = previous_payload.value.clone();
1495 let mut call_args = vec![old_val.clone()];
1496 call_args.extend(args);
1497 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1498 validate_atom_value(&atom, &new_val, env)?;
1499 let new_val = atom.get().reset(new_val);
1500 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1501 check_watch_error()?;
1502 Ok(new_val)
1503}
1504
1505pub fn eval_volatile(args: Vec<Value>) -> EvalResult {
1507 if args.is_empty() {
1508 return Err(EvalError::Arity {
1509 name: "volatile!".into(),
1510 expected: "1".into(),
1511 got: 0,
1512 });
1513 }
1514 #[cfg(feature = "no-gc")]
1515 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1516 Ok(Value::Volatile(GcPtr::new(Volatile::new(
1517 args.into_iter().next().unwrap(),
1518 ))))
1519}
1520
1521pub fn eval_vreset_bang(args: Vec<Value>) -> EvalResult {
1523 if args.len() < 2 {
1524 return Err(EvalError::Arity {
1525 name: "vreset!".into(),
1526 expected: "2".into(),
1527 got: args.len(),
1528 });
1529 }
1530 let new_val = args[1].clone();
1531 match &args[0] {
1532 Value::Volatile(v) => {
1533 let new_val = v.get().reset(new_val);
1534 Ok(new_val)
1535 }
1536 other => Err(EvalError::Runtime(format!(
1537 "vreset!: expected volatile, got {}",
1538 other.type_name()
1539 ))),
1540 }
1541}
1542
1543pub fn eval_vswap_bang(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1545 if args.len() < 2 {
1546 return Err(EvalError::Arity {
1547 name: "vswap!".into(),
1548 expected: "2+".into(),
1549 got: args.len(),
1550 });
1551 }
1552 let vol_val = args.remove(0);
1553 let f = args.remove(0);
1554 match vol_val {
1555 Value::Volatile(v) => {
1556 let previous_payload = v.get().snapshot();
1557 let cur = previous_payload.value.clone();
1558 let mut call_args = vec![cur];
1559 call_args.extend(args);
1560 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1561 let new_val = v.get().reset(new_val);
1562 Ok(new_val)
1563 }
1564 other => Err(EvalError::Runtime(format!(
1565 "vswap!: expected volatile, got {}",
1566 other.type_name()
1567 ))),
1568 }
1569}
1570
1571pub fn make_delay_from_fn(
1576 f_val: &Value,
1577 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
1578 ns: std::sync::Arc<str>,
1579) -> EvalResult {
1580 let f = match f_val {
1581 Value::Fn(f) => f.get().clone(),
1582 other => {
1583 return Err(EvalError::Runtime(format!(
1584 "make-delay requires a fn, got {}",
1585 other.type_name()
1586 )));
1587 }
1588 };
1589 let thunk = ClosureThunk { f, globals, ns };
1590 Ok(Value::Delay(GcPtr::new_isolated(Delay::new(Box::new(
1591 thunk,
1592 )))))
1593}
1594
1595pub fn eval_alter_var_root(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1597 if args.len() < 2 {
1598 return Err(EvalError::Arity {
1599 name: "alter-var-root".into(),
1600 expected: "2+".into(),
1601 got: args.len(),
1602 });
1603 }
1604 let var_val = args.remove(0);
1605 let f = args.remove(0);
1606 let vp = match &var_val {
1607 Value::Var(vp) => vp.clone(),
1608 v => {
1609 return Err(EvalError::Runtime(format!(
1610 "alter-var-root: expected var, got {}",
1611 v.type_name()
1612 )));
1613 }
1614 };
1615 let old_val = vp.get().deref().unwrap_or(Value::Nil);
1616 let mut call_args = vec![old_val.clone()];
1617 call_args.extend(args);
1618 #[cfg(feature = "no-gc")]
1619 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1620 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1621 vp.get().bind(new_val.clone());
1622 fire_watches(&vp.get().watches, &var_val, &old_val, &new_val, env);
1623 check_watch_error()?;
1624 Ok(new_val)
1625}
1626
1627pub fn eval_vary_meta(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1629 if args.len() < 2 {
1630 return Err(EvalError::Arity {
1631 name: "vary-meta".into(),
1632 expected: "2+".into(),
1633 got: args.len(),
1634 });
1635 }
1636 let obj = args.remove(0);
1637 let f = args.remove(0);
1638 let current_meta = match &obj {
1639 Value::Var(vp) => vp.get().get_meta().unwrap_or(Value::Nil),
1640 _ => Value::Nil,
1641 };
1642 let mut call_args = vec![current_meta];
1643 call_args.extend(args);
1644 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1645 if let Value::Var(vp) = &obj {
1646 vp.get().set_meta(new_meta);
1647 }
1648 Ok(obj)
1649}
1650
1651pub fn eval_with_bindings_star(args: Vec<Value>, env: &mut Env) -> EvalResult {
1653 if args.len() < 2 {
1654 return Err(EvalError::Arity {
1655 name: "with-bindings*".into(),
1656 expected: "2".into(),
1657 got: args.len(),
1658 });
1659 }
1660 let mut frame: HashMap<usize, Value> = HashMap::new();
1661 if let Value::Map(m) = &args[0] {
1662 m.for_each(|k, v| {
1663 if let Value::Var(vp) = k {
1664 frame.insert(crate::env::dynamics::var_key_of(vp), v.clone());
1665 }
1666 });
1667 } else {
1668 return Err(EvalError::Runtime(
1669 "with-bindings*: first arg must be a map".into(),
1670 ));
1671 }
1672 let _guard = crate::env::dynamics::push_frame(frame);
1673 crate::env::apply::apply_value(&args[1], vec![], env)
1674}
1675
1676pub fn eval_send_to_agent(_args: Vec<Value>, _env: &mut Env) -> EvalResult {
1678 Err(EvalError::Runtime(
1679 "send/send-off: agents are not yet implemented".into(),
1680 ))
1681}
1682
1683fn ns_name_from_val(v: &Value) -> Result<String, EvalError> {
1686 match v {
1687 Value::Symbol(s) => Ok(s.get().name.as_ref().to_string()),
1688 Value::Str(s) => Ok(s.get().clone()),
1689 Value::Namespace(ns) => Ok(ns.get().name.as_ref().to_string()),
1690 Value::Keyword(k) => Ok(k.get().name.as_ref().to_string()),
1691 other => Err(EvalError::Runtime(format!(
1692 "expected symbol, string, or namespace, got {}",
1693 other.type_name()
1694 ))),
1695 }
1696}
1697
1698fn the_ns(v: &Value, env: &Env) -> Result<GcPtr<cljrs_value::Namespace>, EvalError> {
1703 if let Value::Namespace(ns) = v {
1704 return Ok(ns.clone());
1705 }
1706 let name = ns_name_from_val(v)?;
1707 let map = env.globals.namespaces.read().unwrap();
1708 match map.get(name.as_str()) {
1709 Some(ns) => Ok(ns.clone()),
1710 None => Err(EvalError::Runtime(format!("No namespace: {name} found"))),
1711 }
1712}
1713
1714fn handle_ns_interns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1717 if arg_forms.is_empty() {
1718 return Err(EvalError::Arity {
1719 name: "ns-interns".into(),
1720 expected: "1".into(),
1721 got: 0,
1722 });
1723 }
1724 let arg = eval(&arg_forms[0], env)?;
1725 let ns = the_ns(&arg, env)?;
1726 crate::builtins::builtins::builtin_ns_interns(&[Value::Namespace(ns)])
1727 .map_err(crate::env::error::value_error_to_eval_error)
1728}
1729
1730fn handle_ns_refers(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1732 if arg_forms.is_empty() {
1733 return Err(EvalError::Arity {
1734 name: "ns-refers".into(),
1735 expected: "1".into(),
1736 got: 0,
1737 });
1738 }
1739 let arg = eval(&arg_forms[0], env)?;
1740 let ns = the_ns(&arg, env)?;
1741 crate::builtins::builtins::builtin_ns_refers(&[Value::Namespace(ns)])
1742 .map_err(crate::env::error::value_error_to_eval_error)
1743}
1744
1745fn handle_ns_map(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1747 if arg_forms.is_empty() {
1748 return Err(EvalError::Arity {
1749 name: "ns-map".into(),
1750 expected: "1".into(),
1751 got: 0,
1752 });
1753 }
1754 let arg = eval(&arg_forms[0], env)?;
1755 let ns = the_ns(&arg, env)?;
1756 crate::builtins::builtins::builtin_ns_map(&[Value::Namespace(ns)])
1757 .map_err(crate::env::error::value_error_to_eval_error)
1758}
1759
1760fn handle_find_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1762 if arg_forms.is_empty() {
1763 return Err(EvalError::Arity {
1764 name: "find-ns".into(),
1765 expected: "1".into(),
1766 got: 0,
1767 });
1768 }
1769 let arg = eval(&arg_forms[0], env)?;
1770 let name = ns_name_from_val(&arg)?;
1771 let map = env.globals.namespaces.read().unwrap();
1772 match map.get(name.as_str()) {
1773 Some(ns) => Ok(Value::Namespace(ns.clone())),
1774 None => Ok(Value::Nil),
1775 }
1776}
1777
1778fn handle_all_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1780 if !arg_forms.is_empty() {
1781 let _ = eval(&arg_forms[0], env)?; }
1783 let map = env.globals.namespaces.read().unwrap();
1784 let items: Vec<Value> = map
1785 .values()
1786 .map(|ns| Value::Namespace(ns.clone()))
1787 .collect();
1788 drop(map);
1789 Ok(Value::List(cljrs_gc::GcPtr::new(
1790 cljrs_value::PersistentList::from_iter(items),
1791 )))
1792}
1793
1794fn handle_create_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1796 if arg_forms.is_empty() {
1797 return Err(EvalError::Arity {
1798 name: "create-ns".into(),
1799 expected: "1".into(),
1800 got: 0,
1801 });
1802 }
1803 let arg = eval(&arg_forms[0], env)?;
1804 let name = ns_name_from_val(&arg)?;
1805 let ns = env.globals.get_or_create_ns(&name);
1806 Ok(Value::Namespace(ns))
1807}
1808
1809fn handle_ns_aliases(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1811 if arg_forms.is_empty() {
1812 return Err(EvalError::Arity {
1813 name: "ns-aliases".into(),
1814 expected: "1".into(),
1815 got: 0,
1816 });
1817 }
1818 let ns_val = eval(&arg_forms[0], env)?;
1819 let ns_name = ns_name_from_val(&ns_val)?;
1820 let map = env.globals.namespaces.read().unwrap();
1821 let ns = match map.get(ns_name.as_str()) {
1822 Some(ns) => ns.clone(),
1823 None => return Ok(Value::Map(cljrs_value::MapValue::empty())),
1824 };
1825 let aliases = ns.get().aliases.lock().unwrap().clone();
1826 drop(map);
1827 let mut m = cljrs_value::MapValue::empty();
1828 for (alias, full_ns_name) in &aliases {
1829 let sym = Value::symbol(cljrs_value::Symbol::simple(alias.clone()));
1830 let nsmap = env.globals.namespaces.read().unwrap();
1831 if let Some(target_ns) = nsmap.get(full_ns_name.as_ref()) {
1832 m = m.assoc(sym, Value::Namespace(target_ns.clone()));
1833 }
1834 }
1835 Ok(Value::Map(m))
1836}
1837
1838fn handle_remove_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1840 if arg_forms.is_empty() {
1841 return Err(EvalError::Arity {
1842 name: "remove-ns".into(),
1843 expected: "1".into(),
1844 got: 0,
1845 });
1846 }
1847 let arg = eval(&arg_forms[0], env)?;
1848 let name = ns_name_from_val(&arg)?;
1849 env.globals
1850 .namespaces
1851 .write()
1852 .unwrap()
1853 .remove(name.as_str());
1854 Ok(Value::Nil)
1855}
1856
1857fn handle_alter_meta(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1859 if arg_forms.len() < 2 {
1860 return Err(EvalError::Arity {
1861 name: "alter-meta!".into(),
1862 expected: "2+".into(),
1863 got: arg_forms.len(),
1864 });
1865 }
1866 let obj = eval(&arg_forms[0], env)?;
1867 let f = eval(&arg_forms[1], env)?;
1868 let extra: Vec<Value> = arg_forms[2..]
1869 .iter()
1870 .map(|form| eval(form, env))
1871 .collect::<EvalResult<_>>()?;
1872
1873 let current_meta = match &obj {
1874 Value::Var(vp) => vp
1875 .get()
1876 .get_meta()
1877 .unwrap_or(Value::Map(cljrs_value::MapValue::empty())),
1878 _ => Value::Map(cljrs_value::MapValue::empty()),
1879 };
1880 let mut call_args = vec![current_meta];
1881 call_args.extend(extra);
1882 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1883 if let Value::Var(vp) = &obj {
1884 vp.get().set_meta(new_meta.clone());
1885 }
1886 Ok(new_meta)
1887}
1888
1889fn handle_ns_resolve(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1891 if arg_forms.len() < 2 {
1892 return Err(EvalError::Arity {
1893 name: "ns-resolve".into(),
1894 expected: "2".into(),
1895 got: arg_forms.len(),
1896 });
1897 }
1898 let ns_arg = eval(&arg_forms[0], env)?;
1899 let sym_arg = eval(&arg_forms[1], env)?;
1900 let ns_name = ns_name_from_val(&ns_arg)?;
1901 let sym_name = match &sym_arg {
1902 Value::Symbol(s) => s.get().name.as_ref().to_string(),
1903 Value::Str(s) => s.get().clone(),
1904 other => {
1905 return Err(EvalError::Runtime(format!(
1906 "ns-resolve: second arg must be symbol or string, got {}",
1907 other.type_name()
1908 )));
1909 }
1910 };
1911 match env.globals.lookup_var(&ns_name, &sym_name) {
1912 Some(var_ptr) => Ok(Value::Var(var_ptr)),
1913 None => Ok(Value::Nil),
1914 }
1915}
1916
1917fn resolve_current_ns(env: &Env) -> Arc<str> {
1921 if let Some(var) = env.globals.lookup_var("clojure.core", "*ns*") {
1922 let val = crate::env::dynamics::deref_var(&var);
1923 if let Some(Value::Namespace(ns_ptr)) = val {
1924 return ns_ptr.get().name.clone();
1925 }
1926 }
1927 env.current_ns.clone()
1928}
1929
1930fn handle_resolve(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1932 if arg_forms.len() != 1 {
1933 return Err(EvalError::Arity {
1934 name: "resolve".into(),
1935 expected: "1".into(),
1936 got: arg_forms.len(),
1937 });
1938 }
1939 let resolve_ns = resolve_current_ns(env);
1940 let sym_arg = eval(&arg_forms[0], env)?;
1941 let sym_name = match &sym_arg {
1942 Value::Symbol(s) => {
1943 let sym = s.get();
1944 if let Some(ns) = &sym.namespace {
1946 let full_ns = env.globals.resolve_ns_part_in(&resolve_ns, ns.as_ref());
1949 return Ok(
1950 match env.globals.lookup_var_in_ns(&full_ns, sym.name.as_ref()) {
1951 Some(var_ptr) => Value::Var(var_ptr),
1952 None => Value::Nil,
1953 },
1954 );
1955 }
1956 sym.name.as_ref().to_string()
1957 }
1958 Value::Str(s) => s.get().clone(),
1959 other => {
1960 return Err(EvalError::Runtime(format!(
1961 "resolve: arg must be symbol or string, got {}",
1962 other.type_name()
1963 )));
1964 }
1965 };
1966 Ok(match env.globals.lookup_var_in_ns(&resolve_ns, &sym_name) {
1967 Some(var_ptr) => Value::Var(var_ptr),
1968 None => Value::Nil,
1969 })
1970}
1971
1972fn handle_intern(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1973 if arg_forms.len() < 2 || arg_forms.len() > 3 {
1974 return Err(EvalError::Runtime("intern expects 2 or 3 arguments".into()));
1975 }
1976 let ns_val = eval(&arg_forms[0], env)?;
1977 let ns_name: Arc<str> = match &ns_val {
1978 Value::Symbol(s) => s.get().name.clone(),
1979 Value::Namespace(ns) => ns.get().name.clone(),
1980 other => {
1981 return Err(EvalError::Runtime(format!(
1982 "intern: first arg must be namespace or symbol, got {}",
1983 other.type_name()
1984 )));
1985 }
1986 };
1987 let var_name: Arc<str> = match eval(&arg_forms[1], env)? {
1988 Value::Symbol(s) => s.get().name.clone(),
1989 other => {
1990 return Err(EvalError::Runtime(format!(
1991 "intern: second arg must be symbol, got {}",
1992 other.type_name()
1993 )));
1994 }
1995 };
1996 let ns = {
1998 let map = env.globals.namespaces.read().unwrap();
1999 map.get(ns_name.as_ref()).cloned()
2000 };
2001 let ns = ns.ok_or_else(|| EvalError::Runtime(format!("No namespace: {ns_name} found")))?;
2002 let var = if arg_forms.len() == 3 {
2003 #[cfg(feature = "no-gc")]
2006 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
2007 let val = eval(&arg_forms[2], env)?;
2008 let mut interns = ns.get().interns.lock().unwrap();
2009 if let Some(var) = interns.get(&var_name) {
2010 var.get().bind(val);
2011 var.clone()
2012 } else {
2013 let var =
2014 cljrs_gc::GcPtr::new(cljrs_value::Var::new(ns_name.clone(), var_name.clone()));
2015 var.get().bind(val);
2016 interns.insert(var_name, var.clone());
2017 var
2018 }
2019 } else {
2020 let mut interns = ns.get().interns.lock().unwrap();
2021 if let Some(var) = interns.get(&var_name) {
2022 var.clone()
2023 } else {
2024 let var =
2025 cljrs_gc::GcPtr::new(cljrs_value::Var::new(ns_name.clone(), var_name.clone()));
2026 interns.insert(var_name, var.clone());
2027 var
2028 }
2029 };
2030 Ok(Value::Var(var))
2031}
2032
2033fn handle_bound_fn_star(arg_forms: &[Form], env: &mut Env) -> EvalResult {
2038 if arg_forms.len() != 1 {
2039 return Err(EvalError::Arity {
2040 name: "bound-fn*".into(),
2041 expected: "1".into(),
2042 got: arg_forms.len(),
2043 });
2044 }
2045 let f = eval(&arg_forms[0], env)?;
2046 let frames = crate::env::dynamics::capture_current();
2048 let mut merged = std::collections::HashMap::new();
2049 for frame in &frames {
2050 merged.extend(frame.iter().map(|(k, v)| (*k, v.clone())));
2051 }
2052 Ok(Value::BoundFn(cljrs_gc::GcPtr::new(cljrs_value::BoundFn {
2053 wrapped: f,
2054 captured_bindings: merged,
2055 })))
2056}
2057
2058fn trace_saved_watch_error(error: &Option<EvalError>, visitor: &mut cljrs_gc::MarkVisitor) {
2059 use cljrs_gc::Trace;
2060 match error {
2061 Some(EvalError::Thrown(value)) => value.trace(visitor),
2062 Some(EvalError::Recur(values)) => {
2063 for value in values {
2064 value.trace(visitor);
2065 }
2066 }
2067 _ => {}
2068 }
2069}