1use std::collections::{HashMap, HashSet};
4use std::sync::Arc;
5
6use crate::builtins::form::{
7 expand_pairs, expand_reader_conds, expand_reader_conds_cow, form_to_value, resolve_auto_forms,
8 select_reader_cond,
9};
10use crate::env::env::{Env, RequireRefer, RequireSpec};
11use crate::env::error::{EvalError, EvalResult};
12use crate::env::loader::load_ns;
13use crate::interp::destructure::bind_pattern;
14use crate::interp::eval::{eval_body, eval_unscoped as eval, is_special_form};
15use cljrs_gc::GcPtr;
16use cljrs_reader::Form;
17use cljrs_reader::form::FormKind;
18use cljrs_value::error::ExceptionInfo;
19use cljrs_value::{
20 CljxFn, CljxFnArity, Keyword, MapValue, Protocol, ProtocolMethod, ReferClojureFilter, TypeHint,
21 Value, ValueError,
22};
23
24pub fn eval_special(head: &str, args: &[Form], env: &mut Env) -> EvalResult {
26 crate::env::policy::check_special(head)?;
27 match head {
28 "def" => eval_def(args, env),
29 "fn*" | "fn" => eval_fn(args, env),
30 "if" => eval_if(args, env),
31 "do" => eval_body(args, env),
32 "let*" | "let" => eval_let(args, env),
33 "loop*" | "loop" => eval_loop(args, env),
34 "recur" => eval_recur(args, env),
35 "quote" => eval_quote(args, env),
36 "var" => eval_var(args, env),
37 "set!" => eval_set_bang(args, env),
38 "throw" => eval_throw(args, env),
39 "try" => eval_try(args, env),
40 "defn" => eval_defn(args, env, false),
41 "defn-" => eval_defn(args, env, true),
42 "defmacro" => eval_defmacro(args, env),
43 "defonce" => eval_defonce(args, env),
44 "and" => eval_and(args, env),
45 "or" => eval_or(args, env),
46 "." => Err(EvalError::Runtime("interop not yet implemented".into())),
47 "ns" => eval_ns(args, env),
48 "require" => eval_require(args, env),
49 "letfn" => eval_letfn(args, env),
50 "in-ns" => eval_in_ns(args, env),
51 "alias" => eval_alias(args, env),
52 "protocol*" => eval_protocol_star(args, env),
53 "deftype*" => eval_deftype_star(args, env),
54 "load-file" => eval_load_file(args, env),
55 "binding" => eval_binding(args, env),
56 "with-out-str" => eval_with_out_str(args, env),
57 "await" => eval_await(args, env),
58 _ => unreachable!("unknown special form: {head}"),
59 }
60}
61
62fn eval_def(args: &[Form], env: &mut Env) -> EvalResult {
65 let target = parse_def(args, env)?;
66 crate::interp::eval::with_scratch(|| {
67 let val = match target.value_form {
68 Some(form) => eval(form, env)?,
69 None => Value::Nil,
70 };
71 intern_def(target, val, env)
72 })
73}
74
75pub struct DefTarget<'a> {
81 pub name: String,
82 pub meta: Option<Value>,
84 pub value_form: Option<&'a Form>,
86}
87
88pub fn parse_def<'a>(args: &'a [Form], env: &mut Env) -> EvalResult<DefTarget<'a>> {
91 if args.is_empty() {
92 return Err(EvalError::Runtime("def requires a name".into()));
93 }
94 let (name, meta_opt) = extract_def_name(&args[0], env)?;
95 let (docstring, val_idx) = if args.len() > 2
97 && let FormKind::Str(s) = &args[1].kind
98 {
99 (Some(s.clone()), 2)
100 } else {
101 (None, 1)
102 };
103 Ok(DefTarget {
104 name,
105 meta: merge_meta(meta_opt, docstring.as_deref().map(doc_meta)),
106 value_form: args.get(val_idx),
107 })
108}
109
110pub fn intern_def(target: DefTarget<'_>, val: Value, env: &mut Env) -> EvalResult {
112 let var = env
113 .globals
114 .intern(&env.current_ns, Arc::from(target.name.as_str()), val);
115 if let Some(meta_val) = target.meta {
116 var.get().set_meta(meta_val);
117 }
118 Ok(Value::Var(var))
119}
120
121pub fn defonce_existing(name: &str, env: &Env) -> Option<Value> {
124 env.globals
125 .lookup_var(&env.current_ns, name)
126 .filter(|var| var.get().is_bound())
127 .map(Value::Var)
128}
129
130fn doc_meta(doc: &str) -> Value {
132 Value::Map(MapValue::empty().assoc(
133 Value::keyword(Keyword::parse("doc")),
134 Value::string(doc.to_string()),
135 ))
136}
137
138fn private_meta() -> Value {
139 Value::Map(
140 MapValue::empty().assoc(Value::keyword(Keyword::parse("private")), Value::Bool(true)),
141 )
142}
143
144fn arglists_meta(fn_val: &Value, skip: usize) -> Option<Value> {
149 let arities = match fn_val {
150 Value::Fn(f) => &f.get().arities,
151 Value::Macro(f) => &f.get().arities,
152 _ => return None,
153 };
154 let lists: Vec<Value> = arities
155 .iter()
156 .map(|a| {
157 let mut syms: Vec<Value> = a
158 .params
159 .iter()
160 .skip(skip)
161 .map(|p| Value::symbol(cljrs_value::Symbol::simple(p.as_ref())))
162 .collect();
163 if let Some(rest) = &a.rest_param {
164 syms.push(Value::symbol(cljrs_value::Symbol::simple("&")));
165 syms.push(Value::symbol(cljrs_value::Symbol::simple(rest.as_ref())));
166 }
167 Value::Vector(GcPtr::new(cljrs_value::PersistentVector::from_iter(syms)))
168 })
169 .collect();
170 Some(Value::Map(MapValue::empty().assoc(
171 Value::keyword(Keyword::parse("arglists")),
172 Value::Vector(GcPtr::new(cljrs_value::PersistentVector::from_iter(lists))),
173 )))
174}
175
176fn extract_def_name(form: &Form, env: &mut Env) -> EvalResult<(String, Option<Value>)> {
178 match &form.kind {
179 FormKind::Symbol(s) => Ok((s.clone(), None)),
180 FormKind::Meta(meta_form, inner) => {
182 let meta_val = compile_meta_form(meta_form, env)?;
183 let (name, inner_meta) = extract_def_name(inner, env)?;
184 Ok((name, merge_meta(inner_meta, Some(meta_val))))
185 }
186 _ => Err(EvalError::Runtime("def name must be a symbol".into())),
187 }
188}
189
190pub fn compile_meta_form(meta: &Form, env: &mut Env) -> EvalResult<Value> {
197 crate::builtins::form::expand_meta_annotation(meta, &mut |f| eval(f, env))
198}
199
200fn eval_fn(args: &[Form], env: &mut Env) -> EvalResult {
203 let is_async = Form::fn_args_request_async(args);
207 let peeled: Vec<Form>;
209 let args: &[Form] = if matches!(args.first().map(|f| &f.kind), Some(FormKind::Meta(..))) {
210 let (_, head) = args[0].peel_meta();
211 peeled = std::iter::once(head.clone())
212 .chain(args[1..].iter().cloned())
213 .collect();
214 &peeled
215 } else {
216 args
217 };
218
219 let mut idx = 0;
220 let mut name: Option<Arc<str>> = None;
221
222 if let Some(FormKind::Symbol(s)) = args.first().map(|f| &f.kind)
224 && !is_special_form(s)
225 {
226 name = Some(Arc::from(s.as_str()));
227 idx = 1;
228 }
229
230 let rest = &args[idx..];
231 if rest.is_empty() {
232 return Err(EvalError::Runtime("fn* requires params and body".into()));
233 }
234
235 let arities = match &rest[0].unmeta().kind {
238 FormKind::Vector(_) => {
239 vec![parse_arity(&rest[0], &rest[1..])?]
241 }
242 FormKind::List(_) => {
243 rest.iter()
245 .map(|arity_form| {
246 if let Some(forms) = arity_form.as_list() {
247 if forms.is_empty() {
248 return Err(EvalError::Runtime("arity clause requires params".into()));
249 }
250 parse_arity(&forms[0], &forms[1..])
251 } else {
252 Err(EvalError::Runtime("expected arity clause (list)".into()))
253 }
254 })
255 .collect::<EvalResult<Vec<_>>>()?
256 }
257 _ => {
258 return Err(EvalError::Runtime(
259 "fn* expects vector or arity clauses".into(),
260 ));
261 }
262 };
263
264 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
266
267 let mut cljrs_fn = CljxFn::new(
268 name.clone(),
269 arities,
270 closed_over_names,
271 closed_over_vals,
272 false,
273 Arc::clone(&env.current_ns),
274 );
275 cljrs_fn.is_async = is_async;
276
277 env.on_fn_defined(&cljrs_fn);
278
279 let mut ptr = GcPtr::new_isolated(cljrs_fn);
283 if ptr.get().name.is_some() {
287 let self_clone = ptr.clone();
288 ptr.get_mut().self_ptr = Some(self_clone);
289 }
290 Ok(Value::Fn(ptr))
291}
292
293pub fn parse_arity(params_form: &Form, body: &[Form]) -> EvalResult<CljxFnArity> {
295 let Some(param_forms) = params_form.as_vector() else {
296 return Err(EvalError::Runtime(
297 "fn arity params must be a vector".into(),
298 ));
299 };
300
301 let mut params: Vec<Arc<str>> = Vec::new();
302 let mut param_hints: Vec<Option<TypeHint>> = Vec::new();
303 let mut rest_param: Option<Arc<str>> = None;
304 let mut rest_hint: Option<TypeHint> = None;
305 let mut destructure_params: Vec<(usize, Form)> = Vec::new();
306 let mut destructure_rest: Option<Form> = None;
307 let mut saw_amp = false;
308
309 for p in param_forms {
310 let (hint, p) = peel_param_hint(p);
316 match &p.kind {
317 FormKind::Symbol(s) if s == "&" => {
318 saw_amp = true;
319 }
320 FormKind::Symbol(s) => {
321 if saw_amp {
322 rest_param = Some(Arc::from(s.as_str()));
323 rest_hint = hint;
324 break;
325 } else {
326 params.push(Arc::from(s.as_str()));
327 param_hints.push(hint);
328 }
329 }
330 FormKind::Vector(_) | FormKind::Map(_) => {
332 if saw_amp {
333 let gensym = format!("__destructure_rest_{}", params.len());
334 rest_param = Some(Arc::from(gensym.as_str()));
335 destructure_rest = Some(p.clone());
336 break;
337 } else {
338 let idx = params.len();
339 let gensym = format!("__destructure_{idx}");
340 params.push(Arc::from(gensym.as_str()));
341 param_hints.push(None);
343 destructure_params.push((idx, p.clone()));
344 }
345 }
346 _ => {
347 return Err(EvalError::Runtime(
348 "fn params must be symbols, vectors, or maps".into(),
349 ));
350 }
351 }
352 }
353
354 let body = desugar_pre_post_conditions(body);
355
356 Ok(CljxFnArity {
357 params,
358 rest_param,
359 body,
360 destructure_params,
361 destructure_rest,
362 ir_arity_id: crate::interp::arity::fresh_arity_id(),
363 param_hints,
364 rest_hint,
365 })
366}
367
368fn desugar_pre_post_conditions(body: &[Form]) -> Vec<Form> {
386 let first = match body.first() {
387 Some(f) => f,
388 None => return body.to_vec(),
389 };
390
391 let entries = match first.as_map() {
392 Some(entries) => entries,
393 None => return body.to_vec(),
394 };
395
396 let mut pre_conds: Vec<Form> = Vec::new();
397 let mut post_conds: Vec<Form> = Vec::new();
398 let mut has_conditions = false;
399
400 for chunk in entries.chunks(2) {
401 if chunk.len() < 2 {
402 break;
403 }
404 let (key, val) = (&chunk[0], &chunk[1]);
405 match &key.kind {
406 FormKind::Keyword(k) if k == "pre" => {
407 if let FormKind::Vector(conds) = &val.kind {
408 pre_conds.extend_from_slice(conds);
409 has_conditions = true;
410 }
411 }
412 FormKind::Keyword(k) if k == "post" => {
413 if let FormKind::Vector(conds) = &val.kind {
414 post_conds.extend_from_slice(conds);
415 has_conditions = true;
416 }
417 }
418 _ => {}
419 }
420 }
421
422 if !has_conditions {
423 return body.to_vec();
424 }
425
426 let real_body = &body[1..]; let span = first.span.clone();
428 let mut new_body: Vec<Form> = Vec::new();
429
430 for cond in &pre_conds {
432 new_body.push(make_assert_call(cond, &span));
433 }
434
435 if post_conds.is_empty() {
436 new_body.extend_from_slice(real_body);
437 } else {
438 let percent = Form::new(FormKind::Symbol("%".to_string()), span.clone());
441
442 let body_expr = if real_body.len() == 1 {
443 real_body[0].clone()
444 } else {
445 let mut do_forms = vec![Form::new(FormKind::Symbol("do".to_string()), span.clone())];
446 do_forms.extend_from_slice(real_body);
447 Form::new(FormKind::List(do_forms), span.clone())
448 };
449
450 let binding_vec = Form::new(
451 FormKind::Vector(vec![percent.clone(), body_expr]),
452 span.clone(),
453 );
454
455 let mut let_forms = vec![
456 Form::new(FormKind::Symbol("let*".to_string()), span.clone()),
457 binding_vec,
458 ];
459 for cond in &post_conds {
460 let_forms.push(make_assert_call(cond, &span));
461 }
462 let_forms.push(percent);
463
464 new_body.push(Form::new(FormKind::List(let_forms), span));
465 }
466
467 new_body
468}
469
470fn make_assert_call(cond: &Form, span: &cljrs_types::span::Span) -> Form {
472 Form::new(
473 FormKind::List(vec![
474 Form::new(FormKind::Symbol("assert".to_string()), span.clone()),
475 cond.clone(),
476 ]),
477 span.clone(),
478 )
479}
480
481fn peel_param_hint(p: &Form) -> (Option<TypeHint>, &Form) {
485 if let FormKind::Meta(meta, inner) = &p.kind {
486 let hint = tag_name_of_meta(meta).and_then(|n| TypeHint::from_tag(&n));
487 let (inner_hint, inner_form) = peel_param_hint(inner);
489 (hint.or(inner_hint), inner_form)
490 } else {
491 (None, p)
492 }
493}
494
495fn tag_name_of_meta(meta: &Form) -> Option<Arc<str>> {
498 match &meta.kind {
499 FormKind::Symbol(s) => Some(strip_tag_ns(s)),
501 FormKind::Map(entries) => entries.chunks(2).find_map(|kv| {
503 let is_tag = matches!(&kv[0].kind, FormKind::Keyword(k) if k == "tag");
504 if !is_tag {
505 return None;
506 }
507 match kv.get(1).map(|f| &f.kind) {
508 Some(FormKind::Symbol(s)) => Some(strip_tag_ns(s)),
509 Some(FormKind::Str(s)) => Some(strip_tag_ns(s)),
510 _ => None,
511 }
512 }),
513 _ => None,
514 }
515}
516
517fn strip_tag_ns(s: &str) -> Arc<str> {
519 match s.rfind('/') {
520 Some(pos) if pos + 1 < s.len() => Arc::from(&s[pos + 1..]),
521 _ => Arc::from(s),
522 }
523}
524
525fn eval_if(args: &[Form], env: &mut Env) -> EvalResult {
528 if args.is_empty() {
529 return Err(EvalError::Runtime("if requires a test".into()));
530 }
531 let test = eval(&args[0], env)?;
532 let truthy = !matches!(test, Value::Nil | Value::Bool(false));
533 if truthy {
534 if args.len() > 1 {
535 eval(&args[1], env)
536 } else {
537 Ok(Value::Nil)
538 }
539 } else if args.len() > 2 {
540 eval(&args[2], env)
541 } else {
542 Ok(Value::Nil)
543 }
544}
545
546fn eval_let(args: &[Form], env: &mut Env) -> EvalResult {
549 let bindings = match args.first().and_then(|f| f.as_vector()) {
550 Some(v) => expand_pairs(v)
551 .map_err(|_| EvalError::Runtime("let* binding vector must have even length".into()))?
552 .into_owned(),
553 None => return Err(EvalError::Runtime("let* requires a binding vector".into())),
554 };
555
556 let body = &args[1..];
557
558 let chains = crate::interp::virtualize::detect_let_chains(&bindings);
560 let virtualizable_chains = find_virtualizable_chains(&chains, &bindings, body);
561
562 env.with_frame(|env| {
563 let pairs: Vec<_> = bindings.chunks(2).collect();
564 let mut i = 0;
565 while i < pairs.len() {
566 if let Some(chain) = virtualizable_chains.iter().find(|c| c.start == i) {
568 match eval_virtualized_chain(chain, &pairs, env) {
569 Ok(()) => {
570 i += chain.len;
571 continue;
572 }
573 Err(e) => {
574 return Err(e);
575 }
576 }
577 }
578
579 let pair = pairs[i];
581 let val = eval(&pair[1], env)?;
582 bind_pattern(&pair[0], val, env)?;
583 i += 1;
584 }
585
586 eval_body(body, env)
587 })
588}
589
590fn find_virtualizable_chains<'a>(
595 chains: &'a [crate::interp::virtualize::LetChain],
596 bindings: &[Form],
597 body: &[Form],
598) -> Vec<&'a crate::interp::virtualize::LetChain> {
599 chains
600 .iter()
601 .filter(|chain| {
602 for j in chain.start..(chain.start + chain.len - 1) {
605 let name = match &bindings[j * 2].kind {
606 FormKind::Symbol(s) => s.as_str(),
607 _ => return false,
608 };
609 if crate::interp::virtualize::binding_used_in_body(name, body) {
610 return false;
611 }
612 if crate::interp::virtualize::binding_used_in_other_bindings(
613 name,
614 bindings,
615 chain.start,
616 chain.len,
617 ) {
618 return false;
619 }
620 }
621 true
622 })
623 .collect()
624}
625
626fn eval_virtualized_chain(
636 chain: &crate::interp::virtualize::LetChain,
637 pairs: &[&[Form]],
638 env: &mut Env,
639) -> Result<(), EvalError> {
640 use crate::builtins::transients::{
641 builtin_assoc_bang, builtin_conj_bang, builtin_persistent_bang, builtin_transient,
642 };
643
644 let first_pair = pairs[chain.start];
646 let first_expr_forms = match &first_pair[1].kind {
647 FormKind::List(forms) => forms,
648 _ => unreachable!("chain detection ensures this is a list"),
649 };
650 let root_collection = eval(&first_expr_forms[1], env)?;
651
652 let mut transient = match builtin_transient(std::slice::from_ref(&root_collection)) {
654 Ok(t) => t,
655 Err(_) => {
656 return eval_chain_normally(chain, pairs, env);
659 }
660 };
661
662 for j in 0..chain.len {
664 let pair_idx = chain.start + j;
665 let pair = pairs[pair_idx];
666 let expr_forms = match &pair[1].kind {
667 FormKind::List(forms) => forms,
668 _ => unreachable!(),
669 };
670
671 let mut args = vec![transient.clone()];
673 for arg_form in expr_forms.iter().skip(2) {
674 args.push(eval(arg_form, env)?);
675 }
676
677 transient = match chain.ops[j] {
679 crate::interp::virtualize::ChainOpKind::Assoc => {
680 builtin_assoc_bang(&args).map_err(|e| EvalError::Runtime(e.to_string()))?
681 }
682 crate::interp::virtualize::ChainOpKind::Conj => {
683 builtin_conj_bang(&args).map_err(|e| EvalError::Runtime(e.to_string()))?
684 }
685 };
686
687 if j < chain.len - 1 {
691 let name = match &pair[0].kind {
692 FormKind::Symbol(s) => s.clone(),
693 _ => unreachable!(),
694 };
695 env.bind(Arc::from(name.as_str()), Value::Nil);
697 }
698 }
699
700 let persistent =
702 builtin_persistent_bang(&[transient]).map_err(|e| EvalError::Runtime(e.to_string()))?;
703
704 let last_pair = pairs[chain.start + chain.len - 1];
706 bind_pattern(&last_pair[0], persistent, env)?;
707
708 Ok(())
709}
710
711fn eval_chain_normally(
713 chain: &crate::interp::virtualize::LetChain,
714 pairs: &[&[Form]],
715 env: &mut Env,
716) -> Result<(), EvalError> {
717 for j in 0..chain.len {
718 let pair_idx = chain.start + j;
719 let pair = pairs[pair_idx];
720 let val = eval(&pair[1], env)?;
721 bind_pattern(&pair[0], val, env)?;
722 }
723 Ok(())
724}
725
726pub fn eval_loop(args: &[Form], env: &mut Env) -> EvalResult {
729 let bindings = match args.first().and_then(|f| f.as_vector()) {
730 Some(v) => expand_pairs(v)
731 .map_err(|_| EvalError::Runtime("loop* binding vector must have even length".into()))?
732 .into_owned(),
733 None => return Err(EvalError::Runtime("loop* requires a binding vector".into())),
734 };
735
736 let body = &args[1..];
737
738 let patterns: Vec<Form> = bindings.iter().step_by(2).cloned().collect();
740 let mut current_vals: Vec<Value> = Vec::new();
741
742 #[cfg(feature = "no-gc")]
743 let mut initial_scope = cljrs_gc::alloc_ctx::ScratchGuard::new();
744 for i in (1..bindings.len()).step_by(2) {
745 match eval(&bindings[i], env) {
746 Ok(value) => current_vals.push(value),
747 Err(error) => {
748 #[cfg(feature = "no-gc")]
749 {
750 initial_scope.pop_for_return();
751 return crate::interp::eval::publish_result(Err(error), None);
752 }
753 #[cfg(not(feature = "no-gc"))]
754 return Err(error);
755 }
756 }
757 }
758 #[cfg(feature = "no-gc")]
759 let mut recur_lease = cljrs_gc::region::RegionLease::for_values(¤t_vals);
760 #[cfg(feature = "no-gc")]
761 drop(initial_scope);
762 loop {
763 let _vals_root = crate::env::gc_roots::root_values(¤t_vals);
765
766 crate::env::gc_roots::gc_safepoint(env)?;
769
770 #[cfg(feature = "no-gc")]
774 let mut scratch = cljrs_gc::alloc_ctx::ScratchGuard::new();
775
776 #[cfg(not(feature = "no-gc"))]
787 let _iter_frame = cljrs_gc::push_alloc_frame();
788
789 let result = env.with_frame(|env| {
790 for (pat, val) in patterns.iter().zip(current_vals.iter()) {
791 bind_pattern(pat, val.clone(), env)?;
792 }
793
794 #[cfg(not(feature = "no-gc"))]
797 let result = eval_body_recur(body, env);
798 #[cfg(feature = "no-gc")]
799 let result = crate::interp::apply::eval_body_with_scratch(
800 body,
801 &mut scratch,
802 &mut recur_lease,
803 env,
804 );
805
806 result
807 });
808 match result {
812 Ok(v) => return Ok(v),
813 Err(EvalError::Recur(new_vals)) => {
814 if new_vals.len() != patterns.len() {
815 return Err(EvalError::Arity {
816 name: "recur".into(),
817 expected: patterns.len().to_string(),
818 got: new_vals.len(),
819 });
820 }
821 current_vals = new_vals;
824 }
825 Err(e) => return Err(e),
826 }
827 }
828}
829
830fn eval_recur(args: &[Form], env: &mut Env) -> EvalResult {
831 let vals: Vec<Value> = args
832 .iter()
833 .map(|f| eval(f, env))
834 .collect::<EvalResult<_>>()?;
835 Err(EvalError::Recur(vals))
836}
837
838pub fn eval_body_recur(body: &[Form], env: &mut Env) -> EvalResult {
840 let mut result = Value::Nil;
841 for form in body {
842 result = eval(form, env)?;
843 }
844 Ok(result)
845}
846
847fn eval_quote(args: &[Form], env: &Env) -> EvalResult {
850 match args.first() {
851 Some(f) => form_to_value(&resolve_auto_forms(f, env)?),
855 None => Err(EvalError::Runtime("quote requires an argument".into())),
856 }
857}
858
859fn eval_var(args: &[Form], env: &mut Env) -> EvalResult {
862 let sym = match args.first().map(|f| &f.kind) {
863 Some(FormKind::Symbol(s)) => s.clone(),
864 _ => return Err(EvalError::Runtime("var requires a symbol".into())),
865 };
866 let parsed = cljrs_value::Symbol::parse(&sym);
867 let ns: Arc<str> = env.resolve_ns_or_current(parsed.namespace.as_deref());
868 let name = parsed.name.as_ref();
869 env.globals
870 .lookup_var_in_ns(&ns, name)
871 .map(Value::Var)
872 .ok_or_else(|| EvalError::UnboundSymbol(sym))
873}
874
875fn eval_set_bang(args: &[Form], env: &mut Env) -> EvalResult {
878 let target = args
879 .first()
880 .ok_or_else(|| EvalError::Runtime("set! requires a target".into()))?;
881 let val = if args.len() > 1 {
882 eval(&args[1], env)?
883 } else {
884 Value::Nil
885 };
886 match &target.kind {
887 FormKind::Symbol(sym) => set_bang_symbol(sym, val, env),
888 _ => match set_bang_field_target(target) {
889 Some((field, inst_form)) => {
890 let inst = eval(inst_form, env)?;
891 set_type_instance_field(&inst, field, val)
892 }
893 None => Err(set_bang_target_error()),
894 },
895 }
896}
897
898pub fn set_bang_symbol(sym: &str, val: Value, env: &mut Env) -> EvalResult {
901 if !sym.contains('/')
904 && let Some(v) = try_set_mutable_field(env, sym, &val)?
905 {
906 return Ok(v);
907 }
908 let parsed = cljrs_value::Symbol::parse(sym);
909 let ns = parsed.namespace.as_deref().unwrap_or(&env.current_ns);
910 let var = env
911 .globals
912 .lookup_var_in_ns(ns, &parsed.name)
913 .ok_or_else(|| EvalError::UnboundSymbol(sym.to_string()))?;
914 if !crate::env::dynamics::set_thread_local(&var, val.clone()) {
916 var.get().bind(val.clone());
917 }
918 Ok(val)
919}
920
921pub fn set_bang_field_target(target: &Form) -> Option<(&str, &Form)> {
924 match &target.kind {
925 FormKind::List(parts) if parts.len() == 2 => match &parts[0].kind {
926 FormKind::Symbol(op) if op.starts_with(".-") => Some((&op[2..], &parts[1])),
927 _ => None,
928 },
929 _ => None,
930 }
931}
932
933pub fn set_bang_target_error() -> EvalError {
935 EvalError::Runtime("set! requires a symbol or (.-field inst) target".into())
936}
937
938fn try_set_mutable_field(env: &mut Env, sym: &str, val: &Value) -> EvalResult<Option<Value>> {
943 let Some(Value::TypeInstance(ti)) = env.lookup_local_frames(DEFTYPE_SELF) else {
944 return Ok(None);
945 };
946 let Some(atom) = ti.get().mutable.clone() else {
947 return Ok(None);
948 };
949 let key = Value::keyword(cljrs_value::Keyword::simple(sym));
950 let Value::Map(map) = atom.get().deref() else {
951 return Ok(None);
952 };
953 if map.get(&key).is_none() {
954 return Ok(None);
955 }
956 atom.get().reset(Value::Map(map.assoc(key, val.clone())));
957 env.bind(Arc::from(sym), val.clone());
959 Ok(Some(val.clone()))
960}
961
962pub fn set_type_instance_field(inst: &Value, field: &str, val: Value) -> EvalResult {
964 let Value::TypeInstance(ti) = inst else {
965 return Err(EvalError::Runtime(format!(
966 "set! (.-{field} …): target is not a type instance"
967 )));
968 };
969 let atom = ti.get().mutable.clone().ok_or_else(|| {
970 EvalError::Runtime(format!("set! (.-{field} …): type has no mutable fields"))
971 })?;
972 let key = Value::keyword(cljrs_value::Keyword::simple(field));
973 let map = match atom.get().deref() {
974 Value::Map(m) => m,
975 _ => MapValue::empty(),
976 };
977 if map.get(&key).is_none() {
978 return Err(EvalError::Runtime(format!(
979 "set!: {field} is not a mutable field"
980 )));
981 }
982 atom.get().reset(Value::Map(map.assoc(key, val.clone())));
983 Ok(val)
984}
985
986fn eval_throw(args: &[Form], env: &mut Env) -> EvalResult {
989 let val = match args.first() {
990 Some(f) => eval(f, env)?,
991 None => Value::Nil,
992 };
993 Err(throw_value(val))
994}
995
996pub fn throw_value(val: Value) -> EvalError {
1001 let val = match val {
1002 Value::Error(_) => val,
1003 other => {
1004 let msg = format!("{}", other);
1005 Value::Error(GcPtr::new(ExceptionInfo::new(
1006 ValueError::Other(msg.clone()),
1007 msg,
1008 None,
1009 None,
1010 )))
1011 }
1012 };
1013 EvalError::Thrown(val)
1014}
1015
1016pub struct CatchClause<'a> {
1023 pub type_sym: &'a str,
1024 pub binding: &'a str,
1025 pub body: &'a [Form],
1026}
1027
1028pub fn eval_error_to_value(err: &EvalError) -> Value {
1033 let msg = err.to_string();
1034 Value::Error(GcPtr::new(ExceptionInfo::new(
1035 ValueError::Other(msg.clone()),
1036 msg,
1037 None,
1038 None,
1039 )))
1040}
1041
1042pub fn catch_type_matches(type_name: &str, val: &Value) -> bool {
1046 let short = type_name.rsplit('.').next().unwrap_or(type_name);
1047 match short {
1048 "Object" | "Exception" | "Throwable" | "Error" | "default" => true,
1052 "ExceptionInfo" => matches!(val, Value::Error(_)),
1054 _ => false,
1055 }
1056}
1057
1058fn eval_try(args: &[Form], env: &mut Env) -> EvalResult {
1059 let (body, catches, fin_body) = parse_try_args(args);
1060
1061 let mut result = eval_body(body, env);
1062
1063 let err_opt = match std::mem::replace(&mut result, Ok(Value::Nil)) {
1065 Ok(v) => {
1066 result = Ok(v);
1067 None
1068 }
1069 Err(EvalError::Recur(args)) => {
1070 result = Err(EvalError::Recur(args));
1071 None
1072 }
1073 Err(
1074 error @ (EvalError::GasExhausted
1075 | EvalError::Cancelled
1076 | EvalError::MemoryLimitExceeded(_)),
1077 ) => {
1078 result = Err(error);
1079 None
1080 }
1081 Err(other) => Some(other),
1082 };
1083
1084 if let Some(err) = err_opt {
1085 let thrown_val = match err {
1086 EvalError::Thrown(v) => v,
1087 ref other => eval_error_to_value(other),
1088 };
1089 let mut handled = false;
1090 for c in &catches {
1091 if catch_type_matches(c.type_sym, &thrown_val) {
1092 result = env.with_frame(|env| {
1093 env.bind(Arc::from(c.binding), thrown_val.clone());
1094 eval_body(c.body, env)
1095 });
1096 handled = true;
1097 break;
1098 }
1099 }
1100 if !handled {
1101 result = Err(EvalError::Thrown(thrown_val));
1103 }
1104 }
1105
1106 if !fin_body.is_empty()
1112 && let Err(error) = eval_body(fin_body, env)
1113 && !matches!(&result, Err(pending) if is_resource_error(pending))
1114 {
1115 return Err(error);
1116 }
1117
1118 result
1119}
1120
1121fn is_resource_error(error: &EvalError) -> bool {
1122 matches!(
1123 error,
1124 EvalError::GasExhausted | EvalError::Cancelled | EvalError::MemoryLimitExceeded(_)
1125 )
1126}
1127
1128fn catch_target(f: &Form) -> Option<&str> {
1130 f.as_symbol().or_else(|| f.as_keyword())
1131}
1132
1133pub fn parse_try_args(args: &[Form]) -> (&[Form], Vec<CatchClause<'_>>, &[Form]) {
1137 let mut body_end = args.len();
1138 let mut catches: Vec<CatchClause<'_>> = Vec::new();
1139 let mut fin_body: &[Form] = &[];
1140
1141 for (i, form) in args.iter().enumerate() {
1142 if let Some(parts) = form.as_list()
1143 && let Some(s) = parts.first().and_then(|f| f.as_symbol())
1144 {
1145 if s == "catch" {
1146 if i < body_end {
1147 body_end = i;
1148 }
1149 let type_sym = match parts.get(1) {
1154 Some(f) => match catch_target(f) {
1155 Some(name) => name,
1156 None => match &f.unmeta().kind {
1157 FormKind::ReaderCond {
1158 splicing: false,
1159 clauses,
1160 } => match select_reader_cond(clauses).and_then(catch_target) {
1161 Some(name) => name,
1162 None => continue,
1163 },
1164 _ => continue,
1165 },
1166 },
1167 None => continue,
1168 };
1169 let binding = match parts.get(2).and_then(|f| f.as_symbol()) {
1170 Some(s) => s,
1171 None => continue,
1172 };
1173 catches.push(CatchClause {
1174 type_sym,
1175 binding,
1176 body: &parts[3..],
1177 });
1178 continue;
1179 }
1180 if s == "finally" {
1181 if i < body_end {
1182 body_end = i;
1183 }
1184 fin_body = &parts[1..];
1185 continue;
1186 }
1187 }
1188 }
1189
1190 (&args[..body_end], catches, fin_body)
1191}
1192
1193pub fn eval_defn(args: &[Form], env: &mut Env, private: bool) -> EvalResult {
1196 crate::interp::eval::with_scratch(|| eval_defn_inner(args, env, private))
1197}
1198
1199fn eval_defn_inner(args: &[Form], env: &mut Env, private: bool) -> EvalResult {
1200 let name_form = args
1202 .first()
1203 .ok_or_else(|| EvalError::Runtime("defn requires a symbol name".into()))?;
1204 let (name_metas, name_sym) = name_form.peel_meta();
1205 let (name, mut is_async) = match &name_sym.kind {
1206 FormKind::Symbol(s) => (s.clone(), name_metas.iter().any(|m| m.requests_async())),
1207 _ => return Err(EvalError::Runtime("defn name must be a symbol".into())),
1208 };
1209 let mut rest_start = 1;
1213 let mut docstring: Option<String> = None;
1214 if rest_start < args.len()
1215 && let Some(s) = args[rest_start].as_string()
1216 {
1217 docstring = Some(s.to_string());
1218 rest_start += 1;
1219 }
1220 let mut attr_meta: Option<Value> = None;
1221 if rest_start < args.len() && args[rest_start].as_map().is_some() {
1222 is_async |= args[rest_start].requests_async();
1224 attr_meta = Some(eval(&args[rest_start], env)?);
1225 rest_start += 1;
1226 }
1227 let mut fn_args = vec![Form::new(
1229 FormKind::Symbol(name.to_string()),
1230 args[0].span.clone(),
1231 )];
1232 fn_args.extend_from_slice(&args[rest_start..]);
1233 let mut fn_val = eval_fn(&fn_args, env)?;
1234 if is_async && let Value::Fn(ref mut f) = fn_val {
1235 f.get_mut().is_async = true;
1236 }
1237 let var = env
1238 .globals
1239 .intern(&env.current_ns, Arc::from(name.as_str()), fn_val.clone());
1240 let mut meta = attr_meta;
1241 if let Some(doc) = &docstring {
1242 meta = merge_meta(meta, Some(doc_meta(doc)));
1243 }
1244 meta = merge_meta(meta, arglists_meta(&fn_val, 0));
1245 if private {
1246 meta = merge_meta(meta, Some(private_meta()));
1247 }
1248 if let Some(meta_val) = meta {
1249 var.get().set_meta(meta_val);
1250 }
1251 Ok(Value::Var(var))
1252}
1253
1254fn prepend_macro_params(form: &Form) -> Form {
1262 let span = form.span.clone();
1263 match &form.unmeta().kind {
1264 FormKind::Vector(params) => {
1265 let mut new_params = vec![
1266 Form::new(FormKind::Symbol("&form".to_string()), span.clone()),
1267 Form::new(FormKind::Symbol("&env".to_string()), span.clone()),
1268 ];
1269 new_params.extend_from_slice(params);
1270 Form::new(FormKind::Vector(new_params), span)
1271 }
1272 FormKind::List(forms) => {
1273 if let Some(first) = forms.first() {
1275 let new_params_form = prepend_macro_params(first);
1276 let mut new_forms = vec![new_params_form];
1277 new_forms.extend_from_slice(&forms[1..]);
1278 Form::new(FormKind::List(new_forms), span)
1279 } else {
1280 form.clone()
1281 }
1282 }
1283 _ => form.clone(),
1284 }
1285}
1286
1287fn eval_defmacro(args: &[Form], env: &mut Env) -> EvalResult {
1288 let mut current = args
1291 .first()
1292 .ok_or_else(|| EvalError::Runtime("defmacro requires a symbol at position 0".into()))?
1293 .clone();
1294 let mut name_meta: Option<Value> = None;
1295 while let FormKind::Meta(meta_form, inner) = current.kind {
1296 let meta_val = compile_meta_form(&meta_form, env)?;
1297 name_meta = merge_meta(name_meta, Some(meta_val));
1298 current = *inner;
1299 }
1300 let name = match ¤t.kind {
1301 FormKind::Symbol(s) => s.clone(),
1302 _ => {
1303 return Err(EvalError::Runtime(
1304 "defmacro requires a symbol at position 0".into(),
1305 ));
1306 }
1307 };
1308
1309 let mut rest_start = 1;
1310 let mut docstring: Option<String> = None;
1311 if rest_start < args.len()
1312 && let FormKind::Str(s) = &args[rest_start].kind
1313 {
1314 docstring = Some(s.clone());
1315 rest_start += 1;
1316 }
1317 let mut attr_meta = None;
1318 if rest_start < args.len() && matches!(args[rest_start].kind, FormKind::Map(_)) {
1319 attr_meta = Some(eval(&args[rest_start], env)?);
1320 rest_start += 1;
1321 }
1322 let mut fn_args = vec![Form::new(
1324 FormKind::Symbol(name.to_string()),
1325 args[0].span.clone(),
1326 )];
1327 for form in &args[rest_start..] {
1328 fn_args.push(prepend_macro_params(form));
1329 }
1330 #[cfg(feature = "no-gc")]
1333 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1334 let fn_val = eval_fn(&fn_args, env)?;
1335
1336 let macro_val = match fn_val {
1338 Value::Fn(f) => {
1339 let mut mfn = f.get().clone();
1340 mfn.is_macro = true;
1341 Value::Macro(GcPtr::new_isolated(mfn))
1342 }
1343 other => other,
1344 };
1345
1346 let var = env
1347 .globals
1348 .intern(&env.current_ns, Arc::from(name.as_str()), macro_val.clone());
1349 let mut meta = merge_meta(name_meta, attr_meta);
1350 if let Some(doc) = &docstring {
1351 meta = merge_meta(meta, Some(doc_meta(doc)));
1352 }
1353 meta = merge_meta(meta, arglists_meta(¯o_val, 2));
1355 if let Some(m) = meta {
1356 var.get().set_meta(m);
1357 }
1358 Ok(Value::Var(var))
1359}
1360
1361fn eval_defonce(args: &[Form], env: &mut Env) -> EvalResult {
1364 if args.is_empty() {
1365 return Err(EvalError::Runtime("defonce requires a name".into()));
1366 }
1367 let (name, _meta) = extract_def_name(&args[0], env)?;
1370 if let Some(var) = defonce_existing(&name, env) {
1372 return Ok(var);
1373 }
1374 eval_def(args, env)
1375}
1376
1377fn eval_and(args: &[Form], env: &mut Env) -> EvalResult {
1380 let mut result = Value::Bool(true);
1381 for form in args {
1382 result = eval(form, env)?;
1383 if matches!(result, Value::Nil | Value::Bool(false)) {
1384 return Ok(result);
1385 }
1386 }
1387 Ok(result)
1388}
1389
1390fn eval_or(args: &[Form], env: &mut Env) -> EvalResult {
1391 let mut last = Value::Nil;
1392 for form in args {
1393 last = eval(form, env)?;
1394 if !matches!(last, Value::Nil | Value::Bool(false)) {
1395 return Ok(last);
1396 }
1397 }
1398 Ok(last)
1399}
1400
1401fn eval_require(args: &[Form], env: &mut Env) -> EvalResult {
1404 for arg in args {
1405 let val = eval(arg, env)?;
1406 let spec = parse_require_spec_val(val).map_err(EvalError::Runtime)?;
1407 load_ns(env.globals.clone(), &spec, &env.current_ns)?;
1408 }
1409 Ok(Value::Nil)
1410}
1411
1412fn parse_require_spec_val(val: Value) -> Result<RequireSpec, String> {
1417 match val {
1418 Value::Symbol(s) => {
1419 let sym = s.get();
1420 Ok(RequireSpec {
1421 ns: sym.name.clone(),
1422 version: sym.version.clone(),
1423 alias: None,
1424 refer: RequireRefer::None,
1425 })
1426 }
1427 Value::Vector(v) => {
1428 let items: Vec<Value> = v.get().iter().cloned().collect();
1429 if items.is_empty() {
1430 return Err("require spec vector must not be empty".into());
1431 }
1432 let (ns, version) = match &items[0] {
1433 Value::Symbol(s) => {
1434 let sym = s.get();
1435 (sym.name.clone(), sym.version.clone())
1436 }
1437 other => {
1438 return Err(format!(
1439 "require spec: first element must be a symbol, got {}",
1440 other.type_name()
1441 ));
1442 }
1443 };
1444 let mut alias = None;
1445 let mut refer = RequireRefer::None;
1446 let mut i = 1;
1447 while i < items.len() {
1448 match &items[i] {
1449 Value::Keyword(k) if k.get().name.as_ref() == "as" => {
1450 i += 1;
1451 alias = Some(match items.get(i) {
1452 Some(Value::Symbol(s)) => s.get().name.clone(),
1453 _ => return Err("require :as expects a symbol".into()),
1454 });
1455 }
1456 Value::Keyword(k) if k.get().name.as_ref() == "refer" => {
1457 i += 1;
1458 refer = match items.get(i) {
1459 Some(Value::Keyword(k2)) if k2.get().name.as_ref() == "all" => {
1460 RequireRefer::All
1461 }
1462 Some(Value::Vector(rv)) => {
1463 let names: Vec<Arc<str>> = rv
1464 .get()
1465 .iter()
1466 .map(|v| match v {
1467 Value::Symbol(s) => Ok(s.get().name.clone()),
1468 other => Err(format!(
1469 "require :refer expects symbols, got {}",
1470 other.type_name()
1471 )),
1472 })
1473 .collect::<Result<_, _>>()?;
1474 RequireRefer::Named(names)
1475 }
1476 _ => {
1477 return Err(
1478 "require :refer expects :all or a vector of symbols".into()
1479 );
1480 }
1481 };
1482 }
1483 other => {
1484 return Err(format!(
1485 "require spec: unexpected option {}",
1486 other.type_name()
1487 ));
1488 }
1489 }
1490 i += 1;
1491 }
1492 Ok(RequireSpec {
1493 ns,
1494 version,
1495 alias,
1496 refer,
1497 })
1498 }
1499 other => Err(format!(
1500 "require expects a symbol or vector, got {}",
1501 other.type_name()
1502 )),
1503 }
1504}
1505
1506fn spec_element(form: &Form) -> Option<&Form> {
1510 match &form.kind {
1511 FormKind::ReaderCond { clauses, .. } => select_reader_cond(clauses),
1512 _ => Some(form),
1513 }
1514}
1515
1516pub fn parse_require_spec_form(form: &Form) -> Result<RequireSpec, String> {
1523 match &form.kind {
1524 FormKind::Symbol(s) => {
1525 let sym = cljrs_value::Symbol::parse(s);
1526 Ok(RequireSpec {
1527 ns: sym.name.clone(),
1528 version: sym.version.clone(),
1529 alias: None,
1530 refer: RequireRefer::None,
1531 })
1532 }
1533 FormKind::Vector(items) => {
1534 if items.is_empty() {
1535 return Err("require spec vector must not be empty".into());
1536 }
1537 let head = spec_element(&items[0]).ok_or_else(|| {
1538 "require spec: no reader-conditional branch matched for the namespace".to_string()
1539 })?;
1540 let (ns, version) = match &head.kind {
1541 FormKind::Symbol(s) => {
1542 let sym = cljrs_value::Symbol::parse(s);
1543 (sym.name.clone(), sym.version.clone())
1544 }
1545 _ => return Err("require spec: first element must be a symbol".into()),
1546 };
1547 let mut alias = None;
1548 let mut refer = RequireRefer::None;
1549 let mut i = 1;
1550 while i < items.len() {
1551 let Some(item) = spec_element(&items[i]) else {
1554 i += 1;
1555 continue;
1556 };
1557 match &item.kind {
1558 FormKind::Keyword(k) if k == "as" => {
1559 i += 1;
1560 alias = Some(match items.get(i).map(|f| &f.kind) {
1561 Some(FormKind::Symbol(s)) => Arc::from(s.as_str()),
1562 _ => return Err("require :as expects a symbol".into()),
1563 });
1564 }
1565 FormKind::Keyword(k) if k == "refer" => {
1566 i += 1;
1567 refer = match items.get(i).map(|f| &f.kind) {
1568 Some(FormKind::Keyword(k2)) if k2 == "all" => RequireRefer::All,
1569 Some(FormKind::Vector(rv)) => {
1570 let names: Vec<Arc<str>> = rv
1571 .iter()
1572 .map(|f| match &f.kind {
1573 FormKind::Symbol(s) => Ok(Arc::from(s.as_str())),
1574 _ => Err("require :refer expects symbols".to_string()),
1575 })
1576 .collect::<Result<_, _>>()?;
1577 RequireRefer::Named(names)
1578 }
1579 _ => return Err("require :refer expects :all or a vector".into()),
1580 };
1581 }
1582 _ => return Err(format!("require spec: unexpected form at position {i}")),
1583 }
1584 i += 1;
1585 }
1586 Ok(RequireSpec {
1587 ns,
1588 version,
1589 alias,
1590 refer,
1591 })
1592 }
1593 _ => Err("require spec must be a symbol or vector".into()),
1594 }
1595}
1596
1597fn extract_ns_name_form(form: Option<&Form>, env: &mut Env) -> EvalResult<(String, Option<Value>)> {
1603 let mut current = form
1604 .ok_or_else(|| EvalError::Runtime("ns requires a symbol at position 0".into()))?
1605 .clone();
1606 let mut meta_acc: Option<Value> = None;
1607 while let FormKind::Meta(meta_form, inner) = current.kind {
1608 let meta_val = compile_meta_form(&meta_form, env)?;
1609 meta_acc = merge_meta(meta_acc, Some(meta_val));
1610 current = *inner;
1611 }
1612 match ¤t.kind {
1613 FormKind::Symbol(s) => Ok((s.clone(), meta_acc)),
1614 _ => Err(EvalError::Runtime(
1615 "ns requires a symbol at position 0".into(),
1616 )),
1617 }
1618}
1619
1620fn merge_meta(base: Option<Value>, overlay: Option<Value>) -> Option<Value> {
1623 match (base, overlay) {
1624 (None, None) => None,
1625 (Some(b), None) => Some(b),
1626 (None, Some(o)) => Some(o),
1627 (Some(Value::Map(b)), Some(Value::Map(o))) => {
1628 let mut merged = b;
1629 for (k, v) in o.iter() {
1630 merged = merged.assoc(k.clone(), v.clone());
1631 }
1632 Some(Value::Map(merged))
1633 }
1634 (_, Some(o)) => Some(o),
1635 }
1636}
1637
1638fn parse_refer_clojure_clause(items: &[Form]) -> Result<ReferClojureFilter, String> {
1642 let mut filter = ReferClojureFilter::default();
1643 let items = expand_reader_conds(items);
1644 let mut i = 0;
1645 while i < items.len() {
1646 let FormKind::Keyword(k) = &items[i].kind else {
1647 return Err(":refer-clojure expects keyword options (:exclude, :only, :rename)".into());
1648 };
1649 let arg = items
1650 .get(i + 1)
1651 .ok_or_else(|| format!(":refer-clojure :{k} expects a value"))?;
1652 match k.as_str() {
1653 "exclude" => filter.exclude = symbol_name_set(arg, "exclude")?,
1654 "only" => filter.only = Some(symbol_name_set(arg, "only")?),
1655 "rename" => {
1656 let FormKind::Map(entries) = &arg.kind else {
1657 return Err(":refer-clojure :rename expects a map".into());
1658 };
1659 if entries.len() % 2 != 0 {
1660 return Err(":refer-clojure :rename expects an even-sized map".into());
1661 }
1662 for pair in entries.chunks(2) {
1663 match (&pair[0].kind, &pair[1].kind) {
1664 (FormKind::Symbol(from), FormKind::Symbol(to)) => {
1665 filter
1666 .rename
1667 .insert(Arc::from(from.as_str()), Arc::from(to.as_str()));
1668 }
1669 _ => {
1670 return Err(
1671 ":refer-clojure :rename expects symbol keys and values".into()
1672 );
1673 }
1674 }
1675 }
1676 }
1677 other => return Err(format!(":refer-clojure does not support :{other}")),
1678 }
1679 i += 2;
1680 }
1681 Ok(filter)
1682}
1683
1684fn symbol_name_set(form: &Form, opt: &str) -> Result<HashSet<Arc<str>>, String> {
1686 let FormKind::Vector(items) = &form.kind else {
1687 return Err(format!(":refer-clojure :{opt} expects a vector of symbols"));
1688 };
1689 expand_reader_conds(items)
1690 .iter()
1691 .map(|f| match &f.kind {
1692 FormKind::Symbol(sym) => Ok(Arc::from(sym.as_str())),
1693 _ => Err(format!(":refer-clojure :{opt} expects symbols")),
1694 })
1695 .collect()
1696}
1697
1698fn eval_ns(args: &[Form], env: &mut Env) -> EvalResult {
1699 let (name, name_meta) = extract_ns_name_form(args.first(), env)?;
1700 env.globals.get_or_create_ns(&name);
1701 env.current_ns = Arc::from(name.as_str());
1702 if name != "clojure.core" {
1704 env.globals.refer_core(&name);
1705 }
1706 sync_star_ns(env);
1707
1708 let mut rest = &args[1..];
1710 if matches!(rest.first().map(|f| &f.kind), Some(FormKind::Str(_))) {
1711 rest = &rest[1..];
1712 }
1713 let mut attr_meta = None;
1714 if matches!(rest.first().map(|f| &f.kind), Some(FormKind::Map(_))) {
1715 attr_meta = Some(eval(&rest[0], env)?);
1716 rest = &rest[1..];
1717 }
1718
1719 if let Some(m) = merge_meta(name_meta, attr_meta) {
1720 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1721 ns_ptr.get().set_meta(m);
1722 }
1723
1724 let mut refer_clojure = None;
1735 for clause in rest {
1736 if let FormKind::List(items) = &clause.kind
1737 && matches!(items.first().map(|f| &f.kind), Some(FormKind::Keyword(k)) if k == "refer-clojure")
1738 {
1739 refer_clojure =
1740 Some(parse_refer_clojure_clause(&items[1..]).map_err(EvalError::Runtime)?);
1741 }
1742 }
1743 if name != "clojure.core" {
1744 env.globals
1745 .set_refer_clojure_filter(&name, refer_clojure)
1746 .map_err(EvalError::Runtime)?;
1747 }
1748
1749 for clause in rest {
1750 if let FormKind::List(items) = &clause.kind {
1751 match items.first().map(|f| &f.kind) {
1752 Some(FormKind::Keyword(k)) if k == "require" => {
1753 let expanded = expand_reader_conds(&items[1..]);
1755 for spec_form in &expanded {
1756 let spec =
1757 parse_require_spec_form(spec_form).map_err(EvalError::Runtime)?;
1758 load_ns(env.globals.clone(), &spec, &name)?;
1759 }
1760 }
1761 Some(FormKind::Keyword(k)) if k == "import" => {
1762 for spec in &expand_reader_conds(&items[1..]) {
1763 import_types(env, &name, spec);
1764 }
1765 }
1766 _ => {}
1769 }
1770 }
1771 }
1772
1773 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1774 Ok(Value::Namespace(ns_ptr))
1775}
1776
1777fn import_types(env: &Env, dst_ns: &str, spec: &Form) {
1785 match &spec.unmeta().kind {
1786 FormKind::Vector(items) | FormKind::List(items) => {
1787 let mut syms = items.iter().filter_map(Form::as_symbol);
1788 if let Some(pkg) = syms.next() {
1789 for name in syms {
1790 import_type(env, dst_ns, pkg, name);
1791 }
1792 }
1793 }
1794 FormKind::Symbol(s) => {
1795 if let Some((pkg, name)) = s.rsplit_once('.') {
1796 import_type(env, dst_ns, pkg, name);
1797 }
1798 }
1799 _ => {}
1800 }
1801}
1802
1803fn import_type(env: &Env, dst_ns: &str, pkg: &str, name: &str) {
1808 let demunged = pkg.replace('_', "-");
1809 for ns in [pkg, demunged.as_str()] {
1810 let tag = format!("{ns}.{name}");
1811 let names_type = matches!(
1812 env.globals.lookup_in_ns(ns, name),
1813 Some(Value::Symbol(s)) if s.get().to_string() == tag
1814 );
1815 if names_type {
1816 env.globals.refer_named(dst_ns, ns, &[Arc::from(name)]);
1817 return;
1818 }
1819 }
1820}
1821
1822fn eval_load_file(args: &[Form], env: &mut Env) -> EvalResult {
1825 if args.is_empty() {
1826 return Err(EvalError::Runtime(
1827 "load-file requires a path argument".into(),
1828 ));
1829 }
1830 let path_val = eval(&args[0], env)?;
1831 let path = match &path_val {
1832 Value::Str(s) => s.get().clone(),
1833 v => {
1834 return Err(EvalError::Runtime(format!(
1835 "load-file: expected string, got {}",
1836 v.type_name()
1837 )));
1838 }
1839 };
1840 let src = std::fs::read_to_string(&path)
1841 .map_err(|e| EvalError::Runtime(format!("load-file: {e}")))?;
1842 let mut parser = cljrs_reader::Parser::new(src, path.clone());
1843 let forms = parser
1844 .parse_all()
1845 .map_err(|e| EvalError::Runtime(format!("load-file parse error: {e}")))?;
1846 let mut result = Value::Nil;
1847 for form in forms {
1848 let _alloc_frame = cljrs_gc::push_alloc_frame();
1849 result = eval(&form, env)?;
1850 }
1851 Ok(result)
1852}
1853
1854fn eval_letfn(args: &[Form], env: &mut Env) -> EvalResult {
1857 push_letfn_frame(args, env)?;
1858 let result = eval_body(&args[1..], env);
1859 env.pop_frame();
1860 result
1861}
1862
1863pub fn push_letfn_frame(args: &[Form], env: &mut Env) -> EvalResult<()> {
1869 let bindings = match args.first().and_then(|f| f.as_vector()) {
1878 Some(v) => expand_reader_conds_cow(v).into_owned(),
1879 None => return Err(EvalError::Runtime("letfn requires a binding vector".into())),
1880 };
1881
1882 env.push_frame();
1883
1884 for binding in &bindings {
1887 if let Some(parts) = binding.as_list() {
1888 if parts.is_empty() {
1889 continue;
1890 }
1891 let Some(name) = parts[0].as_symbol() else {
1892 env.pop_frame();
1893 return Err(EvalError::Runtime(
1894 "letfn binding name must be a symbol".into(),
1895 ));
1896 };
1897 env.bind(Arc::from(name), Value::Nil);
1898 }
1899 }
1900
1901 let mut built: Vec<(Arc<str>, Value)> = Vec::new();
1904 for binding in &bindings {
1905 if let Some(parts) = binding.as_list() {
1906 if parts.is_empty() {
1907 continue;
1908 }
1909 let fn_val = match eval_fn(parts, env) {
1912 Ok(v) => v,
1913 Err(e) => {
1914 env.pop_frame();
1915 return Err(e);
1916 }
1917 };
1918 let name: Arc<str> = match parts[0].as_symbol() {
1919 Some(s) => Arc::from(s),
1920 None => unreachable!("pass 1 rejected every non-symbol name"),
1921 };
1922 env.bind(Arc::clone(&name), fn_val.clone());
1923 built.push((name, fn_val));
1924 }
1925 }
1926
1927 for (_, fn_val) in &built {
1932 if let Value::Fn(ptr) = fn_val {
1933 let mut ptr = ptr.clone();
1934 #[allow(unused_mut)]
1935 let mut f = ptr.get_mut();
1936 for i in 0..f.closed_over_names.len() {
1937 let captured = f.closed_over_names[i].clone();
1938 if let Some((_, real)) = built.iter().find(|(n, _)| *n == captured) {
1939 f.closed_over_vals[i] = real.clone();
1940 }
1941 }
1942 }
1943 }
1944
1945 Ok(())
1946}
1947
1948fn eval_in_ns(args: &[Form], env: &mut Env) -> EvalResult {
1951 if args.is_empty() {
1953 return Err(EvalError::Runtime("in-ns requires a namespace name".into()));
1954 }
1955 let ns_val = eval(&args[0], env)?;
1956 let ns_name = extract_ns_name(&ns_val)?;
1957 env.globals.get_or_create_ns(&ns_name);
1958 env.globals.refer_core(&ns_name);
1959 env.current_ns = Arc::from(ns_name.as_str());
1960 sync_star_ns(env);
1961 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1962 Ok(Value::Namespace(ns_ptr))
1963}
1964
1965fn eval_alias(args: &[Form], env: &mut Env) -> EvalResult {
1968 if args.len() < 2 {
1970 return Err(EvalError::Runtime(
1971 "alias requires alias-sym and namespace-sym".into(),
1972 ));
1973 }
1974 let alias_val = eval(&args[0], env)?;
1975 let ns_val = eval(&args[1], env)?;
1976
1977 let alias_name = extract_ns_name(&alias_val)?;
1978 let full_ns = extract_ns_name(&ns_val)?;
1979
1980 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1981 let mut aliases = ns_ptr.get().aliases.lock().unwrap();
1982 aliases.insert(Arc::from(alias_name.as_str()), Arc::from(full_ns.as_str()));
1983 Ok(Value::Nil)
1984}
1985
1986fn extract_ns_name(v: &Value) -> EvalResult<String> {
1988 match v {
1989 Value::Symbol(s) => {
1990 Ok(s.get().name.as_ref().to_string())
1992 }
1993 Value::Str(s) => Ok(s.get().clone()),
1994 Value::Keyword(k) => Ok(k.get().name.as_ref().to_string()),
1995 other => Err(EvalError::Runtime(format!(
1996 "expected a symbol or string for namespace name, got {}",
1997 other.type_name()
1998 ))),
1999 }
2000}
2001
2002fn protocol_method_of(spec: &Value) -> EvalResult<ProtocolMethod> {
2006 let Value::Map(m) = spec.unwrap_meta() else {
2007 return Err(EvalError::Runtime(format!(
2008 "protocol* method spec must be a map, got {}",
2009 spec.type_name()
2010 )));
2011 };
2012 let field = |k: &str| m.get(&Value::keyword(Keyword::simple(k)));
2013 let name: Arc<str> = match field("name") {
2014 Some(Value::Str(s)) => Arc::from(s.get().as_str()),
2015 Some(Value::Symbol(s)) => Arc::from(s.get().name.as_ref()),
2016 Some(Value::Keyword(k)) => Arc::from(k.get().name.as_ref()),
2017 _ => {
2018 return Err(EvalError::Runtime(
2019 "protocol* method spec needs a :name".into(),
2020 ));
2021 }
2022 };
2023 let min_arity = match field("min-arity") {
2024 Some(Value::Long(n)) if n >= 0 => n as usize,
2025 _ => 1,
2026 };
2027 let variadic = !matches!(
2028 field("variadic"),
2029 None | Some(Value::Nil) | Some(Value::Bool(false))
2030 );
2031 Ok(ProtocolMethod {
2032 name,
2033 min_arity,
2034 variadic,
2035 })
2036}
2037
2038fn eval_protocol_star(args: &[Form], env: &mut Env) -> EvalResult {
2047 if args.len() < 2 {
2048 return Err(EvalError::Runtime(
2049 "protocol* requires a name and method specs".into(),
2050 ));
2051 }
2052 let (name, _) = require_sym_meta(args, 0, "protocol*", env)?;
2054 let specs = crate::interp::eval::eval_unscoped(&args[1], env)?;
2055 let specs: Vec<Value> = match specs.unwrap_meta() {
2056 Value::Vector(v) => v.get().iter().cloned().collect(),
2057 Value::Nil => Vec::new(),
2058 v => {
2059 return Err(EvalError::Runtime(format!(
2060 "protocol* method specs must be a vector, got {}",
2061 v.type_name()
2062 )));
2063 }
2064 };
2065 let methods = specs
2066 .iter()
2067 .map(protocol_method_of)
2068 .collect::<EvalResult<Vec<_>>>()?;
2069 let extend_via_metadata = match args.get(2) {
2070 Some(f) => !matches!(
2071 crate::interp::eval::eval_unscoped(f, env)?,
2072 Value::Nil | Value::Bool(false)
2073 ),
2074 None => false,
2075 };
2076 let proto = Protocol::new(
2077 Arc::from(name.as_str()),
2078 env.current_ns.clone(),
2079 methods,
2080 extend_via_metadata,
2081 );
2082 Ok(Value::Protocol(GcPtr::new(proto)))
2083}
2084
2085fn synth_field_scope(
2103 params_form: &Form,
2104 fields: &[Arc<str>],
2105 mutable_fields: &[Arc<str>],
2106 body: &[Form],
2107) -> Option<Vec<Form>> {
2108 let param_forms = match ¶ms_form.kind {
2109 FormKind::Vector(v) => v,
2110 _ => return None,
2111 };
2112 let this_name = match param_forms.first().map(|f| &f.kind) {
2113 Some(FormKind::Symbol(s)) => s.clone(),
2114 _ => return None,
2115 };
2116 let param_names: Vec<&str> = param_forms
2117 .iter()
2118 .filter_map(|f| match &f.kind {
2119 FormKind::Symbol(s) => Some(s.as_str()),
2120 _ => None,
2121 })
2122 .collect();
2123
2124 let span = params_form.span.clone();
2125 let is_mut = |name: &str| mutable_fields.iter().any(|m| m.as_ref() == name);
2126 let mut bindings: Vec<Form> = Vec::new();
2127 for field in fields {
2128 if param_names.contains(&field.as_ref()) {
2129 continue;
2130 }
2131 bindings.push(Form::new(FormKind::Symbol(field.to_string()), span.clone()));
2132 let accessor = if is_mut(field) {
2136 FormKind::List(vec![
2137 Form::new(FormKind::Symbol(format!(".-{field}")), span.clone()),
2138 Form::new(FormKind::Symbol(this_name.clone()), span.clone()),
2139 ])
2140 } else {
2141 FormKind::List(vec![
2142 Form::new(FormKind::Keyword(field.to_string()), span.clone()),
2143 Form::new(FormKind::Symbol(this_name.clone()), span.clone()),
2144 ])
2145 };
2146 bindings.push(Form::new(accessor, span.clone()));
2147 }
2148 if !mutable_fields.is_empty() {
2151 bindings.push(Form::new(
2152 FormKind::Symbol(DEFTYPE_SELF.to_string()),
2153 span.clone(),
2154 ));
2155 bindings.push(Form::new(FormKind::Symbol(this_name.clone()), span.clone()));
2156 }
2157 if bindings.is_empty() {
2158 return None;
2159 }
2160
2161 let mut let_forms = vec![
2162 Form::new(FormKind::Symbol("let*".to_string()), span.clone()),
2163 Form::new(FormKind::Vector(bindings), span.clone()),
2164 ];
2165 let_forms.extend_from_slice(body);
2166 Some(vec![Form::new(FormKind::List(let_forms), span)])
2167}
2168
2169fn build_impl_fn(
2170 parts: &[Form],
2171 fields: &[Arc<str>],
2172 mutable_fields: &[Arc<str>],
2173 env: &mut Env,
2174) -> EvalResult<Value> {
2175 if parts.len() < 2 {
2176 return Err(EvalError::Runtime(
2177 "protocol method impl requires params and body".into(),
2178 ));
2179 }
2180 let params_form = &parts[1];
2182 let body = &parts[2..];
2183 let scoped;
2184 let body: &[Form] = if fields.is_empty() {
2185 body
2186 } else {
2187 match synth_field_scope(params_form, fields, mutable_fields, body) {
2188 Some(v) => {
2189 scoped = v;
2190 &scoped
2191 }
2192 None => body,
2193 }
2194 };
2195 let arity = parse_arity(params_form, body)?;
2196 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
2197 let fn_name: Option<Arc<str>> = parts[0].as_symbol().map(Arc::from);
2198 let cljrs_fn = CljxFn::new(
2199 fn_name,
2200 vec![arity],
2201 closed_over_names,
2202 closed_over_vals,
2203 false,
2204 Arc::clone(&env.current_ns),
2205 );
2206 Ok(Value::Fn(GcPtr::new_isolated(cljrs_fn)))
2207}
2208
2209fn eval_binding(args: &[Form], env: &mut Env) -> EvalResult {
2212 let pairs = match args.first().and_then(|f| f.as_vector()) {
2213 Some(v) => expand_pairs(v)
2214 .map_err(|_| EvalError::Runtime("binding vector must have even count".into()))?
2215 .into_owned(),
2216 None => return Err(EvalError::Runtime("binding requires a vector".into())),
2217 };
2218
2219 let mut frame: HashMap<usize, Value> = HashMap::new();
2220 for pair in pairs.chunks(2) {
2221 let Some(sym_str) = pair[0].as_symbol() else {
2222 return Err(EvalError::Runtime("binding targets must be symbols".into()));
2223 };
2224 let parsed = cljrs_value::Symbol::parse(sym_str);
2225 let ns_part: Arc<str> = env.resolve_ns_or_current(parsed.namespace.as_deref());
2226 let var_ptr = env
2227 .globals
2228 .lookup_var_in_ns(&ns_part, &parsed.name)
2229 .ok_or_else(|| EvalError::UnboundSymbol(sym_str.to_string()))?;
2230 let val = eval(&pair[1], env)?;
2231 frame.insert(crate::env::dynamics::var_key_of(&var_ptr), val);
2232 }
2233
2234 let _guard = crate::env::dynamics::push_frame(frame);
2235 eval_body(&args[1..], env)
2236 }
2238
2239const DEFTYPE_SELF: &str = "__deftype_self__";
2245
2246fn meta_form_is_mutable(meta: &Form) -> bool {
2250 let is_mut_kw = |k: &str| k == "unsynchronized-mutable" || k == "volatile-mutable";
2251 match &meta.kind {
2252 FormKind::Keyword(k) => is_mut_kw(k),
2253 FormKind::Map(entries) => entries.chunks(2).any(|kv| {
2254 matches!(&kv[0].kind, FormKind::Keyword(k) if is_mut_kw(k))
2255 && !matches!(
2256 kv.get(1).map(|f| &f.kind),
2257 None | Some(FormKind::Bool(false)) | Some(FormKind::Nil)
2258 )
2259 }),
2260 FormKind::Quote(inner) => meta_form_is_mutable(inner),
2266 _ => false,
2267 }
2268}
2269
2270fn field_spec_of(form: &Form) -> Option<(Arc<str>, bool)> {
2272 match &form.kind {
2273 FormKind::Symbol(s) => Some((Arc::from(s.as_str()), false)),
2274 FormKind::Meta(meta, inner) => {
2275 let here = meta_form_is_mutable(meta);
2276 field_spec_of(inner).map(|(name, inner_mut)| (name, inner_mut || here))
2277 }
2278 _ => None,
2279 }
2280}
2281
2282fn parse_field_specs(form: &Form, ctx: &str) -> EvalResult<Vec<(Arc<str>, bool)>> {
2284 let Some(fields) = form.as_vector() else {
2287 return Err(EvalError::Runtime(format!(
2288 "{ctx} requires a field vector as second arg"
2289 )));
2290 };
2291 fields
2292 .iter()
2293 .map(|f| {
2294 field_spec_of(f)
2295 .ok_or_else(|| EvalError::Runtime(format!("{ctx} field names must be symbols")))
2296 })
2297 .collect()
2298}
2299
2300fn eval_deftype_star(args: &[Form], env: &mut Env) -> EvalResult {
2308 if args.len() < 2 {
2310 return Err(EvalError::Runtime(
2311 "deftype* requires a name and field vector".into(),
2312 ));
2313 }
2314 let (type_name, _) = require_sym_meta(args, 0, "deftype*", env)?;
2317 let type_tag = qualified_type_tag(&type_name, env);
2318
2319 let specs = parse_field_specs(&args[1], "deftype*")?;
2320 let field_names: Vec<Arc<str>> = specs.iter().map(|(n, _)| n.clone()).collect();
2321 let mutable_names: Vec<Arc<str>> = specs
2322 .iter()
2323 .filter(|(_, m)| *m)
2324 .map(|(n, _)| n.clone())
2325 .collect();
2326
2327 register_impls_for_tag(&type_tag, &args[2..], &field_names, &mutable_names, env)?;
2331 Ok(Value::string(type_tag.to_string()))
2335}
2336
2337fn qualified_type_tag(type_name: &str, env: &Env) -> Arc<str> {
2343 Arc::from(format!("{}.{}", env.current_ns, type_name))
2344}
2345
2346fn resolve_protocol_sym(env: &Env, s: &str) -> Option<GcPtr<Protocol>> {
2359 let parsed = cljrs_value::Symbol::parse(s);
2360 let val = match parsed.namespace.as_deref() {
2361 Some(ns_part) => {
2362 let ns = env.resolve_ns_part(ns_part);
2363 env.globals.lookup_in_ns(&ns, &parsed.name)
2364 }
2365 None => env.globals.lookup_in_ns(&env.current_ns, s),
2366 };
2367 match val {
2368 Some(Value::Protocol(p)) => Some(p),
2369 _ => None,
2370 }
2371}
2372
2373fn register_impls_for_tag(
2376 type_tag: &Arc<str>,
2377 forms: &[Form],
2378 fields: &[Arc<str>],
2379 mutable_fields: &[Arc<str>],
2380 env: &mut Env,
2381) -> EvalResult<()> {
2382 let mut current_proto: Option<GcPtr<cljrs_value::Protocol>> = None;
2383
2384 for form in forms {
2385 match &form.unmeta().kind {
2386 FormKind::Symbol(s) => match resolve_protocol_sym(env, s) {
2387 Some(p) => current_proto = Some(p),
2388 None => {
2389 return Err(EvalError::Runtime(format!(
2390 "reify/defrecord: {} is not a protocol",
2391 s
2392 )));
2393 }
2394 },
2395 FormKind::List(parts) => {
2396 let proto = current_proto.as_ref().ok_or_else(|| {
2397 EvalError::Runtime("reify/defrecord: method impl before protocol name".into())
2398 })?;
2399 if parts.is_empty() {
2400 continue;
2401 }
2402 let method_name: Arc<str> = match parts[0].as_symbol() {
2403 Some(s) => Arc::from(s),
2404 None => continue,
2405 };
2406 let fn_val = build_impl_fn(parts, fields, mutable_fields, env)?;
2407 proto
2408 .get()
2409 .set_implementation(type_tag.clone(), method_name, fn_val);
2410 cljrs_value::bump_protocol_generation();
2411 }
2412 _ => {}
2413 }
2414 }
2415 Ok(())
2416}
2417
2418pub fn sync_star_ns(env: &mut Env) {
2423 if let Some(star_ns_var) = env.globals.lookup_var("clojure.core", "*ns*") {
2424 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
2425 star_ns_var.get().bind(Value::Namespace(ns_ptr));
2426 }
2427}
2428
2429fn require_sym_meta(
2441 args: &[Form],
2442 idx: usize,
2443 form_name: &str,
2444 env: &mut Env,
2445) -> EvalResult<(String, Option<Value>)> {
2446 fn peel(form: &Form, env: &mut Env) -> EvalResult<Option<(String, Option<Value>)>> {
2447 match &form.kind {
2448 FormKind::Symbol(s) => Ok(Some((s.clone(), None))),
2449 FormKind::Meta(meta_form, inner) => {
2451 let meta_val = compile_meta_form(meta_form, env)?;
2452 match peel(inner, env)? {
2453 Some((name, inner_meta)) => {
2454 Ok(Some((name, merge_meta(inner_meta, Some(meta_val)))))
2455 }
2456 None => Ok(None),
2457 }
2458 }
2459 _ => Ok(None),
2460 }
2461 }
2462 let err = || EvalError::Runtime(format!("{form_name} requires a symbol at position {idx}"));
2463 match args.get(idx) {
2464 Some(form) => peel(form, env)?.ok_or_else(err),
2465 None => Err(err()),
2466 }
2467}
2468
2469fn eval_with_out_str(body: &[Form], env: &mut Env) -> EvalResult {
2472 crate::builtins::builtins::push_output_capture();
2473 let result = eval_body(body, env);
2474 let captured = crate::builtins::builtins::pop_output_capture().unwrap_or_default();
2475 result?;
2477 Ok(Value::string(captured))
2478}
2479
2480fn eval_await(args: &[Form], env: &mut Env) -> EvalResult {
2490 if args.is_empty() {
2491 return Err(EvalError::Runtime("await requires one argument".into()));
2492 }
2493 let val = eval(&args[0], env)?;
2494 crate::interp::eval::await_value_sync(val, &env.globals)
2495}