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;
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 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}
61cljrs_gc::mutator_slot!("cljrs-runtime/WATCH_ERROR", refcell WATCH_ERROR: Option<EvalError>, trace trace_saved_watch_error);
62
63fn check_watch_error() -> EvalResult<()> {
65 WATCH_ERROR.with(|cell| {
66 if let Some(e) = cell.borrow_mut().take() {
67 Err(e)
68 } else {
69 Ok(())
70 }
71 })
72}
73
74#[derive(Debug)]
78pub struct ClosureThunk {
79 pub f: CljxFn,
80 pub globals: std::sync::Arc<crate::env::env::GlobalEnv>,
81 pub ns: std::sync::Arc<str>,
82}
83
84struct CallableValueThunk {
90 callee: Value,
91 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
92 ns: std::sync::Arc<str>,
93}
94
95impl std::fmt::Debug for CallableValueThunk {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.debug_struct("CallableValueThunk")
98 .field("callee", &self.callee.type_name())
99 .field("ns", &self.ns)
100 .finish()
101 }
102}
103
104impl cljrs_gc::Trace for CallableValueThunk {
105 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
106 self.callee.trace(visitor);
107 }
108}
109
110impl Thunk for CallableValueThunk {
111 fn force(&self) -> Result<Value, String> {
112 let mut env = Env::new(self.globals.clone(), &self.ns);
113 crate::env::apply::apply_value(&self.callee, Vec::new(), &mut env)
114 .map_err(|e| format!("{e}"))
115 }
116}
117
118pub fn make_lazy_seq_from_fn(
131 f_val: &Value,
132 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
133 ns: std::sync::Arc<str>,
134) -> EvalResult {
135 let unwrapped = f_val.unwrap_meta();
136 if let Value::Fn(g) = unwrapped {
137 let thunk = ClosureThunk {
138 f: g.get().clone(),
139 globals,
140 ns,
141 };
142 return Ok(Value::LazySeq(GcPtr::new(LazySeq::new(Box::new(thunk)))));
143 }
144 if unwrapped.type_name() != "fn" {
147 return Err(EvalError::Runtime(format!(
148 "make-lazy-seq requires a fn, got {}",
149 unwrapped.type_name(),
150 )));
151 }
152 let thunk = CallableValueThunk {
153 callee: unwrapped.clone(),
154 globals,
155 ns,
156 };
157 Ok(Value::LazySeq(GcPtr::new(LazySeq::new(Box::new(thunk)))))
158}
159
160impl cljrs_gc::Trace for ClosureThunk {
161 fn trace(&self, visitor: &mut cljrs_gc::MarkVisitor) {
162 self.f.trace(visitor);
163 }
164}
165
166impl Thunk for ClosureThunk {
167 fn force(&self) -> Result<Value, String> {
168 let _closed_root = crate::env::gc_roots::root_values(&self.f.closed_over_vals);
172 let mut env = Env::with_closure(self.globals.clone(), &self.ns, &self.f);
173 call_cljrs_fn(&self.f, &[], &mut env).map_err(|e| format!("{e}"))
174 }
175}
176
177pub fn is_form_intercepted(name: &str) -> bool {
184 matches!(
185 name,
186 "apply"
187 | "atom"
188 | "reset!"
189 | "swap!"
190 | "volatile!"
191 | "vreset!"
192 | "agent"
193 | "make-lazy-seq"
194 | "make-delay"
195 | "vswap!"
196 | "send"
197 | "send-off"
198 | "with-bindings*"
199 | "alter-var-root"
200 | "vary-meta"
201 | "eval"
202 | "find-ns"
203 | "the-ns"
204 | "ns-interns"
205 | "ns-publics"
206 | "ns-refers"
207 | "ns-map"
208 | "all-ns"
209 | "create-ns"
210 | "ns-aliases"
211 | "remove-ns"
212 | "alter-meta!"
213 | "ns-resolve"
214 | "resolve"
215 | "intern"
216 | "bound-fn*"
217 )
218}
219
220pub fn eval_call(func_form: &Form, arg_forms: &[Form], env: &mut Env) -> EvalResult {
228 if let FormKind::Symbol(s) = &func_form.kind
230 && is_method_sugar(s)
231 {
232 return eval_method_call(&s[1..], arg_forms, env);
233 }
234
235 let callee = eval(func_form, env)?;
237
238 let _callee_root = crate::env::gc_roots::root_value(&callee);
240
241 if let Value::Macro(mfn) = &callee {
243 let expanded = macro_apply(mfn.get(), func_form, arg_forms, env)?;
244 return eval(&expanded, env);
245 }
246
247 if let Value::NativeFunction(nf) = &callee {
249 crate::env::policy::check_native(&nf.get().name)?;
250 match nf.get().name.as_ref() {
251 "apply" => return handle_apply_call(arg_forms, env),
252 "atom" => return handle_atom_call(arg_forms, env),
253 "reset!" => return handle_reset_bang(arg_forms, env),
254 "swap!" => return handle_swap_call(arg_forms, env),
255 "volatile!" => return handle_volatile(arg_forms, env),
256 "vreset!" => return handle_vreset(arg_forms, env),
257 "agent" => return handle_agent_call(arg_forms, env),
258 "make-lazy-seq" => return handle_make_lazy_seq(arg_forms, env),
259 "make-delay" => return handle_make_delay(arg_forms, env),
260 "vswap!" => return handle_vswap(arg_forms, env),
261 "send" | "send-off" => return handle_send(arg_forms, env),
262 "with-bindings*" => return handle_with_bindings(arg_forms, env),
263 "alter-var-root" => return handle_alter_var_root(arg_forms, env),
264 "vary-meta" => return handle_vary_meta(arg_forms, env),
265 "eval" => return handle_eval(arg_forms, env),
266 "find-ns" | "the-ns" => return handle_find_ns(arg_forms, env),
267 "ns-interns" | "ns-publics" => return handle_ns_interns(arg_forms, env),
268 "ns-refers" => return handle_ns_refers(arg_forms, env),
269 "ns-map" => return handle_ns_map(arg_forms, env),
270 "all-ns" => return handle_all_ns(arg_forms, env),
271 "create-ns" => return handle_create_ns(arg_forms, env),
272 "ns-aliases" => return handle_ns_aliases(arg_forms, env),
273 "remove-ns" => return handle_remove_ns(arg_forms, env),
274 "alter-meta!" => return handle_alter_meta(arg_forms, env),
275 "ns-resolve" => return handle_ns_resolve(arg_forms, env),
276 "resolve" => return handle_resolve(arg_forms, env),
277 "intern" => return handle_intern(arg_forms, env),
278 "bound-fn*" => return handle_bound_fn_star(arg_forms, env),
279 _ => {}
280 }
281 }
282
283 let mut args: Vec<Value> = Vec::with_capacity(arg_forms.len());
286 for f in arg_forms {
287 let _args_root = crate::env::gc_roots::root_values(&args);
289 args.push(eval(f, env)?);
290 }
291
292 if let Value::Fn(f) = &callee {
297 if let Some(fut) = crate::env::apply::dispatch_if_async(&callee, &args, env) {
300 return Ok(fut);
301 }
302 let _args_root = crate::env::gc_roots::root_values(&args);
303 crate::env::gc_roots::gc_safepoint(env)?;
304 return env.call_cljrs_fn(f.get(), &args);
305 }
306
307 crate::env::apply::apply_value(&callee, args, env)
308}
309
310fn eval_method_call(method: &str, arg_forms: &[Form], env: &mut Env) -> EvalResult {
320 if arg_forms.is_empty() {
321 return Err(EvalError::Runtime(format!(
322 ".{method} requires a target object"
323 )));
324 }
325 let target = eval(&arg_forms[0], env)?;
326 let args: Vec<Value> = arg_forms[1..]
327 .iter()
328 .map(|f| eval(f, env))
329 .collect::<EvalResult<_>>()?;
330
331 dispatch_method(method, &target, &args)
332}
333
334pub use cljrs_ir::lower::is_method_sugar;
339
340pub fn dispatch_method(method: &str, target: &Value, args: &[Value]) -> EvalResult {
346 match target {
347 Value::Str(s) => dispatch_string_method(method, s.get(), args),
348 Value::Vector(v) => dispatch_vector_method(method, v, args),
349 Value::List(_) | Value::Cons(_) | Value::LazySeq(_) => {
350 dispatch_seq_method(method, target, args)
351 }
352 Value::TypeInstance(ti) => {
353 if ti.get().type_tag.as_ref() == "java.util.Date"
354 && method == "getTime"
355 && args.is_empty()
356 {
357 let key = Value::keyword(cljrs_value::Keyword::simple("millis"));
358 return Ok(ti.get().fields.get(&key).unwrap_or(Value::Nil));
359 }
360 if let Some(field) = method.strip_prefix('-') {
364 let key = Value::keyword(cljrs_value::Keyword::simple(field));
365 let inst = ti.get();
366 if let Some(atom) = &inst.mutable
369 && let Value::Map(m) = atom.get().deref()
370 && let Some(v) = m.get(&key)
371 {
372 return Ok(v);
373 }
374 Ok(inst.fields.get(&key).unwrap_or(Value::Nil))
375 } else {
376 Err(EvalError::Runtime(format!(
377 ".{method} not supported on {} (only .-field access is)",
378 target.type_name()
379 )))
380 }
381 }
382 _ => Err(EvalError::Runtime(format!(
383 ".{method} not supported on type {}",
384 target.type_name()
385 ))),
386 }
387}
388
389fn dispatch_string_method(method: &str, s: &str, args: &[Value]) -> EvalResult {
390 match method {
391 "indexOf" => {
392 let needle = match args.first() {
393 Some(Value::Str(s)) => s.get().to_string(),
394 Some(Value::Char(c)) => c.to_string(),
395 Some(v) => {
396 return Err(EvalError::Runtime(format!(
397 ".indexOf expects string or char argument, got {}",
398 v.type_name()
399 )));
400 }
401 None => return Err(EvalError::Runtime(".indexOf requires an argument".into())),
402 };
403 match s.find(&needle) {
404 Some(pos) => Ok(Value::Long(pos as i64)),
405 None => Ok(Value::Long(-1)),
406 }
407 }
408 "lastIndexOf" => {
409 let needle = match args.first() {
410 Some(Value::Str(s)) => s.get().to_string(),
411 Some(Value::Char(c)) => c.to_string(),
412 _ => {
413 return Err(EvalError::Runtime(
414 ".lastIndexOf requires a string or char argument".into(),
415 ));
416 }
417 };
418 match s.rfind(&needle) {
419 Some(pos) => Ok(Value::Long(pos as i64)),
420 None => Ok(Value::Long(-1)),
421 }
422 }
423 "startsWith" => {
424 let prefix = require_str_arg(args, ".startsWith")?;
425 Ok(Value::Bool(s.starts_with(&prefix)))
426 }
427 "endsWith" => {
428 let suffix = require_str_arg(args, ".endsWith")?;
429 Ok(Value::Bool(s.ends_with(&suffix)))
430 }
431 "contains" => {
432 let sub = require_str_arg(args, ".contains")?;
433 Ok(Value::Bool(s.contains(&sub)))
434 }
435 "length" => Ok(Value::Long(s.len() as i64)),
436 "isEmpty" => Ok(Value::Bool(s.is_empty())),
437 "charAt" => {
438 let idx = require_long_arg(args, ".charAt")? as usize;
439 s.chars()
440 .nth(idx)
441 .map(Value::Char)
442 .ok_or_else(|| EvalError::Runtime(format!(".charAt index {idx} out of bounds")))
443 }
444 "substring" => {
445 let start = require_long_arg(args, ".substring")? as usize;
446 let end = args
447 .get(1)
448 .map(|v| match v {
449 Value::Long(n) => Ok(*n as usize),
450 _ => Err(EvalError::Runtime(
451 ".substring end must be an integer".into(),
452 )),
453 })
454 .transpose()?;
455 let result = match end {
456 Some(e) => &s[start..e.min(s.len())],
457 None => &s[start..],
458 };
459 Ok(Value::Str(GcPtr::new(result.to_string())))
460 }
461 "toUpperCase" => Ok(Value::Str(GcPtr::new(s.to_uppercase()))),
462 "toLowerCase" => Ok(Value::Str(GcPtr::new(s.to_lowercase()))),
463 "trim" => Ok(Value::Str(GcPtr::new(s.trim().to_string()))),
464 "replace" => {
465 let from = require_str_arg(args, ".replace")?;
466 let to = match args.get(1) {
467 Some(Value::Str(s)) => s.get().to_string(),
468 Some(Value::Char(c)) => c.to_string(),
469 _ => {
470 return Err(EvalError::Runtime(
471 ".replace requires two string arguments".into(),
472 ));
473 }
474 };
475 Ok(Value::Str(GcPtr::new(s.replace(&from, &to))))
476 }
477 "split" => {
478 let sep = require_str_arg(args, ".split")?;
479 let parts: Vec<Value> = s
480 .split(&sep)
481 .map(|p| Value::Str(GcPtr::new(p.to_string())))
482 .collect();
483 Ok(Value::Vector(GcPtr::new(
484 cljrs_value::PersistentVector::from_iter(parts),
485 )))
486 }
487 _ => Err(EvalError::Runtime(format!(
488 ".{method} not supported on String"
489 ))),
490 }
491}
492
493fn dispatch_vector_method(
494 method: &str,
495 v: &GcPtr<cljrs_value::PersistentVector>,
496 args: &[Value],
497) -> EvalResult {
498 match method {
499 "indexOf" => {
500 let needle = args
501 .first()
502 .ok_or_else(|| EvalError::Runtime(".indexOf requires an argument".into()))?;
503 for (i, item) in v.get().iter().enumerate() {
504 if item == needle {
505 return Ok(Value::Long(i as i64));
506 }
507 }
508 Ok(Value::Long(-1))
509 }
510 "size" | "count" => Ok(Value::Long(v.get().count() as i64)),
511 _ => Err(EvalError::Runtime(format!(
512 ".{method} not supported on Vector"
513 ))),
514 }
515}
516
517fn dispatch_seq_method(method: &str, target: &Value, args: &[Value]) -> EvalResult {
518 match method {
519 "indexOf" => {
520 let needle = args
521 .first()
522 .ok_or_else(|| EvalError::Runtime(".indexOf requires an argument".into()))?;
523 let items = crate::interp::destructure::value_to_seq_vec(target)
524 .map_err(crate::env::error::value_error_to_eval_error)?;
525 for (i, item) in items.iter().enumerate() {
526 if item == needle {
527 return Ok(Value::Long(i as i64));
528 }
529 }
530 Ok(Value::Long(-1))
531 }
532 _ => Err(EvalError::Runtime(format!(
533 ".{method} not supported on {}",
534 target.type_name()
535 ))),
536 }
537}
538
539fn require_str_arg(args: &[Value], method: &str) -> Result<String, EvalError> {
540 match args.first() {
541 Some(Value::Str(s)) => Ok(s.get().to_string()),
542 Some(Value::Char(c)) => Ok(c.to_string()),
543 _ => Err(EvalError::Runtime(format!(
544 "{method} requires a string argument"
545 ))),
546 }
547}
548
549fn require_long_arg(args: &[Value], method: &str) -> Result<i64, EvalError> {
550 match args.first() {
551 Some(Value::Long(n)) => Ok(*n),
552 _ => Err(EvalError::Runtime(format!(
553 "{method} requires an integer argument"
554 ))),
555 }
556}
557
558pub fn resolve_type_tag(sym: &str) -> Arc<str> {
561 Arc::from(sym)
562}
563
564pub fn call_cljrs_fn(f: &CljxFn, args: &[Value], caller_env: &mut Env) -> EvalResult {
566 let arity = select_arity(f, args.len())?;
567
568 let _caller_root = crate::env::gc_roots::push_env_root(caller_env);
571
572 let mut env = Env::with_closure(caller_env.globals.clone(), &f.defining_ns, f);
575
576 let mut current_args = Vec::from(args);
577 loop {
578 let _args_root = crate::env::gc_roots::root_values(¤t_args);
581
582 crate::env::gc_roots::gc_safepoint(&env)?;
584
585 env.push_frame();
586
587 #[cfg(not(feature = "no-gc"))]
597 let _call_frame = cljrs_gc::push_alloc_frame();
598
599 if let Some(ref name) = f.name {
608 let self_val = if let Some(ref p) = f.self_ptr {
609 Value::Fn(p.clone())
610 } else {
611 Value::Fn(GcPtr::new(f.clone()))
612 };
613 env.bind(name.clone(), self_val);
614 }
615
616 bind_fn_params(arity, ¤t_args, &mut env)?;
618
619 #[cfg(not(feature = "no-gc"))]
624 let result = eval_body_recur_fn(&arity.body, &mut env);
625 #[cfg(feature = "no-gc")]
626 let result = {
627 let mut scratch = cljrs_gc::alloc_ctx::ScratchGuard::new();
628 eval_body_with_scratch(&arity.body, &mut scratch, &mut env)
630 };
631 env.pop_frame();
632 match result {
636 Ok(v) => return Ok(v),
637 Err(EvalError::Recur(new_args)) => {
638 if arity.rest_param.is_some() {
643 let n = arity.params.len();
644 if new_args.len() == n + 1 {
645 let mut flat = new_args[..n].to_vec();
646 let rest_val = &new_args[n];
648 match rest_val {
649 Value::Nil => {} _ => {
651 let rest_items = value_to_seq_vec(rest_val)
652 .map_err(crate::env::error::value_error_to_eval_error)?;
653 flat.extend(rest_items);
654 }
655 }
656 current_args = flat;
657 } else {
658 current_args = new_args;
659 }
660 } else {
661 current_args = new_args;
662 }
663 }
664 Err(e) => return Err(e),
665 }
666 }
667}
668
669pub fn bind_fn_params(arity: &CljxFnArity, args: &[Value], env: &mut Env) -> EvalResult<()> {
672 bind_fn_params_impl(arity, args, env, true)
673}
674
675pub fn bind_fn_params_positional(
686 arity: &CljxFnArity,
687 args: &[Value],
688 env: &mut Env,
689) -> EvalResult<()> {
690 bind_fn_params_impl(arity, args, env, false)
691}
692
693fn bind_fn_params_impl(
694 arity: &CljxFnArity,
695 args: &[Value],
696 env: &mut Env,
697 destructure: bool,
698) -> EvalResult<()> {
699 let n = arity.params.len();
700 for (i, name) in arity.params.iter().enumerate() {
702 let val = args.get(i).cloned().unwrap_or(Value::Nil);
703 env.bind(name.clone(), val);
704 }
705 if let Some(ref rest) = arity.rest_param {
707 let rest_items = args[n..].to_vec();
708 let rest_val = if rest_items.is_empty() {
709 Value::Nil
710 } else {
711 Value::List(GcPtr::new(PersistentList::from_iter(rest_items)))
712 };
713 env.bind(rest.clone(), rest_val.clone());
714 if destructure && let Some(ref pattern) = arity.destructure_rest {
716 let destructure_val = if pattern.is_kwargs_rest_pattern() {
720 let items = value_to_seq_vec(&rest_val)
721 .map_err(crate::env::error::value_error_to_eval_error)?;
722 Value::from_kwargs_rest(items).map_err(value_error_to_eval_error)?
723 } else {
724 rest_val
725 };
726 crate::interp::destructure::bind_pattern(pattern, destructure_val, env)?;
727 }
728 }
729 if destructure {
731 for (idx, pattern) in &arity.destructure_params {
732 let val = args.get(*idx).cloned().unwrap_or(Value::Nil);
733 crate::interp::destructure::bind_pattern(pattern, val, env)?;
734 }
735 }
736 Ok(())
737}
738
739#[cfg(not(feature = "no-gc"))]
741fn eval_body_recur_fn(body: &[cljrs_reader::Form], env: &mut Env) -> EvalResult {
742 let mut result = Value::Nil;
743 for form in body {
744 result = eval(form, env)?;
745 }
746 Ok(result)
747}
748
749#[cfg(feature = "no-gc")]
753fn eval_body_with_scratch(
754 body: &[cljrs_reader::Form],
755 scratch: &mut cljrs_gc::alloc_ctx::ScratchGuard,
756 env: &mut Env,
757) -> EvalResult {
758 if body.is_empty() {
759 scratch.pop_for_return();
760 return Ok(Value::Nil);
761 }
762 for form in &body[..body.len() - 1] {
764 eval(form, env)?;
765 }
766 scratch.pop_for_return();
768 eval(&body[body.len() - 1], env)
769}
770
771pub fn select_arity(f: &CljxFn, argc: usize) -> EvalResult<&CljxFnArity> {
773 let name = f.name.as_deref().unwrap_or("fn");
774 for arity in &f.arities {
776 if arity.rest_param.is_none() && arity.params.len() == argc {
777 return Ok(arity);
778 }
779 }
780 for arity in &f.arities {
782 if arity.rest_param.is_some() && argc >= arity.params.len() {
783 return Ok(arity);
784 }
785 }
786 let implicit = if f.is_macro { IMPLICIT_MACRO_ARGS } else { 0 };
791 let expected: Vec<String> = f
792 .arities
793 .iter()
794 .map(|a| {
795 let fixed = a.params.len().saturating_sub(implicit);
796 if a.rest_param.is_some() {
797 format!("{fixed}+")
798 } else {
799 fixed.to_string()
800 }
801 })
802 .collect();
803 Err(EvalError::Arity {
804 name: name.to_string(),
805 expected: expected.join(" or "),
806 got: argc.saturating_sub(implicit),
807 })
808}
809
810const IMPLICIT_MACRO_ARGS: usize = 2;
812
813fn macro_apply(
820 mfn: &CljxFn,
821 func_form: &Form,
822 arg_forms: &[Form],
823 env: &mut Env,
824) -> EvalResult<Form> {
825 let resolved_args: Vec<Form> = arg_forms
830 .iter()
831 .map(|f| crate::builtins::form::resolve_auto_forms(f, env))
832 .collect::<EvalResult<Vec<Form>>>()?;
833
834 let form_val = {
836 let mut items = vec![form_to_value(func_form)?];
837 for f in &resolved_args {
838 items.push(form_to_value(f)?);
839 }
840 Value::List(GcPtr::new(PersistentList::from_iter(items)))
841 };
842
843 let env_val = {
845 let (names, vals) = env.all_local_bindings();
846 let mut m = MapValue::empty();
847 for (name, val) in names.iter().zip(vals.iter()) {
848 m = m.assoc(Value::symbol(Symbol::simple(name.as_ref())), val.clone());
849 }
850 Value::Map(m)
851 };
852
853 let mut args = vec![form_val, env_val];
855 for f in &resolved_args {
856 args.push(form_to_value(f)?);
857 }
858
859 let expanded_val = call_cljrs_fn(mfn, args.as_ref(), env)?;
860 let _expanded_root = crate::env::gc_roots::root_value(&expanded_val);
863 let dummy_span = cljrs_types::span::Span::new(Arc::new("<macro>".to_string()), 0, 0, 1, 1);
864 crate::interp::macros::value_to_form(&expanded_val, dummy_span)
865}
866
867fn handle_apply_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
869 let mut evaled: Vec<Value> = Vec::with_capacity(arg_forms.len());
870 for f in arg_forms {
871 let _root = crate::env::gc_roots::root_values(&evaled);
872 evaled.push(eval(f, env)?);
873 }
874
875 if evaled.len() < 2 {
876 return Err(EvalError::Arity {
877 name: "apply".into(),
878 expected: "2+".into(),
879 got: evaled.len(),
880 });
881 }
882
883 let f = evaled.remove(0);
884 let last = evaled.pop().unwrap();
885 let _f_root = crate::env::gc_roots::root_value(&f);
887 let _last_root = crate::env::gc_roots::root_value(&last);
888 let _evaled_root = crate::env::gc_roots::root_values(&evaled);
889 let spread =
891 crate::builtins::builtins::value_to_seq(&last).map_err(value_error_to_eval_error)?;
892 evaled.extend(spread);
893 crate::env::apply::apply_value(&f, evaled, env)
894}
895
896pub fn handle_make_lazy_seq(arg_forms: &[Form], env: &mut Env) -> EvalResult {
898 if arg_forms.len() != 1 {
899 return Err(EvalError::Arity {
900 name: "make-lazy-seq".into(),
901 expected: "1".into(),
902 got: arg_forms.len(),
903 });
904 }
905 let f_val = eval(&arg_forms[0], env)?;
906 let f = match f_val {
907 Value::Fn(f) => f.get().clone(),
908 other => {
909 return Err(EvalError::Runtime(format!(
910 "make-lazy-seq requires a fn, got {}",
911 other.type_name()
912 )));
913 }
914 };
915 let thunk = ClosureThunk {
916 f,
917 globals: env.globals.clone(),
918 ns: env.current_ns.clone(),
919 };
920 Ok(Value::LazySeq(GcPtr::new(LazySeq::new(Box::new(thunk)))))
921}
922
923fn handle_make_delay(arg_forms: &[Form], env: &mut Env) -> EvalResult {
925 if arg_forms.len() != 1 {
926 return Err(EvalError::Arity {
927 name: "make-delay".into(),
928 expected: "1".into(),
929 got: arg_forms.len(),
930 });
931 }
932 let f_val = eval(&arg_forms[0], env)?;
933 let f = match f_val {
934 Value::Fn(f) => f.get().clone(),
935 other => {
936 return Err(EvalError::Runtime(format!(
937 "make-delay requires a fn, got {}",
938 other.type_name()
939 )));
940 }
941 };
942 let thunk = ClosureThunk {
943 f,
944 globals: env.globals.clone(),
945 ns: env.current_ns.clone(),
946 };
947 Ok(Value::Delay(GcPtr::new(Delay::new(Box::new(thunk)))))
948}
949
950fn handle_vswap(arg_forms: &[Form], env: &mut Env) -> EvalResult {
952 if arg_forms.len() < 2 {
953 return Err(EvalError::Arity {
954 name: "vswap!".into(),
955 expected: "2+".into(),
956 got: arg_forms.len(),
957 });
958 }
959 let vol_val = eval(&arg_forms[0], env)?;
960 let f = eval(&arg_forms[1], env)?;
961 let extra: Vec<Value> = arg_forms[2..]
962 .iter()
963 .map(|a| eval(a, env))
964 .collect::<EvalResult<_>>()?;
965
966 match vol_val {
967 Value::Volatile(v) => {
968 let cur = v.get().deref();
969 let mut call_args = vec![cur];
970 call_args.extend(extra);
971 #[cfg(feature = "no-gc")]
974 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
975 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
976 v.get().reset(new_val.clone());
977 Ok(new_val)
978 }
979 other => Err(EvalError::Runtime(format!(
980 "vswap!: expected volatile, got {}",
981 other.type_name()
982 ))),
983 }
984}
985
986fn handle_volatile(arg_forms: &[Form], env: &mut Env) -> EvalResult {
990 if arg_forms.is_empty() {
991 return Err(EvalError::Arity {
992 name: "volatile!".into(),
993 expected: "1".into(),
994 got: 0,
995 });
996 }
997 #[cfg(feature = "no-gc")]
1000 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1001 let initial = eval(&arg_forms[0], env)?;
1002 Ok(Value::Volatile(GcPtr::new(Volatile::new(initial))))
1003}
1004
1005fn handle_vreset(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1009 if arg_forms.len() < 2 {
1010 return Err(EvalError::Arity {
1011 name: "vreset!".into(),
1012 expected: "2".into(),
1013 got: arg_forms.len(),
1014 });
1015 }
1016 let vol_val = eval(&arg_forms[0], env)?;
1017 #[cfg(feature = "no-gc")]
1020 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1021 let new_val = eval(&arg_forms[1], env)?;
1022 match &vol_val {
1023 Value::Volatile(v) => {
1024 v.get().reset(new_val.clone());
1025 Ok(new_val)
1026 }
1027 other => Err(EvalError::Runtime(format!(
1028 "vreset!: expected volatile, got {}",
1029 other.type_name()
1030 ))),
1031 }
1032}
1033
1034fn handle_agent_call(_arg_forms: &[Form], _env: &mut Env) -> EvalResult {
1038 Err(EvalError::Runtime("agent is not yet implemented".into()))
1039}
1040
1041fn handle_send(_arg_forms: &[Form], _env: &mut Env) -> EvalResult {
1043 Err(EvalError::Runtime(
1044 "send/send-off: agents are not yet implemented".into(),
1045 ))
1046}
1047
1048fn handle_atom_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1052 if arg_forms.is_empty() {
1053 return Err(EvalError::Arity {
1054 name: "atom".into(),
1055 expected: "1+".into(),
1056 got: 0,
1057 });
1058 }
1059 #[cfg(feature = "no-gc")]
1062 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1063 let initial = eval(&arg_forms[0], env)?;
1064
1065 let options: Vec<Value> = arg_forms[1..]
1067 .iter()
1068 .map(|f| eval(f, env))
1069 .collect::<EvalResult<_>>()?;
1070
1071 let mut meta_opt: Option<Value> = None;
1072 let mut validator_opt: Option<Value> = None;
1073 let mut i = 0;
1074 while i + 1 < options.len() {
1075 match &options[i] {
1076 Value::Keyword(k) if k.get().name.as_ref() == "meta" => {
1077 meta_opt = Some(options[i + 1].clone());
1078 i += 2;
1079 }
1080 Value::Keyword(k) if k.get().name.as_ref() == "validator" => {
1081 let vf = options[i + 1].clone();
1082 validator_opt = if vf == Value::Nil { None } else { Some(vf) };
1083 i += 2;
1084 }
1085 _ => {
1086 i += 2;
1087 }
1088 }
1089 }
1090
1091 if let Some(ref m) = meta_opt
1093 && !matches!(m, Value::Nil | Value::Map(_))
1094 {
1095 return Err(EvalError::Thrown(Value::string(
1096 "Atom metadata must be a map or nil".to_string(),
1097 )));
1098 }
1099
1100 if let Some(ref vf) = validator_opt {
1102 let result = crate::env::apply::apply_value(vf, vec![initial.clone()], env)?;
1103 if result == Value::Nil || result == Value::Bool(false) {
1104 return Err(EvalError::Thrown(Value::string(
1105 "Invalid initial value for atom".to_string(),
1106 )));
1107 }
1108 }
1109
1110 let atom = GcPtr::new(Atom::new(initial));
1111 if let Some(m) = meta_opt {
1112 atom.get()
1113 .set_meta(if m == Value::Nil { None } else { Some(m) });
1114 }
1115 if let Some(vf) = validator_opt {
1116 atom.get().set_validator(Some(vf));
1117 }
1118 Ok(Value::Atom(atom))
1119}
1120
1121fn shared_atom_reset(sa: &Arc<cljrs_value::SharedAtom>, new_val: Value) -> EvalResult {
1133 let promoted = cljrs_value::promote(&new_val).map_err(promote_error)?;
1134 sa.try_reset(promoted)
1135 .map_err(EvalError::MemoryLimitExceeded)?;
1136 Ok(new_val)
1137}
1138
1139fn promote_error(e: cljrs_value::PromoteError) -> EvalError {
1141 match e.memory {
1142 Some(fault) => EvalError::MemoryLimitExceeded(fault),
1143 None => EvalError::Runtime(e.to_string()),
1144 }
1145}
1146
1147fn shared_atom_swap(
1152 sa: &Arc<cljrs_value::SharedAtom>,
1153 f: &Value,
1154 extra: Vec<Value>,
1155 env: &mut Env,
1156) -> EvalResult {
1157 loop {
1158 let cur = sa.deref_val();
1159 let old_val = cljrs_value::demote(&cur);
1160 let mut call_args = Vec::with_capacity(1 + extra.len());
1161 call_args.push(old_val);
1162 call_args.extend(extra.iter().cloned());
1163 let new_val = crate::env::apply::apply_value(f, call_args, env)?;
1164 let promoted = cljrs_value::promote(&new_val).map_err(promote_error)?;
1165 if sa
1166 .try_compare_and_set(&cur, promoted)
1167 .map_err(EvalError::MemoryLimitExceeded)?
1168 {
1169 return Ok(new_val);
1170 }
1171 }
1173}
1174
1175fn handle_reset_bang(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1178 if arg_forms.len() < 2 {
1179 return Err(EvalError::Arity {
1180 name: "reset!".into(),
1181 expected: "2".into(),
1182 got: arg_forms.len(),
1183 });
1184 }
1185 let atom_val = eval(&arg_forms[0], env)?;
1186 #[cfg(feature = "no-gc")]
1189 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1190 let new_val = eval(&arg_forms[1], env)?;
1191
1192 let atom = match &atom_val {
1193 Value::Atom(a) => a.clone(),
1194 Value::SharedAtom(sa) => return shared_atom_reset(sa, new_val),
1195 v => {
1196 return Err(EvalError::Runtime(format!(
1197 "reset! requires an atom, got {}",
1198 v.type_name()
1199 )));
1200 }
1201 };
1202
1203 validate_atom_value(&atom, &new_val, env)?;
1204 let old_val = atom.get().deref();
1205 atom.get().reset(new_val.clone());
1206 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1207 check_watch_error()?;
1208 Ok(new_val)
1209}
1210
1211fn validate_atom_value(atom: &GcPtr<Atom>, new_val: &Value, env: &mut Env) -> EvalResult<()> {
1213 if let Some(vf) = atom.get().get_validator() {
1214 let result = crate::env::apply::apply_value(&vf, vec![new_val.clone()], env)?;
1215 if result == Value::Nil || result == Value::Bool(false) {
1216 return Err(EvalError::Thrown(Value::string(
1217 "Invalid value for atom".to_string(),
1218 )));
1219 }
1220 }
1221 Ok(())
1222}
1223
1224fn handle_swap_call(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1227 let mut evaled: Vec<Value> = arg_forms
1228 .iter()
1229 .map(|f| eval(f, env))
1230 .collect::<EvalResult<_>>()?;
1231
1232 if evaled.len() < 2 {
1233 return Err(EvalError::Arity {
1234 name: "swap!".into(),
1235 expected: "2+".into(),
1236 got: evaled.len(),
1237 });
1238 }
1239
1240 let atom_val = evaled.remove(0);
1241 let f = evaled.remove(0);
1242
1243 let atom = match &atom_val {
1244 Value::Atom(a) => a.clone(),
1245 Value::SharedAtom(sa) => return shared_atom_swap(sa, &f, evaled, env),
1246 v => {
1247 return Err(EvalError::Runtime(format!(
1248 "swap! requires an atom, got {}",
1249 v.type_name()
1250 )));
1251 }
1252 };
1253
1254 let old_val = atom.get().deref();
1255 let mut args = vec![old_val.clone()];
1256 args.extend(evaled);
1257 #[cfg(feature = "no-gc")]
1260 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1261 let new_val = crate::env::apply::apply_value(&f, args, env)?;
1262 validate_atom_value(&atom, &new_val, env)?;
1263 atom.get().reset(new_val.clone());
1264 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1265 check_watch_error()?;
1266 Ok(new_val)
1267}
1268
1269fn handle_with_bindings(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1274 if arg_forms.len() < 2 {
1275 return Err(EvalError::Arity {
1276 name: "with-bindings*".into(),
1277 expected: "2".into(),
1278 got: arg_forms.len(),
1279 });
1280 }
1281 let map_val = eval(&arg_forms[0], env)?;
1282 let func_val = eval(&arg_forms[1], env)?;
1283
1284 let mut frame: HashMap<usize, Value> = HashMap::new();
1285 if let Value::Map(m) = &map_val {
1286 m.for_each(|k, v| {
1287 if let Value::Var(vp) = k {
1288 frame.insert(crate::env::dynamics::var_key_of(vp), v.clone());
1289 }
1290 });
1292 } else {
1293 return Err(EvalError::Runtime(
1294 "with-bindings*: first arg must be a map".into(),
1295 ));
1296 }
1297
1298 let _guard = crate::env::dynamics::push_frame(frame);
1299 crate::env::apply::apply_value(&func_val, vec![], env)
1300}
1301
1302fn handle_alter_var_root(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1306 if arg_forms.len() < 2 {
1307 return Err(EvalError::Arity {
1308 name: "alter-var-root".into(),
1309 expected: "2+".into(),
1310 got: arg_forms.len(),
1311 });
1312 }
1313 let var_val = eval(&arg_forms[0], env)?;
1314 let f = eval(&arg_forms[1], env)?;
1315 let extra: Vec<Value> = arg_forms[2..]
1316 .iter()
1317 .map(|form| eval(form, env))
1318 .collect::<EvalResult<_>>()?;
1319
1320 let vp = match &var_val {
1321 Value::Var(vp) => vp.clone(),
1322 v => {
1323 return Err(EvalError::Runtime(format!(
1324 "alter-var-root: expected var, got {}",
1325 v.type_name()
1326 )));
1327 }
1328 };
1329 let old_val = vp.get().deref().unwrap_or(Value::Nil);
1330 let mut call_args = vec![old_val.clone()];
1331 call_args.extend(extra);
1332 #[cfg(feature = "no-gc")]
1335 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1336 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1337 vp.get().bind(new_val.clone());
1338 fire_watches(&vp.get().watches, &var_val, &old_val, &new_val, env);
1339 check_watch_error()?;
1340 Ok(new_val)
1341}
1342
1343fn handle_vary_meta(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1347 if arg_forms.len() < 2 {
1348 return Err(EvalError::Arity {
1349 name: "vary-meta".into(),
1350 expected: "2+".into(),
1351 got: arg_forms.len(),
1352 });
1353 }
1354 let obj = eval(&arg_forms[0], env)?;
1355 let f = eval(&arg_forms[1], env)?;
1356 let extra: Vec<Value> = arg_forms[2..]
1357 .iter()
1358 .map(|form| eval(form, env))
1359 .collect::<EvalResult<_>>()?;
1360
1361 let current_meta = match &obj {
1362 Value::Var(vp) => vp.get().get_meta().unwrap_or(Value::Nil),
1363 _ => Value::Nil,
1364 };
1365 let mut call_args = vec![current_meta];
1366 call_args.extend(extra);
1367 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1368 if let Value::Var(vp) = &obj {
1369 vp.get().set_meta(new_meta);
1370 }
1371 Ok(obj)
1372}
1373
1374fn handle_eval(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1378 let [arg] = arg_forms else {
1379 return Err(EvalError::Arity {
1380 name: "eval".into(),
1381 expected: "1".into(),
1382 got: arg_forms.len(),
1383 });
1384 };
1385 let value = eval(arg, env)?;
1386 eval_eval(vec![value], env)
1387}
1388
1389pub fn eval_eval(args: Vec<Value>, env: &mut Env) -> EvalResult {
1394 let [value] = args.as_slice() else {
1395 return Err(EvalError::Arity {
1396 name: "eval".into(),
1397 expected: "1".into(),
1398 got: args.len(),
1399 });
1400 };
1401 if matches!(
1404 value.unwrap_meta(),
1405 Value::NativeFunction(_) | Value::Fn(_) | Value::Macro(_) | Value::BoundFn(_)
1406 ) {
1407 return Ok(value.clone());
1408 }
1409 let span = cljrs_types::span::Span::new(Arc::new("<eval>".to_string()), 0, 0, 1, 1);
1410 let form = crate::interp::macros::value_to_form(value, span)?;
1411 let mut top = Env::new(env.globals.clone(), &env.current_ns);
1412 eval(&form, &mut top)
1413}
1414
1415pub fn eval_reset_bang(args: Vec<Value>, env: &mut Env) -> EvalResult {
1423 if args.len() < 2 {
1424 return Err(EvalError::Arity {
1425 name: "reset!".into(),
1426 expected: "2".into(),
1427 got: args.len(),
1428 });
1429 }
1430 let atom_val = args[0].clone();
1431 let new_val = args[1].clone();
1432 let atom = match &atom_val {
1433 Value::Atom(a) => a.clone(),
1434 Value::SharedAtom(sa) => return shared_atom_reset(sa, new_val),
1435 v => {
1436 return Err(EvalError::Runtime(format!(
1437 "reset! requires an atom, got {}",
1438 v.type_name()
1439 )));
1440 }
1441 };
1442 #[cfg(feature = "no-gc")]
1443 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1444 validate_atom_value(&atom, &new_val, env)?;
1445 let old_val = atom.get().deref();
1446 atom.get().reset(new_val.clone());
1447 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1448 check_watch_error()?;
1449 Ok(new_val)
1450}
1451
1452pub fn eval_swap_bang(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1454 if args.len() < 2 {
1455 return Err(EvalError::Arity {
1456 name: "swap!".into(),
1457 expected: "2+".into(),
1458 got: args.len(),
1459 });
1460 }
1461 let atom_val = args.remove(0);
1462 let f = args.remove(0);
1463 let atom = match &atom_val {
1464 Value::Atom(a) => a.clone(),
1465 Value::SharedAtom(sa) => return shared_atom_swap(sa, &f, args, env),
1466 v => {
1467 return Err(EvalError::Runtime(format!(
1468 "swap! requires an atom, got {}",
1469 v.type_name()
1470 )));
1471 }
1472 };
1473 let old_val = atom.get().deref();
1474 let mut call_args = vec![old_val.clone()];
1475 call_args.extend(args);
1476 #[cfg(feature = "no-gc")]
1477 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1478 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1479 validate_atom_value(&atom, &new_val, env)?;
1480 atom.get().reset(new_val.clone());
1481 fire_watches(&atom.get().watches, &atom_val, &old_val, &new_val, env);
1482 check_watch_error()?;
1483 Ok(new_val)
1484}
1485
1486pub fn eval_volatile(args: Vec<Value>) -> EvalResult {
1488 if args.is_empty() {
1489 return Err(EvalError::Arity {
1490 name: "volatile!".into(),
1491 expected: "1".into(),
1492 got: 0,
1493 });
1494 }
1495 #[cfg(feature = "no-gc")]
1496 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1497 Ok(Value::Volatile(GcPtr::new(Volatile::new(
1498 args.into_iter().next().unwrap(),
1499 ))))
1500}
1501
1502pub fn eval_vreset_bang(args: Vec<Value>) -> EvalResult {
1504 if args.len() < 2 {
1505 return Err(EvalError::Arity {
1506 name: "vreset!".into(),
1507 expected: "2".into(),
1508 got: args.len(),
1509 });
1510 }
1511 #[cfg(feature = "no-gc")]
1512 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1513 let new_val = args[1].clone();
1514 match &args[0] {
1515 Value::Volatile(v) => {
1516 v.get().reset(new_val.clone());
1517 Ok(new_val)
1518 }
1519 other => Err(EvalError::Runtime(format!(
1520 "vreset!: expected volatile, got {}",
1521 other.type_name()
1522 ))),
1523 }
1524}
1525
1526pub fn eval_vswap_bang(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1528 if args.len() < 2 {
1529 return Err(EvalError::Arity {
1530 name: "vswap!".into(),
1531 expected: "2+".into(),
1532 got: args.len(),
1533 });
1534 }
1535 let vol_val = args.remove(0);
1536 let f = args.remove(0);
1537 match vol_val {
1538 Value::Volatile(v) => {
1539 let cur = v.get().deref();
1540 let mut call_args = vec![cur];
1541 call_args.extend(args);
1542 #[cfg(feature = "no-gc")]
1543 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1544 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1545 v.get().reset(new_val.clone());
1546 Ok(new_val)
1547 }
1548 other => Err(EvalError::Runtime(format!(
1549 "vswap!: expected volatile, got {}",
1550 other.type_name()
1551 ))),
1552 }
1553}
1554
1555pub fn make_delay_from_fn(
1560 f_val: &Value,
1561 globals: std::sync::Arc<crate::env::env::GlobalEnv>,
1562 ns: std::sync::Arc<str>,
1563) -> EvalResult {
1564 let f = match f_val {
1565 Value::Fn(f) => f.get().clone(),
1566 other => {
1567 return Err(EvalError::Runtime(format!(
1568 "make-delay requires a fn, got {}",
1569 other.type_name()
1570 )));
1571 }
1572 };
1573 let thunk = ClosureThunk { f, globals, ns };
1574 Ok(Value::Delay(GcPtr::new(Delay::new(Box::new(thunk)))))
1575}
1576
1577pub fn eval_alter_var_root(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1579 if args.len() < 2 {
1580 return Err(EvalError::Arity {
1581 name: "alter-var-root".into(),
1582 expected: "2+".into(),
1583 got: args.len(),
1584 });
1585 }
1586 let var_val = args.remove(0);
1587 let f = args.remove(0);
1588 let vp = match &var_val {
1589 Value::Var(vp) => vp.clone(),
1590 v => {
1591 return Err(EvalError::Runtime(format!(
1592 "alter-var-root: expected var, got {}",
1593 v.type_name()
1594 )));
1595 }
1596 };
1597 let old_val = vp.get().deref().unwrap_or(Value::Nil);
1598 let mut call_args = vec![old_val.clone()];
1599 call_args.extend(args);
1600 #[cfg(feature = "no-gc")]
1601 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1602 let new_val = crate::env::apply::apply_value(&f, call_args, env)?;
1603 vp.get().bind(new_val.clone());
1604 fire_watches(&vp.get().watches, &var_val, &old_val, &new_val, env);
1605 check_watch_error()?;
1606 Ok(new_val)
1607}
1608
1609pub fn eval_vary_meta(mut args: Vec<Value>, env: &mut Env) -> EvalResult {
1611 if args.len() < 2 {
1612 return Err(EvalError::Arity {
1613 name: "vary-meta".into(),
1614 expected: "2+".into(),
1615 got: args.len(),
1616 });
1617 }
1618 let obj = args.remove(0);
1619 let f = args.remove(0);
1620 let current_meta = match &obj {
1621 Value::Var(vp) => vp.get().get_meta().unwrap_or(Value::Nil),
1622 _ => Value::Nil,
1623 };
1624 let mut call_args = vec![current_meta];
1625 call_args.extend(args);
1626 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1627 if let Value::Var(vp) = &obj {
1628 vp.get().set_meta(new_meta);
1629 }
1630 Ok(obj)
1631}
1632
1633pub fn eval_with_bindings_star(args: Vec<Value>, env: &mut Env) -> EvalResult {
1635 if args.len() < 2 {
1636 return Err(EvalError::Arity {
1637 name: "with-bindings*".into(),
1638 expected: "2".into(),
1639 got: args.len(),
1640 });
1641 }
1642 let mut frame: HashMap<usize, Value> = HashMap::new();
1643 if let Value::Map(m) = &args[0] {
1644 m.for_each(|k, v| {
1645 if let Value::Var(vp) = k {
1646 frame.insert(crate::env::dynamics::var_key_of(vp), v.clone());
1647 }
1648 });
1649 } else {
1650 return Err(EvalError::Runtime(
1651 "with-bindings*: first arg must be a map".into(),
1652 ));
1653 }
1654 let _guard = crate::env::dynamics::push_frame(frame);
1655 crate::env::apply::apply_value(&args[1], vec![], env)
1656}
1657
1658pub fn eval_send_to_agent(_args: Vec<Value>, _env: &mut Env) -> EvalResult {
1660 Err(EvalError::Runtime(
1661 "send/send-off: agents are not yet implemented".into(),
1662 ))
1663}
1664
1665fn ns_name_from_val(v: &Value) -> Result<String, EvalError> {
1668 match v {
1669 Value::Symbol(s) => Ok(s.get().name.as_ref().to_string()),
1670 Value::Str(s) => Ok(s.get().clone()),
1671 Value::Namespace(ns) => Ok(ns.get().name.as_ref().to_string()),
1672 Value::Keyword(k) => Ok(k.get().name.as_ref().to_string()),
1673 other => Err(EvalError::Runtime(format!(
1674 "expected symbol, string, or namespace, got {}",
1675 other.type_name()
1676 ))),
1677 }
1678}
1679
1680fn the_ns(v: &Value, env: &Env) -> Result<GcPtr<cljrs_value::Namespace>, EvalError> {
1685 if let Value::Namespace(ns) = v {
1686 return Ok(ns.clone());
1687 }
1688 let name = ns_name_from_val(v)?;
1689 let map = env.globals.namespaces.read().unwrap();
1690 match map.get(name.as_str()) {
1691 Some(ns) => Ok(ns.clone()),
1692 None => Err(EvalError::Runtime(format!("No namespace: {name} found"))),
1693 }
1694}
1695
1696fn handle_ns_interns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1699 if arg_forms.is_empty() {
1700 return Err(EvalError::Arity {
1701 name: "ns-interns".into(),
1702 expected: "1".into(),
1703 got: 0,
1704 });
1705 }
1706 let arg = eval(&arg_forms[0], env)?;
1707 let ns = the_ns(&arg, env)?;
1708 crate::builtins::builtins::builtin_ns_interns(&[Value::Namespace(ns)])
1709 .map_err(crate::env::error::value_error_to_eval_error)
1710}
1711
1712fn handle_ns_refers(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1714 if arg_forms.is_empty() {
1715 return Err(EvalError::Arity {
1716 name: "ns-refers".into(),
1717 expected: "1".into(),
1718 got: 0,
1719 });
1720 }
1721 let arg = eval(&arg_forms[0], env)?;
1722 let ns = the_ns(&arg, env)?;
1723 crate::builtins::builtins::builtin_ns_refers(&[Value::Namespace(ns)])
1724 .map_err(crate::env::error::value_error_to_eval_error)
1725}
1726
1727fn handle_ns_map(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1729 if arg_forms.is_empty() {
1730 return Err(EvalError::Arity {
1731 name: "ns-map".into(),
1732 expected: "1".into(),
1733 got: 0,
1734 });
1735 }
1736 let arg = eval(&arg_forms[0], env)?;
1737 let ns = the_ns(&arg, env)?;
1738 crate::builtins::builtins::builtin_ns_map(&[Value::Namespace(ns)])
1739 .map_err(crate::env::error::value_error_to_eval_error)
1740}
1741
1742fn handle_find_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1744 if arg_forms.is_empty() {
1745 return Err(EvalError::Arity {
1746 name: "find-ns".into(),
1747 expected: "1".into(),
1748 got: 0,
1749 });
1750 }
1751 let arg = eval(&arg_forms[0], env)?;
1752 let name = ns_name_from_val(&arg)?;
1753 let map = env.globals.namespaces.read().unwrap();
1754 match map.get(name.as_str()) {
1755 Some(ns) => Ok(Value::Namespace(ns.clone())),
1756 None => Ok(Value::Nil),
1757 }
1758}
1759
1760fn handle_all_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1762 if !arg_forms.is_empty() {
1763 let _ = eval(&arg_forms[0], env)?; }
1765 let map = env.globals.namespaces.read().unwrap();
1766 let items: Vec<Value> = map
1767 .values()
1768 .map(|ns| Value::Namespace(ns.clone()))
1769 .collect();
1770 drop(map);
1771 Ok(Value::List(cljrs_gc::GcPtr::new(
1772 cljrs_value::PersistentList::from_iter(items),
1773 )))
1774}
1775
1776fn handle_create_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1778 if arg_forms.is_empty() {
1779 return Err(EvalError::Arity {
1780 name: "create-ns".into(),
1781 expected: "1".into(),
1782 got: 0,
1783 });
1784 }
1785 let arg = eval(&arg_forms[0], env)?;
1786 let name = ns_name_from_val(&arg)?;
1787 let ns = env.globals.get_or_create_ns(&name);
1788 Ok(Value::Namespace(ns))
1789}
1790
1791fn handle_ns_aliases(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1793 if arg_forms.is_empty() {
1794 return Err(EvalError::Arity {
1795 name: "ns-aliases".into(),
1796 expected: "1".into(),
1797 got: 0,
1798 });
1799 }
1800 let ns_val = eval(&arg_forms[0], env)?;
1801 let ns_name = ns_name_from_val(&ns_val)?;
1802 let map = env.globals.namespaces.read().unwrap();
1803 let ns = match map.get(ns_name.as_str()) {
1804 Some(ns) => ns.clone(),
1805 None => return Ok(Value::Map(cljrs_value::MapValue::empty())),
1806 };
1807 let aliases = ns.get().aliases.lock().unwrap().clone();
1808 drop(map);
1809 let mut m = cljrs_value::MapValue::empty();
1810 for (alias, full_ns_name) in &aliases {
1811 let sym = Value::symbol(cljrs_value::Symbol::simple(alias.clone()));
1812 let nsmap = env.globals.namespaces.read().unwrap();
1813 if let Some(target_ns) = nsmap.get(full_ns_name.as_ref()) {
1814 m = m.assoc(sym, Value::Namespace(target_ns.clone()));
1815 }
1816 }
1817 Ok(Value::Map(m))
1818}
1819
1820fn handle_remove_ns(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1822 if arg_forms.is_empty() {
1823 return Err(EvalError::Arity {
1824 name: "remove-ns".into(),
1825 expected: "1".into(),
1826 got: 0,
1827 });
1828 }
1829 let arg = eval(&arg_forms[0], env)?;
1830 let name = ns_name_from_val(&arg)?;
1831 env.globals
1832 .namespaces
1833 .write()
1834 .unwrap()
1835 .remove(name.as_str());
1836 Ok(Value::Nil)
1837}
1838
1839fn handle_alter_meta(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1841 if arg_forms.len() < 2 {
1842 return Err(EvalError::Arity {
1843 name: "alter-meta!".into(),
1844 expected: "2+".into(),
1845 got: arg_forms.len(),
1846 });
1847 }
1848 let obj = eval(&arg_forms[0], env)?;
1849 let f = eval(&arg_forms[1], env)?;
1850 let extra: Vec<Value> = arg_forms[2..]
1851 .iter()
1852 .map(|form| eval(form, env))
1853 .collect::<EvalResult<_>>()?;
1854
1855 let current_meta = match &obj {
1856 Value::Var(vp) => vp
1857 .get()
1858 .get_meta()
1859 .unwrap_or(Value::Map(cljrs_value::MapValue::empty())),
1860 _ => Value::Map(cljrs_value::MapValue::empty()),
1861 };
1862 let mut call_args = vec![current_meta];
1863 call_args.extend(extra);
1864 let new_meta = crate::env::apply::apply_value(&f, call_args, env)?;
1865 if let Value::Var(vp) = &obj {
1866 vp.get().set_meta(new_meta.clone());
1867 }
1868 Ok(new_meta)
1869}
1870
1871fn handle_ns_resolve(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1873 if arg_forms.len() < 2 {
1874 return Err(EvalError::Arity {
1875 name: "ns-resolve".into(),
1876 expected: "2".into(),
1877 got: arg_forms.len(),
1878 });
1879 }
1880 let ns_arg = eval(&arg_forms[0], env)?;
1881 let sym_arg = eval(&arg_forms[1], env)?;
1882 let ns_name = ns_name_from_val(&ns_arg)?;
1883 let sym_name = match &sym_arg {
1884 Value::Symbol(s) => s.get().name.as_ref().to_string(),
1885 Value::Str(s) => s.get().clone(),
1886 other => {
1887 return Err(EvalError::Runtime(format!(
1888 "ns-resolve: second arg must be symbol or string, got {}",
1889 other.type_name()
1890 )));
1891 }
1892 };
1893 match env.globals.lookup_var(&ns_name, &sym_name) {
1894 Some(var_ptr) => Ok(Value::Var(var_ptr)),
1895 None => Ok(Value::Nil),
1896 }
1897}
1898
1899fn resolve_current_ns(env: &Env) -> Arc<str> {
1903 if let Some(var) = env.globals.lookup_var("clojure.core", "*ns*") {
1904 let val = crate::env::dynamics::deref_var(&var);
1905 if let Some(Value::Namespace(ns_ptr)) = val {
1906 return ns_ptr.get().name.clone();
1907 }
1908 }
1909 env.current_ns.clone()
1910}
1911
1912fn handle_resolve(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1914 if arg_forms.len() != 1 {
1915 return Err(EvalError::Arity {
1916 name: "resolve".into(),
1917 expected: "1".into(),
1918 got: arg_forms.len(),
1919 });
1920 }
1921 let resolve_ns = resolve_current_ns(env);
1922 let sym_arg = eval(&arg_forms[0], env)?;
1923 let sym_name = match &sym_arg {
1924 Value::Symbol(s) => {
1925 let sym = s.get();
1926 if let Some(ns) = &sym.namespace {
1928 let full_ns = env.globals.resolve_ns_part_in(&resolve_ns, ns.as_ref());
1931 return Ok(
1932 match env.globals.lookup_var_in_ns(&full_ns, sym.name.as_ref()) {
1933 Some(var_ptr) => Value::Var(var_ptr),
1934 None => Value::Nil,
1935 },
1936 );
1937 }
1938 sym.name.as_ref().to_string()
1939 }
1940 Value::Str(s) => s.get().clone(),
1941 other => {
1942 return Err(EvalError::Runtime(format!(
1943 "resolve: arg must be symbol or string, got {}",
1944 other.type_name()
1945 )));
1946 }
1947 };
1948 Ok(match env.globals.lookup_var_in_ns(&resolve_ns, &sym_name) {
1949 Some(var_ptr) => Value::Var(var_ptr),
1950 None => Value::Nil,
1951 })
1952}
1953
1954fn handle_intern(arg_forms: &[Form], env: &mut Env) -> EvalResult {
1955 if arg_forms.len() < 2 || arg_forms.len() > 3 {
1956 return Err(EvalError::Runtime("intern expects 2 or 3 arguments".into()));
1957 }
1958 let ns_val = eval(&arg_forms[0], env)?;
1959 let ns_name: Arc<str> = match &ns_val {
1960 Value::Symbol(s) => s.get().name.clone(),
1961 Value::Namespace(ns) => ns.get().name.clone(),
1962 other => {
1963 return Err(EvalError::Runtime(format!(
1964 "intern: first arg must be namespace or symbol, got {}",
1965 other.type_name()
1966 )));
1967 }
1968 };
1969 let var_name: Arc<str> = match eval(&arg_forms[1], env)? {
1970 Value::Symbol(s) => s.get().name.clone(),
1971 other => {
1972 return Err(EvalError::Runtime(format!(
1973 "intern: second arg must be symbol, got {}",
1974 other.type_name()
1975 )));
1976 }
1977 };
1978 let ns = {
1980 let map = env.globals.namespaces.read().unwrap();
1981 map.get(ns_name.as_ref()).cloned()
1982 };
1983 let ns = ns.ok_or_else(|| EvalError::Runtime(format!("No namespace: {ns_name} found")))?;
1984 let var = if arg_forms.len() == 3 {
1985 #[cfg(feature = "no-gc")]
1988 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1989 let val = eval(&arg_forms[2], env)?;
1990 let mut interns = ns.get().interns.lock().unwrap();
1991 if let Some(var) = interns.get(&var_name) {
1992 var.get().bind(val);
1993 var.clone()
1994 } else {
1995 let var =
1996 cljrs_gc::GcPtr::new(cljrs_value::Var::new(ns_name.clone(), var_name.clone()));
1997 var.get().bind(val);
1998 interns.insert(var_name, var.clone());
1999 var
2000 }
2001 } else {
2002 let mut interns = ns.get().interns.lock().unwrap();
2003 if let Some(var) = interns.get(&var_name) {
2004 var.clone()
2005 } else {
2006 let var =
2007 cljrs_gc::GcPtr::new(cljrs_value::Var::new(ns_name.clone(), var_name.clone()));
2008 interns.insert(var_name, var.clone());
2009 var
2010 }
2011 };
2012 Ok(Value::Var(var))
2013}
2014
2015fn handle_bound_fn_star(arg_forms: &[Form], env: &mut Env) -> EvalResult {
2020 if arg_forms.len() != 1 {
2021 return Err(EvalError::Arity {
2022 name: "bound-fn*".into(),
2023 expected: "1".into(),
2024 got: arg_forms.len(),
2025 });
2026 }
2027 let f = eval(&arg_forms[0], env)?;
2028 let frames = crate::env::dynamics::capture_current();
2030 let mut merged = std::collections::HashMap::new();
2031 for frame in &frames {
2032 merged.extend(frame.iter().map(|(k, v)| (*k, v.clone())));
2033 }
2034 Ok(Value::BoundFn(cljrs_gc::GcPtr::new(cljrs_value::BoundFn {
2035 wrapped: f,
2036 captured_bindings: merged,
2037 })))
2038}
2039
2040fn trace_saved_watch_error(error: &Option<EvalError>, visitor: &mut cljrs_gc::MarkVisitor) {
2041 use cljrs_gc::Trace;
2042 match error {
2043 Some(EvalError::Thrown(value)) => value.trace(visitor),
2044 Some(EvalError::Recur(values)) => {
2045 for value in values {
2046 value.trace(visitor);
2047 }
2048 }
2049 _ => {}
2050 }
2051}