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, eval_body, 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, FutureState, Keyword, MapValue, MultiFn, Protocol, ProtocolFn,
21 ProtocolMethod, ReferClojureFilter, TypeHint, TypeInstance, 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" | "defn-" => eval_defn(args, env),
41 "defmacro" => eval_defmacro(args, env),
42 "defonce" => eval_defonce(args, env),
43 "and" => eval_and(args, env),
44 "or" => eval_or(args, env),
45 "." => Err(EvalError::Runtime("interop not yet implemented".into())),
46 "ns" => eval_ns(args, env),
47 "require" => eval_require(args, env),
48 "letfn" => eval_letfn(args, env),
49 "in-ns" => eval_in_ns(args, env),
50 "alias" => eval_alias(args, env),
51 "defprotocol" => eval_defprotocol(args, env),
52 "extend-type" => eval_extend_type(args, env),
53 "extend-protocol" => eval_extend_protocol(args, env),
54 "defmulti" => eval_defmulti(args, env),
55 "defmethod" => eval_defmethod(args, env),
56 "defrecord" => eval_defrecord(args, env),
57 "reify" => eval_reify(args, env),
58 "load-file" => eval_load_file(args, env),
59 "binding" => eval_binding(args, env),
60 "with-out-str" => eval_with_out_str(args, env),
61 "await" => eval_await(args, env),
62 _ => unreachable!("unknown special form: {head}"),
63 }
64}
65
66fn eval_def(args: &[Form], env: &mut Env) -> EvalResult {
69 if args.is_empty() {
70 return Err(EvalError::Runtime("def requires a name".into()));
71 }
72 let (name, meta_opt) = extract_def_name(&args[0], env)?;
73 let (docstring, val_idx) = if args.len() > 2
75 && let FormKind::Str(s) = &args[1].kind
76 {
77 (Some(s.clone()), 2)
78 } else {
79 (None, 1)
80 };
81 let val = if args.len() > val_idx {
82 #[cfg(feature = "no-gc")]
85 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
86 eval(&args[val_idx], env)?
87 } else {
88 Value::Nil
89 };
90 let var = env
91 .globals
92 .intern(&env.current_ns, Arc::from(name.as_str()), val.clone());
93 let meta = merge_meta(meta_opt, docstring.as_deref().map(doc_meta));
94 if let Some(meta_val) = meta {
95 var.get().set_meta(meta_val);
96 }
97 Ok(Value::Var(var))
98}
99
100fn doc_meta(doc: &str) -> Value {
102 Value::Map(MapValue::empty().assoc(
103 Value::keyword(Keyword::parse("doc")),
104 Value::string(doc.to_string()),
105 ))
106}
107
108fn arglists_meta(fn_val: &Value, skip: usize) -> Option<Value> {
113 let arities = match fn_val {
114 Value::Fn(f) => &f.get().arities,
115 Value::Macro(f) => &f.get().arities,
116 _ => return None,
117 };
118 let lists: Vec<Value> = arities
119 .iter()
120 .map(|a| {
121 let mut syms: Vec<Value> = a
122 .params
123 .iter()
124 .skip(skip)
125 .map(|p| Value::symbol(cljrs_value::Symbol::simple(p.as_ref())))
126 .collect();
127 if let Some(rest) = &a.rest_param {
128 syms.push(Value::symbol(cljrs_value::Symbol::simple("&")));
129 syms.push(Value::symbol(cljrs_value::Symbol::simple(rest.as_ref())));
130 }
131 Value::Vector(GcPtr::new(cljrs_value::PersistentVector::from_iter(syms)))
132 })
133 .collect();
134 Some(Value::Map(MapValue::empty().assoc(
135 Value::keyword(Keyword::parse("arglists")),
136 Value::Vector(GcPtr::new(cljrs_value::PersistentVector::from_iter(lists))),
137 )))
138}
139
140fn extract_def_name(form: &Form, env: &mut Env) -> EvalResult<(String, Option<Value>)> {
142 match &form.kind {
143 FormKind::Symbol(s) => Ok((s.clone(), None)),
144 FormKind::Meta(meta_form, inner) => {
146 let meta_val = compile_meta_form(meta_form, env)?;
147 let (name, inner_meta) = extract_def_name(inner, env)?;
148 Ok((name, merge_meta(inner_meta, Some(meta_val))))
149 }
150 _ => Err(EvalError::Runtime("def name must be a symbol".into())),
151 }
152}
153
154fn compile_meta_form(meta: &Form, env: &mut Env) -> EvalResult<Value> {
156 match &meta.kind {
157 FormKind::Keyword(k) => {
158 let m = MapValue::empty().assoc(Value::keyword(Keyword::parse(k)), Value::Bool(true));
160 Ok(Value::Map(m))
161 }
162 FormKind::Symbol(s) => {
163 let m = MapValue::empty().assoc(
165 Value::keyword(Keyword::parse("tag")),
166 Value::string(s.clone()),
167 );
168 Ok(Value::Map(m))
169 }
170 _ => eval(meta, env), }
172}
173
174pub fn meta_form_is_async(meta: &Form) -> bool {
181 match &meta.kind {
182 FormKind::Keyword(k) => k == "async",
183 FormKind::Map(entries) => entries.chunks(2).any(|kv| {
184 matches!(&kv[0].kind, FormKind::Keyword(k) if k == "async")
185 && !matches!(
186 kv.get(1).map(|f| &f.kind),
187 None | Some(FormKind::Bool(false)) | Some(FormKind::Nil)
188 )
189 }),
190 _ => false,
191 }
192}
193
194fn eval_fn(args: &[Form], env: &mut Env) -> EvalResult {
195 let mut is_async = false;
198 let peeled: Vec<Form>;
199 let args: &[Form] = if matches!(args.first().map(|f| &f.kind), Some(FormKind::Meta(..))) {
200 let mut head = args[0].clone();
201 while let FormKind::Meta(meta, inner) = head.kind {
202 is_async |= meta_form_is_async(&meta);
203 head = *inner;
204 }
205 peeled = std::iter::once(head)
206 .chain(args[1..].iter().cloned())
207 .collect();
208 &peeled
209 } else {
210 args
211 };
212
213 let mut idx = 0;
214 let mut name: Option<Arc<str>> = None;
215
216 if let Some(FormKind::Symbol(s)) = args.first().map(|f| &f.kind)
218 && !is_special_form(s)
219 {
220 name = Some(Arc::from(s.as_str()));
221 idx = 1;
222 }
223
224 let rest = &args[idx..];
225 if rest.is_empty() {
226 return Err(EvalError::Runtime("fn* requires params and body".into()));
227 }
228
229 let arities = match &rest[0].kind {
230 FormKind::Vector(_) => {
231 vec![parse_arity(&rest[0], &rest[1..])?]
233 }
234 FormKind::List(_) => {
235 rest.iter()
237 .map(|arity_form| {
238 if let FormKind::List(forms) = &arity_form.kind {
239 if forms.is_empty() {
240 return Err(EvalError::Runtime("arity clause requires params".into()));
241 }
242 parse_arity(&forms[0], &forms[1..])
243 } else {
244 Err(EvalError::Runtime("expected arity clause (list)".into()))
245 }
246 })
247 .collect::<EvalResult<Vec<_>>>()?
248 }
249 _ => {
250 return Err(EvalError::Runtime(
251 "fn* expects vector or arity clauses".into(),
252 ));
253 }
254 };
255
256 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
258
259 let mut cljrs_fn = CljxFn::new(
260 name.clone(),
261 arities,
262 closed_over_names,
263 closed_over_vals,
264 false,
265 Arc::clone(&env.current_ns),
266 );
267 cljrs_fn.is_async = is_async;
268
269 env.on_fn_defined(&cljrs_fn);
270
271 let mut ptr = GcPtr::new(cljrs_fn);
275 if ptr.get().name.is_some() {
279 let self_clone = ptr.clone();
280 ptr.get_mut().self_ptr = Some(self_clone);
281 }
282 Ok(Value::Fn(ptr))
283}
284
285pub fn parse_arity(params_form: &Form, body: &[Form]) -> EvalResult<CljxFnArity> {
287 let param_forms = match ¶ms_form.kind {
288 FormKind::Vector(v) => v,
289 _ => {
290 return Err(EvalError::Runtime(
291 "fn arity params must be a vector".into(),
292 ));
293 }
294 };
295
296 let mut params: Vec<Arc<str>> = Vec::new();
297 let mut param_hints: Vec<Option<TypeHint>> = Vec::new();
298 let mut rest_param: Option<Arc<str>> = None;
299 let mut rest_hint: Option<TypeHint> = None;
300 let mut destructure_params: Vec<(usize, Form)> = Vec::new();
301 let mut destructure_rest: Option<Form> = None;
302 let mut saw_amp = false;
303
304 for p in param_forms {
305 let (hint, p) = peel_param_hint(p);
311 match &p.kind {
312 FormKind::Symbol(s) if s == "&" => {
313 saw_amp = true;
314 }
315 FormKind::Symbol(s) => {
316 if saw_amp {
317 rest_param = Some(Arc::from(s.as_str()));
318 rest_hint = hint;
319 break;
320 } else {
321 params.push(Arc::from(s.as_str()));
322 param_hints.push(hint);
323 }
324 }
325 FormKind::Vector(_) | FormKind::Map(_) => {
327 if saw_amp {
328 let gensym = format!("__destructure_rest_{}", params.len());
329 rest_param = Some(Arc::from(gensym.as_str()));
330 destructure_rest = Some(p.clone());
331 break;
332 } else {
333 let idx = params.len();
334 let gensym = format!("__destructure_{idx}");
335 params.push(Arc::from(gensym.as_str()));
336 param_hints.push(None);
338 destructure_params.push((idx, p.clone()));
339 }
340 }
341 _ => {
342 return Err(EvalError::Runtime(
343 "fn params must be symbols, vectors, or maps".into(),
344 ));
345 }
346 }
347 }
348
349 let body = desugar_pre_post_conditions(body);
350
351 Ok(CljxFnArity {
352 params,
353 rest_param,
354 body,
355 destructure_params,
356 destructure_rest,
357 ir_arity_id: crate::interp::arity::fresh_arity_id(),
358 param_hints,
359 rest_hint,
360 })
361}
362
363fn desugar_pre_post_conditions(body: &[Form]) -> Vec<Form> {
381 let first = match body.first() {
382 Some(f) => f,
383 None => return body.to_vec(),
384 };
385
386 let entries = match &first.kind {
387 FormKind::Map(entries) => entries,
388 _ => return body.to_vec(),
389 };
390
391 let mut pre_conds: Vec<Form> = Vec::new();
392 let mut post_conds: Vec<Form> = Vec::new();
393 let mut has_conditions = false;
394
395 for chunk in entries.chunks(2) {
396 if chunk.len() < 2 {
397 break;
398 }
399 let (key, val) = (&chunk[0], &chunk[1]);
400 match &key.kind {
401 FormKind::Keyword(k) if k == "pre" => {
402 if let FormKind::Vector(conds) = &val.kind {
403 pre_conds.extend_from_slice(conds);
404 has_conditions = true;
405 }
406 }
407 FormKind::Keyword(k) if k == "post" => {
408 if let FormKind::Vector(conds) = &val.kind {
409 post_conds.extend_from_slice(conds);
410 has_conditions = true;
411 }
412 }
413 _ => {}
414 }
415 }
416
417 if !has_conditions {
418 return body.to_vec();
419 }
420
421 let real_body = &body[1..]; let span = first.span.clone();
423 let mut new_body: Vec<Form> = Vec::new();
424
425 for cond in &pre_conds {
427 new_body.push(make_assert_call(cond, &span));
428 }
429
430 if post_conds.is_empty() {
431 new_body.extend_from_slice(real_body);
432 } else {
433 let percent = Form::new(FormKind::Symbol("%".to_string()), span.clone());
436
437 let body_expr = if real_body.len() == 1 {
438 real_body[0].clone()
439 } else {
440 let mut do_forms = vec![Form::new(FormKind::Symbol("do".to_string()), span.clone())];
441 do_forms.extend_from_slice(real_body);
442 Form::new(FormKind::List(do_forms), span.clone())
443 };
444
445 let binding_vec = Form::new(
446 FormKind::Vector(vec![percent.clone(), body_expr]),
447 span.clone(),
448 );
449
450 let mut let_forms = vec![
451 Form::new(FormKind::Symbol("let*".to_string()), span.clone()),
452 binding_vec,
453 ];
454 for cond in &post_conds {
455 let_forms.push(make_assert_call(cond, &span));
456 }
457 let_forms.push(percent);
458
459 new_body.push(Form::new(FormKind::List(let_forms), span));
460 }
461
462 new_body
463}
464
465fn make_assert_call(cond: &Form, span: &cljrs_types::span::Span) -> Form {
467 Form::new(
468 FormKind::List(vec![
469 Form::new(FormKind::Symbol("assert".to_string()), span.clone()),
470 cond.clone(),
471 ]),
472 span.clone(),
473 )
474}
475
476fn peel_param_hint(p: &Form) -> (Option<TypeHint>, &Form) {
480 if let FormKind::Meta(meta, inner) = &p.kind {
481 let hint = tag_name_of_meta(meta).and_then(|n| TypeHint::from_tag(&n));
482 let (inner_hint, inner_form) = peel_param_hint(inner);
484 (hint.or(inner_hint), inner_form)
485 } else {
486 (None, p)
487 }
488}
489
490fn tag_name_of_meta(meta: &Form) -> Option<Arc<str>> {
493 match &meta.kind {
494 FormKind::Symbol(s) => Some(strip_tag_ns(s)),
496 FormKind::Map(entries) => entries.chunks(2).find_map(|kv| {
498 let is_tag = matches!(&kv[0].kind, FormKind::Keyword(k) if k == "tag");
499 if !is_tag {
500 return None;
501 }
502 match kv.get(1).map(|f| &f.kind) {
503 Some(FormKind::Symbol(s)) => Some(strip_tag_ns(s)),
504 Some(FormKind::Str(s)) => Some(strip_tag_ns(s)),
505 _ => None,
506 }
507 }),
508 _ => None,
509 }
510}
511
512fn strip_tag_ns(s: &str) -> Arc<str> {
514 match s.rfind('/') {
515 Some(pos) if pos + 1 < s.len() => Arc::from(&s[pos + 1..]),
516 _ => Arc::from(s),
517 }
518}
519
520fn eval_if(args: &[Form], env: &mut Env) -> EvalResult {
523 if args.is_empty() {
524 return Err(EvalError::Runtime("if requires a test".into()));
525 }
526 let test = eval(&args[0], env)?;
527 let truthy = !matches!(test, Value::Nil | Value::Bool(false));
528 if truthy {
529 if args.len() > 1 {
530 eval(&args[1], env)
531 } else {
532 Ok(Value::Nil)
533 }
534 } else if args.len() > 2 {
535 eval(&args[2], env)
536 } else {
537 Ok(Value::Nil)
538 }
539}
540
541fn eval_let(args: &[Form], env: &mut Env) -> EvalResult {
544 let bindings = match args.first().map(|f| &f.kind) {
545 Some(FormKind::Vector(v)) => expand_pairs(v)
546 .map_err(|_| EvalError::Runtime("let* binding vector must have even length".into()))?
547 .into_owned(),
548 _ => return Err(EvalError::Runtime("let* requires a binding vector".into())),
549 };
550
551 let body = &args[1..];
552
553 let chains = crate::interp::virtualize::detect_let_chains(&bindings);
555 let virtualizable_chains = find_virtualizable_chains(&chains, &bindings, body);
556
557 env.push_frame();
558
559 let pairs: Vec<_> = bindings.chunks(2).collect();
560 let mut i = 0;
561 while i < pairs.len() {
562 if let Some(chain) = virtualizable_chains.iter().find(|c| c.start == i) {
564 match eval_virtualized_chain(chain, &pairs, env) {
565 Ok(()) => {
566 i += chain.len;
567 continue;
568 }
569 Err(e) => {
570 env.pop_frame();
571 return Err(e);
572 }
573 }
574 }
575
576 let pair = pairs[i];
578 let val = match eval(&pair[1], env) {
579 Ok(v) => v,
580 Err(e) => {
581 env.pop_frame();
582 return Err(e);
583 }
584 };
585 if let Err(e) = bind_pattern(&pair[0], val, env) {
586 env.pop_frame();
587 return Err(e);
588 }
589 i += 1;
590 }
591
592 let result = eval_body(body, env);
593 env.pop_frame();
594 result
595}
596
597fn find_virtualizable_chains<'a>(
602 chains: &'a [crate::interp::virtualize::LetChain],
603 bindings: &[Form],
604 body: &[Form],
605) -> Vec<&'a crate::interp::virtualize::LetChain> {
606 chains
607 .iter()
608 .filter(|chain| {
609 for j in chain.start..(chain.start + chain.len - 1) {
612 let name = match &bindings[j * 2].kind {
613 FormKind::Symbol(s) => s.as_str(),
614 _ => return false,
615 };
616 if crate::interp::virtualize::binding_used_in_body(name, body) {
617 return false;
618 }
619 if crate::interp::virtualize::binding_used_in_other_bindings(
620 name,
621 bindings,
622 chain.start,
623 chain.len,
624 ) {
625 return false;
626 }
627 }
628 true
629 })
630 .collect()
631}
632
633fn eval_virtualized_chain(
643 chain: &crate::interp::virtualize::LetChain,
644 pairs: &[&[Form]],
645 env: &mut Env,
646) -> Result<(), EvalError> {
647 use crate::builtins::transients::{
648 builtin_assoc_bang, builtin_conj_bang, builtin_persistent_bang, builtin_transient,
649 };
650
651 let first_pair = pairs[chain.start];
653 let first_expr_forms = match &first_pair[1].kind {
654 FormKind::List(forms) => forms,
655 _ => unreachable!("chain detection ensures this is a list"),
656 };
657 let root_collection = eval(&first_expr_forms[1], env)?;
658
659 let mut transient = match builtin_transient(std::slice::from_ref(&root_collection)) {
661 Ok(t) => t,
662 Err(_) => {
663 return eval_chain_normally(chain, pairs, env);
666 }
667 };
668
669 for j in 0..chain.len {
671 let pair_idx = chain.start + j;
672 let pair = pairs[pair_idx];
673 let expr_forms = match &pair[1].kind {
674 FormKind::List(forms) => forms,
675 _ => unreachable!(),
676 };
677
678 let mut args = vec![transient.clone()];
680 for arg_form in expr_forms.iter().skip(2) {
681 args.push(eval(arg_form, env)?);
682 }
683
684 transient = match chain.ops[j] {
686 crate::interp::virtualize::ChainOpKind::Assoc => {
687 builtin_assoc_bang(&args).map_err(|e| EvalError::Runtime(e.to_string()))?
688 }
689 crate::interp::virtualize::ChainOpKind::Conj => {
690 builtin_conj_bang(&args).map_err(|e| EvalError::Runtime(e.to_string()))?
691 }
692 };
693
694 if j < chain.len - 1 {
698 let name = match &pair[0].kind {
699 FormKind::Symbol(s) => s.clone(),
700 _ => unreachable!(),
701 };
702 env.bind(Arc::from(name.as_str()), Value::Nil);
704 }
705 }
706
707 let persistent =
709 builtin_persistent_bang(&[transient]).map_err(|e| EvalError::Runtime(e.to_string()))?;
710
711 let last_pair = pairs[chain.start + chain.len - 1];
713 bind_pattern(&last_pair[0], persistent, env)?;
714
715 Ok(())
716}
717
718fn eval_chain_normally(
720 chain: &crate::interp::virtualize::LetChain,
721 pairs: &[&[Form]],
722 env: &mut Env,
723) -> Result<(), EvalError> {
724 for j in 0..chain.len {
725 let pair_idx = chain.start + j;
726 let pair = pairs[pair_idx];
727 let val = eval(&pair[1], env)?;
728 bind_pattern(&pair[0], val, env)?;
729 }
730 Ok(())
731}
732
733pub fn eval_loop(args: &[Form], env: &mut Env) -> EvalResult {
736 let bindings = match args.first().map(|f| &f.kind) {
737 Some(FormKind::Vector(v)) => expand_pairs(v)
738 .map_err(|_| EvalError::Runtime("loop* binding vector must have even length".into()))?
739 .into_owned(),
740 _ => return Err(EvalError::Runtime("loop* requires a binding vector".into())),
741 };
742
743 let body = &args[1..];
744
745 let patterns: Vec<Form> = bindings.iter().step_by(2).cloned().collect();
747 let mut current_vals: Vec<Value> = Vec::new();
748
749 for i in (1..bindings.len()).step_by(2) {
751 current_vals.push(eval(&bindings[i], env)?);
752 }
753
754 loop {
755 let _vals_root = crate::env::gc_roots::root_values(¤t_vals);
757
758 crate::env::gc_roots::gc_safepoint(env);
761
762 #[cfg(feature = "no-gc")]
766 let mut scratch = cljrs_gc::alloc_ctx::ScratchGuard::new();
767
768 #[cfg(not(feature = "no-gc"))]
779 let _iter_frame = cljrs_gc::push_alloc_frame();
780
781 env.push_frame();
782 for (pat, val) in patterns.iter().zip(current_vals.iter()) {
783 if let Err(e) = bind_pattern(pat, val.clone(), env) {
784 env.pop_frame();
785 return Err(e);
786 }
787 }
788
789 #[cfg(not(feature = "no-gc"))]
792 let result = eval_body_recur(body, env);
793 #[cfg(feature = "no-gc")]
794 let result = eval_body_with_scratch_loop(body, &mut scratch, env);
795
796 env.pop_frame();
797 match result {
801 Ok(v) => return Ok(v),
802 Err(EvalError::Recur(new_vals)) => {
803 if new_vals.len() != patterns.len() {
804 return Err(EvalError::Arity {
805 name: "recur".into(),
806 expected: patterns.len().to_string(),
807 got: new_vals.len(),
808 });
809 }
810 current_vals = new_vals;
813 }
814 Err(e) => return Err(e),
815 }
816 }
817}
818
819fn eval_recur(args: &[Form], env: &mut Env) -> EvalResult {
820 let vals: Vec<Value> = args
821 .iter()
822 .map(|f| eval(f, env))
823 .collect::<EvalResult<_>>()?;
824 Err(EvalError::Recur(vals))
825}
826
827pub fn eval_body_recur(body: &[Form], env: &mut Env) -> EvalResult {
829 let mut result = Value::Nil;
830 for form in body {
831 result = eval(form, env)?;
832 }
833 Ok(result)
834}
835
836#[cfg(feature = "no-gc")]
842fn eval_body_with_scratch_loop(
843 body: &[Form],
844 scratch: &mut cljrs_gc::alloc_ctx::ScratchGuard,
845 env: &mut Env,
846) -> EvalResult {
847 if body.is_empty() {
848 scratch.pop_for_return();
849 return Ok(Value::Nil);
850 }
851 for form in &body[..body.len() - 1] {
852 eval(form, env)?;
853 }
854 scratch.pop_for_return();
855 eval(&body[body.len() - 1], env)
856}
857
858fn eval_quote(args: &[Form], env: &Env) -> EvalResult {
861 match args.first() {
862 Some(f) => form_to_value(&resolve_auto_forms(f, env)?),
866 None => Err(EvalError::Runtime("quote requires an argument".into())),
867 }
868}
869
870fn eval_var(args: &[Form], env: &mut Env) -> EvalResult {
873 let sym = match args.first().map(|f| &f.kind) {
874 Some(FormKind::Symbol(s)) => s.clone(),
875 _ => return Err(EvalError::Runtime("var requires a symbol".into())),
876 };
877 let parsed = cljrs_value::Symbol::parse(&sym);
878 let ns: Arc<str> = match parsed.namespace.as_deref() {
879 Some(ns_part) => env
880 .globals
881 .resolve_alias(&env.current_ns, ns_part)
882 .unwrap_or_else(|| Arc::from(ns_part)),
883 None => env.current_ns.clone(),
884 };
885 let name = parsed.name.as_ref();
886 env.globals
887 .lookup_var_in_ns(&ns, name)
888 .map(Value::Var)
889 .ok_or_else(|| EvalError::UnboundSymbol(sym))
890}
891
892fn eval_set_bang(args: &[Form], env: &mut Env) -> EvalResult {
895 let sym = match args.first().map(|f| &f.kind) {
896 Some(FormKind::Symbol(s)) => s.clone(),
897 _ => return Err(EvalError::Runtime("set! requires a symbol".into())),
898 };
899 let val = if args.len() > 1 {
900 eval(&args[1], env)?
901 } else {
902 Value::Nil
903 };
904 let parsed = cljrs_value::Symbol::parse(&sym);
905 let ns = parsed.namespace.as_deref().unwrap_or(&env.current_ns);
906 let var = env
907 .globals
908 .lookup_var_in_ns(ns, &parsed.name)
909 .ok_or_else(|| EvalError::UnboundSymbol(sym))?;
910 if !crate::env::dynamics::set_thread_local(&var, val.clone()) {
912 var.get().bind(val.clone());
913 }
914 Ok(val)
915}
916
917fn eval_throw(args: &[Form], env: &mut Env) -> EvalResult {
920 let val = match args.first() {
921 Some(f) => eval(f, env)?,
922 None => Value::Nil,
923 };
924 let val = match val {
927 Value::Error(_) => val,
928 other => {
929 let msg = format!("{}", other);
930 Value::Error(GcPtr::new(ExceptionInfo::new(
931 ValueError::Other(msg.clone()),
932 msg,
933 None,
934 None,
935 )))
936 }
937 };
938 Err(EvalError::Thrown(val))
939}
940
941pub struct CatchClause<'a> {
948 pub type_sym: &'a str,
949 pub binding: &'a str,
950 pub body: &'a [Form],
951}
952
953pub fn eval_error_to_value(err: &EvalError) -> Value {
958 let msg = err.to_string();
959 Value::Error(GcPtr::new(ExceptionInfo::new(
960 ValueError::Other(msg.clone()),
961 msg,
962 None,
963 None,
964 )))
965}
966
967pub fn catch_type_matches(type_name: &str, val: &Value) -> bool {
971 let short = type_name.rsplit('.').next().unwrap_or(type_name);
972 match short {
973 "Object" | "Exception" | "Throwable" | "Error" | "default" => true,
977 "ExceptionInfo" => matches!(val, Value::Error(_)),
979 _ => false,
980 }
981}
982
983fn eval_try(args: &[Form], env: &mut Env) -> EvalResult {
984 let (body, catches, fin_body) = parse_try_args(args);
985
986 let mut result = eval_body(body, env);
987
988 let err_opt = match std::mem::replace(&mut result, Ok(Value::Nil)) {
990 Ok(v) => {
991 result = Ok(v);
992 None
993 }
994 Err(EvalError::Recur(args)) => {
995 result = Err(EvalError::Recur(args));
996 None
997 }
998 Err(EvalError::GasExhausted) => {
999 result = Err(EvalError::GasExhausted);
1000 None
1001 }
1002 Err(other) => Some(other),
1003 };
1004
1005 if let Some(err) = err_opt {
1006 let thrown_val = match err {
1007 EvalError::Thrown(v) => v,
1008 ref other => eval_error_to_value(other),
1009 };
1010 let mut handled = false;
1011 for c in &catches {
1012 if catch_type_matches(c.type_sym, &thrown_val) {
1013 env.push_frame();
1014 env.bind(Arc::from(c.binding), thrown_val.clone());
1015 result = eval_body(c.body, env);
1016 env.pop_frame();
1017 handled = true;
1018 break;
1019 }
1020 }
1021 if !handled {
1022 result = Err(EvalError::Thrown(thrown_val));
1024 }
1025 }
1026
1027 if !fin_body.is_empty() {
1031 eval_body(fin_body, env)?;
1032 }
1033
1034 result
1035}
1036
1037pub fn parse_try_args(args: &[Form]) -> (&[Form], Vec<CatchClause<'_>>, &[Form]) {
1041 let mut body_end = args.len();
1042 let mut catches: Vec<CatchClause<'_>> = Vec::new();
1043 let mut fin_body: &[Form] = &[];
1044
1045 for (i, form) in args.iter().enumerate() {
1046 if let FormKind::List(parts) = &form.kind
1047 && let Some(FormKind::Symbol(s)) = parts.first().map(|f| &f.kind)
1048 {
1049 if s == "catch" {
1050 if i < body_end {
1051 body_end = i;
1052 }
1053 let type_sym = match parts.get(1).map(|f| &f.kind) {
1058 Some(FormKind::Symbol(s)) => s.as_str(),
1059 Some(FormKind::Keyword(s)) => s.as_str(),
1060 Some(FormKind::ReaderCond {
1061 splicing: false,
1062 clauses,
1063 }) => match select_reader_cond(clauses).map(|f| &f.kind) {
1064 Some(FormKind::Symbol(s)) => s.as_str(),
1065 Some(FormKind::Keyword(s)) => s.as_str(),
1066 _ => continue,
1067 },
1068 _ => continue,
1069 };
1070 let binding = match parts.get(2).map(|f| &f.kind) {
1071 Some(FormKind::Symbol(s)) => s.as_str(),
1072 _ => continue,
1073 };
1074 catches.push(CatchClause {
1075 type_sym,
1076 binding,
1077 body: &parts[3..],
1078 });
1079 continue;
1080 }
1081 if s == "finally" {
1082 if i < body_end {
1083 body_end = i;
1084 }
1085 fin_body = &parts[1..];
1086 continue;
1087 }
1088 }
1089 }
1090
1091 (&args[..body_end], catches, fin_body)
1092}
1093
1094pub fn eval_defn(args: &[Form], env: &mut Env) -> EvalResult {
1097 let (name, mut is_async) = match args.first().map(|f| &f.kind) {
1099 Some(FormKind::Symbol(s)) => (s.clone(), false),
1100 Some(FormKind::Meta(meta, inner)) => match &inner.kind {
1101 FormKind::Symbol(s) => (s.clone(), meta_form_is_async(meta)),
1102 _ => return Err(EvalError::Runtime("defn name must be a symbol".into())),
1103 },
1104 _ => return Err(EvalError::Runtime("defn requires a symbol name".into())),
1105 };
1106 let mut rest_start = 1;
1110 let mut docstring: Option<String> = None;
1111 if rest_start < args.len()
1112 && let FormKind::Str(s) = &args[rest_start].kind
1113 {
1114 docstring = Some(s.clone());
1115 rest_start += 1;
1116 }
1117 let mut attr_meta: Option<Value> = None;
1118 if rest_start < args.len() && matches!(args[rest_start].kind, FormKind::Map(_)) {
1119 is_async |= meta_form_is_async(&args[rest_start]);
1121 attr_meta = Some(eval(&args[rest_start], env)?);
1122 rest_start += 1;
1123 }
1124 let mut fn_args = vec![Form::new(
1126 FormKind::Symbol(name.to_string()),
1127 args[0].span.clone(),
1128 )];
1129 fn_args.extend_from_slice(&args[rest_start..]);
1130 #[cfg(feature = "no-gc")]
1133 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1134 let mut fn_val = eval_fn(&fn_args, env)?;
1135 if is_async && let Value::Fn(ref mut f) = fn_val {
1136 f.get_mut().is_async = true;
1137 }
1138 let var = env
1139 .globals
1140 .intern(&env.current_ns, Arc::from(name.as_str()), fn_val.clone());
1141 let mut meta = attr_meta;
1142 if let Some(doc) = &docstring {
1143 meta = merge_meta(meta, Some(doc_meta(doc)));
1144 }
1145 meta = merge_meta(meta, arglists_meta(&fn_val, 0));
1146 if let Some(meta_val) = meta {
1147 var.get().set_meta(meta_val);
1148 }
1149 Ok(Value::Var(var))
1150}
1151
1152fn prepend_macro_params(form: &Form) -> Form {
1160 let span = form.span.clone();
1161 match &form.kind {
1162 FormKind::Vector(params) => {
1163 let mut new_params = vec![
1164 Form::new(FormKind::Symbol("&form".to_string()), span.clone()),
1165 Form::new(FormKind::Symbol("&env".to_string()), span.clone()),
1166 ];
1167 new_params.extend_from_slice(params);
1168 Form::new(FormKind::Vector(new_params), span)
1169 }
1170 FormKind::List(forms) => {
1171 if let Some(first) = forms.first() {
1173 let new_params_form = prepend_macro_params(first);
1174 let mut new_forms = vec![new_params_form];
1175 new_forms.extend_from_slice(&forms[1..]);
1176 Form::new(FormKind::List(new_forms), span)
1177 } else {
1178 form.clone()
1179 }
1180 }
1181 _ => form.clone(),
1182 }
1183}
1184
1185fn eval_defmacro(args: &[Form], env: &mut Env) -> EvalResult {
1186 let mut current = args
1189 .first()
1190 .ok_or_else(|| EvalError::Runtime("defmacro requires a symbol at position 0".into()))?
1191 .clone();
1192 let mut name_meta: Option<Value> = None;
1193 while let FormKind::Meta(meta_form, inner) = current.kind {
1194 let meta_val = compile_meta_form(&meta_form, env)?;
1195 name_meta = merge_meta(name_meta, Some(meta_val));
1196 current = *inner;
1197 }
1198 let name = match ¤t.kind {
1199 FormKind::Symbol(s) => s.clone(),
1200 _ => {
1201 return Err(EvalError::Runtime(
1202 "defmacro requires a symbol at position 0".into(),
1203 ));
1204 }
1205 };
1206
1207 let mut rest_start = 1;
1208 let mut docstring: Option<String> = None;
1209 if rest_start < args.len()
1210 && let FormKind::Str(s) = &args[rest_start].kind
1211 {
1212 docstring = Some(s.clone());
1213 rest_start += 1;
1214 }
1215 let mut attr_meta = None;
1216 if rest_start < args.len() && matches!(args[rest_start].kind, FormKind::Map(_)) {
1217 attr_meta = Some(eval(&args[rest_start], env)?);
1218 rest_start += 1;
1219 }
1220 let mut fn_args = vec![Form::new(
1222 FormKind::Symbol(name.to_string()),
1223 args[0].span.clone(),
1224 )];
1225 for form in &args[rest_start..] {
1226 fn_args.push(prepend_macro_params(form));
1227 }
1228 #[cfg(feature = "no-gc")]
1231 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1232 let fn_val = eval_fn(&fn_args, env)?;
1233
1234 let macro_val = match fn_val {
1236 Value::Fn(f) => {
1237 let mut mfn = f.get().clone();
1238 mfn.is_macro = true;
1239 Value::Macro(GcPtr::new(mfn))
1240 }
1241 other => other,
1242 };
1243
1244 let var = env
1245 .globals
1246 .intern(&env.current_ns, Arc::from(name.as_str()), macro_val.clone());
1247 let mut meta = merge_meta(name_meta, attr_meta);
1248 if let Some(doc) = &docstring {
1249 meta = merge_meta(meta, Some(doc_meta(doc)));
1250 }
1251 meta = merge_meta(meta, arglists_meta(¯o_val, 2));
1253 if let Some(m) = meta {
1254 var.get().set_meta(m);
1255 }
1256 Ok(Value::Var(var))
1257}
1258
1259fn eval_defonce(args: &[Form], env: &mut Env) -> EvalResult {
1262 if args.is_empty() {
1263 return Err(EvalError::Runtime("defonce requires a name".into()));
1264 }
1265 let (name, _meta) = extract_def_name(&args[0], env)?;
1268 if let Some(var) = env.globals.lookup_var(&env.current_ns, &name)
1270 && var.get().is_bound()
1271 {
1272 return Ok(Value::Var(var));
1273 }
1274 eval_def(args, env)
1275}
1276
1277fn eval_and(args: &[Form], env: &mut Env) -> EvalResult {
1280 let mut result = Value::Bool(true);
1281 for form in args {
1282 result = eval(form, env)?;
1283 if matches!(result, Value::Nil | Value::Bool(false)) {
1284 return Ok(result);
1285 }
1286 }
1287 Ok(result)
1288}
1289
1290fn eval_or(args: &[Form], env: &mut Env) -> EvalResult {
1291 let mut last = Value::Nil;
1292 for form in args {
1293 last = eval(form, env)?;
1294 if !matches!(last, Value::Nil | Value::Bool(false)) {
1295 return Ok(last);
1296 }
1297 }
1298 Ok(last)
1299}
1300
1301fn eval_require(args: &[Form], env: &mut Env) -> EvalResult {
1304 for arg in args {
1305 let val = eval(arg, env)?;
1306 let spec = parse_require_spec_val(val).map_err(EvalError::Runtime)?;
1307 load_ns(env.globals.clone(), &spec, &env.current_ns)?;
1308 }
1309 Ok(Value::Nil)
1310}
1311
1312fn parse_require_spec_val(val: Value) -> Result<RequireSpec, String> {
1317 match val {
1318 Value::Symbol(s) => {
1319 let sym = s.get();
1320 Ok(RequireSpec {
1321 ns: sym.name.clone(),
1322 version: sym.version.clone(),
1323 alias: None,
1324 refer: RequireRefer::None,
1325 })
1326 }
1327 Value::Vector(v) => {
1328 let items: Vec<Value> = v.get().iter().cloned().collect();
1329 if items.is_empty() {
1330 return Err("require spec vector must not be empty".into());
1331 }
1332 let (ns, version) = match &items[0] {
1333 Value::Symbol(s) => {
1334 let sym = s.get();
1335 (sym.name.clone(), sym.version.clone())
1336 }
1337 other => {
1338 return Err(format!(
1339 "require spec: first element must be a symbol, got {}",
1340 other.type_name()
1341 ));
1342 }
1343 };
1344 let mut alias = None;
1345 let mut refer = RequireRefer::None;
1346 let mut i = 1;
1347 while i < items.len() {
1348 match &items[i] {
1349 Value::Keyword(k) if k.get().name.as_ref() == "as" => {
1350 i += 1;
1351 alias = Some(match items.get(i) {
1352 Some(Value::Symbol(s)) => s.get().name.clone(),
1353 _ => return Err("require :as expects a symbol".into()),
1354 });
1355 }
1356 Value::Keyword(k) if k.get().name.as_ref() == "refer" => {
1357 i += 1;
1358 refer = match items.get(i) {
1359 Some(Value::Keyword(k2)) if k2.get().name.as_ref() == "all" => {
1360 RequireRefer::All
1361 }
1362 Some(Value::Vector(rv)) => {
1363 let names: Vec<Arc<str>> = rv
1364 .get()
1365 .iter()
1366 .map(|v| match v {
1367 Value::Symbol(s) => Ok(s.get().name.clone()),
1368 other => Err(format!(
1369 "require :refer expects symbols, got {}",
1370 other.type_name()
1371 )),
1372 })
1373 .collect::<Result<_, _>>()?;
1374 RequireRefer::Named(names)
1375 }
1376 _ => {
1377 return Err(
1378 "require :refer expects :all or a vector of symbols".into()
1379 );
1380 }
1381 };
1382 }
1383 other => {
1384 return Err(format!(
1385 "require spec: unexpected option {}",
1386 other.type_name()
1387 ));
1388 }
1389 }
1390 i += 1;
1391 }
1392 Ok(RequireSpec {
1393 ns,
1394 version,
1395 alias,
1396 refer,
1397 })
1398 }
1399 other => Err(format!(
1400 "require expects a symbol or vector, got {}",
1401 other.type_name()
1402 )),
1403 }
1404}
1405
1406fn spec_element(form: &Form) -> Option<&Form> {
1410 match &form.kind {
1411 FormKind::ReaderCond { clauses, .. } => select_reader_cond(clauses),
1412 _ => Some(form),
1413 }
1414}
1415
1416fn parse_require_spec_form(form: &Form) -> Result<RequireSpec, String> {
1419 match &form.kind {
1420 FormKind::Symbol(s) => {
1421 let sym = cljrs_value::Symbol::parse(s);
1422 Ok(RequireSpec {
1423 ns: sym.name.clone(),
1424 version: sym.version.clone(),
1425 alias: None,
1426 refer: RequireRefer::None,
1427 })
1428 }
1429 FormKind::Vector(items) => {
1430 if items.is_empty() {
1431 return Err("require spec vector must not be empty".into());
1432 }
1433 let head = spec_element(&items[0]).ok_or_else(|| {
1434 "require spec: no reader-conditional branch matched for the namespace".to_string()
1435 })?;
1436 let (ns, version) = match &head.kind {
1437 FormKind::Symbol(s) => {
1438 let sym = cljrs_value::Symbol::parse(s);
1439 (sym.name.clone(), sym.version.clone())
1440 }
1441 _ => return Err("require spec: first element must be a symbol".into()),
1442 };
1443 let mut alias = None;
1444 let mut refer = RequireRefer::None;
1445 let mut i = 1;
1446 while i < items.len() {
1447 let Some(item) = spec_element(&items[i]) else {
1450 i += 1;
1451 continue;
1452 };
1453 match &item.kind {
1454 FormKind::Keyword(k) if k == "as" => {
1455 i += 1;
1456 alias = Some(match items.get(i).map(|f| &f.kind) {
1457 Some(FormKind::Symbol(s)) => Arc::from(s.as_str()),
1458 _ => return Err("require :as expects a symbol".into()),
1459 });
1460 }
1461 FormKind::Keyword(k) if k == "refer" => {
1462 i += 1;
1463 refer = match items.get(i).map(|f| &f.kind) {
1464 Some(FormKind::Keyword(k2)) if k2 == "all" => RequireRefer::All,
1465 Some(FormKind::Vector(rv)) => {
1466 let names: Vec<Arc<str>> = rv
1467 .iter()
1468 .map(|f| match &f.kind {
1469 FormKind::Symbol(s) => Ok(Arc::from(s.as_str())),
1470 _ => Err("require :refer expects symbols".to_string()),
1471 })
1472 .collect::<Result<_, _>>()?;
1473 RequireRefer::Named(names)
1474 }
1475 _ => return Err("require :refer expects :all or a vector".into()),
1476 };
1477 }
1478 _ => return Err(format!("require spec: unexpected form at position {i}")),
1479 }
1480 i += 1;
1481 }
1482 Ok(RequireSpec {
1483 ns,
1484 version,
1485 alias,
1486 refer,
1487 })
1488 }
1489 _ => Err("require spec must be a symbol or vector".into()),
1490 }
1491}
1492
1493fn extract_ns_name_form(form: Option<&Form>, env: &mut Env) -> EvalResult<(String, Option<Value>)> {
1499 let mut current = form
1500 .ok_or_else(|| EvalError::Runtime("ns requires a symbol at position 0".into()))?
1501 .clone();
1502 let mut meta_acc: Option<Value> = None;
1503 while let FormKind::Meta(meta_form, inner) = current.kind {
1504 let meta_val = compile_meta_form(&meta_form, env)?;
1505 meta_acc = merge_meta(meta_acc, Some(meta_val));
1506 current = *inner;
1507 }
1508 match ¤t.kind {
1509 FormKind::Symbol(s) => Ok((s.clone(), meta_acc)),
1510 _ => Err(EvalError::Runtime(
1511 "ns requires a symbol at position 0".into(),
1512 )),
1513 }
1514}
1515
1516fn merge_meta(base: Option<Value>, overlay: Option<Value>) -> Option<Value> {
1519 match (base, overlay) {
1520 (None, None) => None,
1521 (Some(b), None) => Some(b),
1522 (None, Some(o)) => Some(o),
1523 (Some(Value::Map(b)), Some(Value::Map(o))) => {
1524 let mut merged = b;
1525 for (k, v) in o.iter() {
1526 merged = merged.assoc(k.clone(), v.clone());
1527 }
1528 Some(Value::Map(merged))
1529 }
1530 (_, Some(o)) => Some(o),
1531 }
1532}
1533
1534fn parse_refer_clojure_clause(items: &[Form]) -> Result<ReferClojureFilter, String> {
1538 let mut filter = ReferClojureFilter::default();
1539 let items = expand_reader_conds(items);
1540 let mut i = 0;
1541 while i < items.len() {
1542 let FormKind::Keyword(k) = &items[i].kind else {
1543 return Err(":refer-clojure expects keyword options (:exclude, :only, :rename)".into());
1544 };
1545 let arg = items
1546 .get(i + 1)
1547 .ok_or_else(|| format!(":refer-clojure :{k} expects a value"))?;
1548 match k.as_str() {
1549 "exclude" => filter.exclude = symbol_name_set(arg, "exclude")?,
1550 "only" => filter.only = Some(symbol_name_set(arg, "only")?),
1551 "rename" => {
1552 let FormKind::Map(entries) = &arg.kind else {
1553 return Err(":refer-clojure :rename expects a map".into());
1554 };
1555 if entries.len() % 2 != 0 {
1556 return Err(":refer-clojure :rename expects an even-sized map".into());
1557 }
1558 for pair in entries.chunks(2) {
1559 match (&pair[0].kind, &pair[1].kind) {
1560 (FormKind::Symbol(from), FormKind::Symbol(to)) => {
1561 filter
1562 .rename
1563 .insert(Arc::from(from.as_str()), Arc::from(to.as_str()));
1564 }
1565 _ => {
1566 return Err(
1567 ":refer-clojure :rename expects symbol keys and values".into()
1568 );
1569 }
1570 }
1571 }
1572 }
1573 other => return Err(format!(":refer-clojure does not support :{other}")),
1574 }
1575 i += 2;
1576 }
1577 Ok(filter)
1578}
1579
1580fn symbol_name_set(form: &Form, opt: &str) -> Result<HashSet<Arc<str>>, String> {
1582 let FormKind::Vector(items) = &form.kind else {
1583 return Err(format!(":refer-clojure :{opt} expects a vector of symbols"));
1584 };
1585 expand_reader_conds(items)
1586 .iter()
1587 .map(|f| match &f.kind {
1588 FormKind::Symbol(sym) => Ok(Arc::from(sym.as_str())),
1589 _ => Err(format!(":refer-clojure :{opt} expects symbols")),
1590 })
1591 .collect()
1592}
1593
1594fn eval_ns(args: &[Form], env: &mut Env) -> EvalResult {
1595 let (name, name_meta) = extract_ns_name_form(args.first(), env)?;
1596 env.globals.get_or_create_ns(&name);
1597 env.current_ns = Arc::from(name.as_str());
1598 if name != "clojure.core" {
1600 env.globals.refer_core(&name);
1601 }
1602 sync_star_ns(env);
1603
1604 let mut rest = &args[1..];
1606 if matches!(rest.first().map(|f| &f.kind), Some(FormKind::Str(_))) {
1607 rest = &rest[1..];
1608 }
1609 let mut attr_meta = None;
1610 if matches!(rest.first().map(|f| &f.kind), Some(FormKind::Map(_))) {
1611 attr_meta = Some(eval(&rest[0], env)?);
1612 rest = &rest[1..];
1613 }
1614
1615 if let Some(m) = merge_meta(name_meta, attr_meta) {
1616 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1617 ns_ptr.get().set_meta(m);
1618 }
1619
1620 let mut refer_clojure = None;
1631 for clause in rest {
1632 if let FormKind::List(items) = &clause.kind
1633 && matches!(items.first().map(|f| &f.kind), Some(FormKind::Keyword(k)) if k == "refer-clojure")
1634 {
1635 refer_clojure =
1636 Some(parse_refer_clojure_clause(&items[1..]).map_err(EvalError::Runtime)?);
1637 }
1638 }
1639 if name != "clojure.core" {
1640 env.globals
1641 .set_refer_clojure_filter(&name, refer_clojure)
1642 .map_err(EvalError::Runtime)?;
1643 }
1644
1645 for clause in rest {
1646 if let FormKind::List(items) = &clause.kind {
1647 match items.first().map(|f| &f.kind) {
1648 Some(FormKind::Keyword(k)) if k == "require" => {
1649 let expanded = expand_reader_conds(&items[1..]);
1651 for spec_form in &expanded {
1652 let spec =
1653 parse_require_spec_form(spec_form).map_err(EvalError::Runtime)?;
1654 load_ns(env.globals.clone(), &spec, &name)?;
1655 }
1656 }
1657 _ => {}
1660 }
1661 }
1662 }
1663
1664 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1665 Ok(Value::Namespace(ns_ptr))
1666}
1667
1668fn eval_load_file(args: &[Form], env: &mut Env) -> EvalResult {
1671 if args.is_empty() {
1672 return Err(EvalError::Runtime(
1673 "load-file requires a path argument".into(),
1674 ));
1675 }
1676 let path_val = eval(&args[0], env)?;
1677 let path = match &path_val {
1678 Value::Str(s) => s.get().clone(),
1679 v => {
1680 return Err(EvalError::Runtime(format!(
1681 "load-file: expected string, got {}",
1682 v.type_name()
1683 )));
1684 }
1685 };
1686 let src = std::fs::read_to_string(&path)
1687 .map_err(|e| EvalError::Runtime(format!("load-file: {e}")))?;
1688 let mut parser = cljrs_reader::Parser::new(src, path.clone());
1689 let forms = parser
1690 .parse_all()
1691 .map_err(|e| EvalError::Runtime(format!("load-file parse error: {e}")))?;
1692 let mut result = Value::Nil;
1693 for form in forms {
1694 let _alloc_frame = cljrs_gc::push_alloc_frame();
1695 result = eval(&form, env)?;
1696 }
1697 Ok(result)
1698}
1699
1700fn eval_letfn(args: &[Form], env: &mut Env) -> EvalResult {
1703 let bindings = match args.first().map(|f| &f.kind) {
1705 Some(FormKind::Vector(v)) => expand_reader_conds_cow(v).into_owned(),
1706 _ => return Err(EvalError::Runtime("letfn requires a binding vector".into())),
1707 };
1708
1709 env.push_frame();
1710
1711 for binding in &bindings {
1712 if let FormKind::List(parts) = &binding.kind {
1713 if parts.is_empty() {
1714 continue;
1715 }
1716 let fn_val = match eval_fn(parts, env) {
1720 Ok(v) => v,
1721 Err(e) => {
1722 env.pop_frame();
1723 return Err(e);
1724 }
1725 };
1726 let name = match &parts[0].kind {
1727 FormKind::Symbol(s) => s.clone(),
1728 _ => {
1729 env.pop_frame();
1730 return Err(EvalError::Runtime(
1731 "letfn binding name must be a symbol".into(),
1732 ));
1733 }
1734 };
1735 env.bind(Arc::from(name.as_str()), fn_val);
1736 }
1737 }
1738
1739 let body = &args[1..];
1740 let result = eval_body(body, env);
1741 env.pop_frame();
1742 result
1743}
1744
1745fn eval_in_ns(args: &[Form], env: &mut Env) -> EvalResult {
1748 if args.is_empty() {
1750 return Err(EvalError::Runtime("in-ns requires a namespace name".into()));
1751 }
1752 let ns_val = eval(&args[0], env)?;
1753 let ns_name = extract_ns_name(&ns_val)?;
1754 env.globals.get_or_create_ns(&ns_name);
1755 env.globals.refer_core(&ns_name);
1756 env.current_ns = Arc::from(ns_name.as_str());
1757 sync_star_ns(env);
1758 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1759 Ok(Value::Namespace(ns_ptr))
1760}
1761
1762fn eval_alias(args: &[Form], env: &mut Env) -> EvalResult {
1765 if args.len() < 2 {
1767 return Err(EvalError::Runtime(
1768 "alias requires alias-sym and namespace-sym".into(),
1769 ));
1770 }
1771 let alias_val = eval(&args[0], env)?;
1772 let ns_val = eval(&args[1], env)?;
1773
1774 let alias_name = extract_ns_name(&alias_val)?;
1775 let full_ns = extract_ns_name(&ns_val)?;
1776
1777 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1778 let mut aliases = ns_ptr.get().aliases.lock().unwrap();
1779 aliases.insert(Arc::from(alias_name.as_str()), Arc::from(full_ns.as_str()));
1780 Ok(Value::Nil)
1781}
1782
1783fn extract_ns_name(v: &Value) -> EvalResult<String> {
1785 match v {
1786 Value::Symbol(s) => {
1787 Ok(s.get().name.as_ref().to_string())
1789 }
1790 Value::Str(s) => Ok(s.get().clone()),
1791 Value::Keyword(k) => Ok(k.get().name.as_ref().to_string()),
1792 other => Err(EvalError::Runtime(format!(
1793 "expected a symbol or string for namespace name, got {}",
1794 other.type_name()
1795 ))),
1796 }
1797}
1798
1799fn eval_defprotocol(args: &[Form], env: &mut Env) -> EvalResult {
1802 let name = require_sym(args, 0, "defprotocol")?;
1804 let proto_name: Arc<str> = Arc::from(name);
1805
1806 let methods_start = if args.len() > 1 && matches!(args[1].kind, FormKind::Str(_)) {
1808 2
1809 } else {
1810 1
1811 };
1812
1813 let mut methods: Vec<ProtocolMethod> = Vec::new();
1814 let mut extend_via_metadata = false;
1815
1816 let rest = &args[methods_start..];
1817 let mut i = 0;
1818 while i < rest.len() {
1819 if let FormKind::Keyword(kw) = &rest[i].kind {
1822 if kw == "extend-via-metadata" {
1823 extend_via_metadata =
1824 matches!(rest.get(i + 1).map(|f| &f.kind), Some(FormKind::Bool(true)));
1825 }
1826 i += 2;
1827 continue;
1828 }
1829 let form = &rest[i];
1830 i += 1;
1831 let parts = match &form.kind {
1833 FormKind::List(parts) => parts,
1834 _ => continue, };
1836 if parts.is_empty() {
1837 continue;
1838 }
1839 let method_name = match &parts[0].kind {
1840 FormKind::Symbol(s) => Arc::from(s.as_str()),
1841 _ => continue,
1842 };
1843 let (min_arity, variadic) = if let Some(params_form) =
1845 parts.iter().find(|f| matches!(f.kind, FormKind::Vector(_)))
1846 {
1847 if let FormKind::Vector(param_forms) = ¶ms_form.kind {
1848 let variadic = param_forms
1849 .iter()
1850 .any(|p| matches!(&p.kind, FormKind::Symbol(s) if s == "&"));
1851 let fixed: usize = param_forms
1852 .iter()
1853 .filter(|p| !matches!(&p.kind, FormKind::Symbol(s) if s == "&"))
1854 .count();
1855 (fixed, variadic)
1856 } else {
1857 (1, false)
1858 }
1859 } else {
1860 (1, false)
1861 };
1862 methods.push(ProtocolMethod {
1863 name: method_name,
1864 min_arity,
1865 variadic,
1866 });
1867 }
1868
1869 let ns: Arc<str> = env.current_ns.clone();
1870 let proto = Protocol::new(proto_name.clone(), ns, methods.clone(), extend_via_metadata);
1871 let proto_ptr = GcPtr::new(proto);
1872
1873 let proto_var = env.globals.intern(
1875 &env.current_ns,
1876 proto_name.clone(),
1877 Value::Protocol(proto_ptr.clone()),
1878 );
1879
1880 for method in &methods {
1882 let pf = ProtocolFn {
1883 protocol: proto_ptr.clone(),
1884 method_name: method.name.clone(),
1885 min_arity: method.min_arity,
1886 variadic: method.variadic,
1887 };
1888 env.globals.intern(
1889 &env.current_ns,
1890 method.name.clone(),
1891 Value::ProtocolFn(GcPtr::new(pf)),
1892 );
1893 }
1894
1895 Ok(Value::Var(proto_var))
1896}
1897
1898fn eval_extend_type(args: &[Form], env: &mut Env) -> EvalResult {
1901 if args.is_empty() {
1903 return Err(EvalError::Runtime(
1904 "extend-type requires a type symbol".into(),
1905 ));
1906 }
1907 let type_sym = match &args[0].kind {
1908 FormKind::Symbol(s) => s.clone(),
1909 _ => {
1910 return Err(EvalError::Runtime(
1911 "extend-type: first arg must be a type symbol".into(),
1912 ));
1913 }
1914 };
1915 let type_tag = crate::interp::apply::resolve_type_tag(&type_sym);
1916
1917 let mut current_proto: Option<GcPtr<Protocol>> = None;
1918
1919 for form in &args[1..] {
1920 match &form.kind {
1921 FormKind::Symbol(s) => {
1922 let val = env.globals.lookup_in_ns(&env.current_ns, s);
1924 match val {
1925 Some(Value::Protocol(p)) => {
1926 current_proto = Some(p);
1927 }
1928 _ => {
1929 return Err(EvalError::Runtime(format!(
1930 "extend-type: {} is not a protocol",
1931 s
1932 )));
1933 }
1934 }
1935 }
1936 FormKind::List(parts) => {
1937 let proto = current_proto.as_ref().ok_or_else(|| {
1939 EvalError::Runtime("extend-type: method before protocol name".into())
1940 })?;
1941 if parts.is_empty() {
1942 continue;
1943 }
1944 let method_name = match &parts[0].kind {
1945 FormKind::Symbol(s) => Arc::from(s.as_str()),
1946 _ => continue,
1947 };
1948 let fn_val = build_impl_fn(parts, env)?;
1949 let mut impls = proto.get().impls.lock().unwrap();
1950 impls
1951 .entry(type_tag.clone())
1952 .or_default()
1953 .insert(method_name, fn_val);
1954 drop(impls);
1955 cljrs_value::bump_protocol_generation();
1956 }
1957 _ => {}
1958 }
1959 }
1960
1961 Ok(Value::Nil)
1962}
1963
1964fn eval_extend_protocol(args: &[Form], env: &mut Env) -> EvalResult {
1967 if args.is_empty() {
1969 return Err(EvalError::Runtime(
1970 "extend-protocol requires a protocol".into(),
1971 ));
1972 }
1973 let proto_sym = match &args[0].kind {
1974 FormKind::Symbol(s) => s.clone(),
1975 _ => {
1976 return Err(EvalError::Runtime(
1977 "extend-protocol: first arg must be a protocol symbol".into(),
1978 ));
1979 }
1980 };
1981 let proto_val = env.globals.lookup_in_ns(&env.current_ns, &proto_sym);
1982 let proto_ptr = match proto_val {
1983 Some(Value::Protocol(p)) => p,
1984 _ => {
1985 return Err(EvalError::Runtime(format!(
1986 "extend-protocol: {} is not a protocol",
1987 proto_sym
1988 )));
1989 }
1990 };
1991
1992 let mut current_type: Option<Arc<str>> = None;
1993
1994 for form in &args[1..] {
1995 match &form.kind {
1996 FormKind::Symbol(s) => {
1997 current_type = Some(crate::interp::apply::resolve_type_tag(s));
1998 }
1999 FormKind::List(parts) => {
2000 let type_tag = current_type.as_ref().ok_or_else(|| {
2001 EvalError::Runtime("extend-protocol: method before type name".into())
2002 })?;
2003 if parts.is_empty() {
2004 continue;
2005 }
2006 let method_name = match &parts[0].kind {
2007 FormKind::Symbol(s) => Arc::from(s.as_str()),
2008 _ => continue,
2009 };
2010 let fn_val = build_impl_fn(parts, env)?;
2011 let mut impls = proto_ptr.get().impls.lock().unwrap();
2012 impls
2013 .entry(type_tag.clone())
2014 .or_default()
2015 .insert(method_name, fn_val);
2016 drop(impls);
2017 cljrs_value::bump_protocol_generation();
2018 }
2019 _ => {}
2020 }
2021 }
2022
2023 Ok(Value::Nil)
2024}
2025
2026fn build_impl_fn(parts: &[Form], env: &mut Env) -> EvalResult<Value> {
2031 if parts.len() < 2 {
2032 return Err(EvalError::Runtime(
2033 "protocol method impl requires params and body".into(),
2034 ));
2035 }
2036 let params_form = &parts[1];
2038 let body = &parts[2..];
2039 let arity = parse_arity(params_form, body)?;
2040 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
2041 let fn_name = match &parts[0].kind {
2042 FormKind::Symbol(s) => Some(Arc::from(s.as_str())),
2043 _ => None,
2044 };
2045 let cljrs_fn = CljxFn::new(
2046 fn_name,
2047 vec![arity],
2048 closed_over_names,
2049 closed_over_vals,
2050 false,
2051 Arc::clone(&env.current_ns),
2052 );
2053 Ok(Value::Fn(GcPtr::new(cljrs_fn)))
2054}
2055
2056fn eval_defmulti(args: &[Form], env: &mut Env) -> EvalResult {
2059 let name = require_sym(args, 0, "defmulti")?;
2061 let name_arc: Arc<str> = Arc::from(name);
2062
2063 let rest_start = if args.len() > 2 && matches!(args[1].kind, FormKind::Str(_)) {
2064 2
2065 } else {
2066 1
2067 };
2068
2069 if args.len() <= rest_start {
2070 return Err(EvalError::Runtime(
2071 "defmulti requires a dispatch function".into(),
2072 ));
2073 }
2074
2075 let dispatch_fn = eval(&args[rest_start], env)?;
2076
2077 let mut default_dispatch = ":default".to_string();
2079 let mut i = rest_start + 1;
2080 while i + 1 < args.len() {
2081 if let FormKind::Keyword(k) = &args[i].kind
2082 && k == "default"
2083 {
2084 let dv = eval(&args[i + 1], env)?;
2085 default_dispatch = format!("{}", dv);
2086 }
2087 i += 2;
2088 }
2089
2090 let mfn = MultiFn::new(name_arc.clone(), dispatch_fn, default_dispatch);
2091 let var = env
2092 .globals
2093 .intern(&env.current_ns, name_arc, Value::MultiFn(GcPtr::new(mfn)));
2094 Ok(Value::Var(var))
2095}
2096
2097fn eval_defmethod(args: &[Form], env: &mut Env) -> EvalResult {
2100 if args.len() < 3 {
2102 return Err(EvalError::Runtime(
2103 "defmethod requires name, dispatch-val, params, and body".into(),
2104 ));
2105 }
2106 let multi_name = require_sym(args, 0, "defmethod")?;
2107
2108 let mf_ptr = match env.globals.lookup_in_ns(&env.current_ns, multi_name) {
2109 Some(Value::MultiFn(mf)) => mf,
2110 _ => {
2111 return Err(EvalError::Runtime(format!(
2112 "defmethod: {} is not a multimethod",
2113 multi_name
2114 )));
2115 }
2116 };
2117
2118 let dispatch_val = eval(&args[1], env)?;
2119 let key = format!("{}", dispatch_val);
2120
2121 let params_form = &args[2];
2123 let body = &args[3..];
2124 let arity = parse_arity(params_form, body)?;
2125 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
2126 let fn_name = Some(Arc::from(multi_name));
2127 let cljrs_fn = CljxFn::new(
2128 fn_name,
2129 vec![arity],
2130 closed_over_names,
2131 closed_over_vals,
2132 false,
2133 Arc::clone(&env.current_ns),
2134 );
2135 let fn_val = Value::Fn(GcPtr::new(cljrs_fn));
2136
2137 mf_ptr.get().methods.lock().unwrap().insert(key, fn_val);
2138
2139 Ok(Value::MultiFn(mf_ptr))
2140}
2141
2142fn eval_binding(args: &[Form], env: &mut Env) -> EvalResult {
2145 let pairs = match args.first().map(|f| &f.kind) {
2146 Some(FormKind::Vector(v)) => expand_pairs(v)
2147 .map_err(|_| EvalError::Runtime("binding vector must have even count".into()))?
2148 .into_owned(),
2149 _ => return Err(EvalError::Runtime("binding requires a vector".into())),
2150 };
2151
2152 let mut frame: HashMap<usize, Value> = HashMap::new();
2153 for pair in pairs.chunks(2) {
2154 let sym_str = match &pair[0].kind {
2155 FormKind::Symbol(s) => s.clone(),
2156 _ => return Err(EvalError::Runtime("binding targets must be symbols".into())),
2157 };
2158 let parsed = cljrs_value::Symbol::parse(&sym_str);
2159 let ns_part: Arc<str> = match parsed.namespace.as_deref() {
2160 Some(ns_part) => env
2164 .globals
2165 .resolve_alias(&env.current_ns, ns_part)
2166 .unwrap_or_else(|| Arc::from(ns_part)),
2167 None => env.current_ns.clone(),
2168 };
2169 let var_ptr = env
2170 .globals
2171 .lookup_var_in_ns(&ns_part, &parsed.name)
2172 .ok_or_else(|| EvalError::UnboundSymbol(sym_str.clone()))?;
2173 let val = eval(&pair[1], env)?;
2174 frame.insert(crate::env::dynamics::var_key_of(&var_ptr), val);
2175 }
2176
2177 let _guard = crate::env::dynamics::push_frame(frame);
2178 eval_body(&args[1..], env)
2179 }
2181
2182fn eval_defrecord(args: &[Form], env: &mut Env) -> EvalResult {
2185 if args.len() < 2 {
2187 return Err(EvalError::Runtime(
2188 "defrecord requires a name and field vector".into(),
2189 ));
2190 }
2191 let type_name = require_sym(args, 0, "defrecord")?;
2192 let type_tag: Arc<str> = Arc::from(type_name);
2193
2194 let field_names: Vec<Arc<str>> = match &args[1].kind {
2196 FormKind::Vector(fields) => fields
2197 .iter()
2198 .map(|f| match &f.kind {
2199 FormKind::Symbol(s) => Ok(Arc::from(s.as_str())),
2200 _ => Err(EvalError::Runtime(
2201 "defrecord field names must be symbols".into(),
2202 )),
2203 })
2204 .collect::<EvalResult<_>>()?,
2205 _ => {
2206 return Err(EvalError::Runtime(
2207 "defrecord requires a field vector as second arg".into(),
2208 ));
2209 }
2210 };
2211
2212 register_impls_for_tag(&type_tag, &args[2..], env)?;
2214
2215 let ns = env.current_ns.clone();
2219 let globals = env.globals.clone();
2220 let type_tag2 = type_tag.clone();
2221
2222 {
2224 let params: Vec<Arc<str>> = field_names.clone();
2225 let rest_param = None;
2226 use cljrs_reader::form::FormKind as FK;
2228 let dummy_span =
2229 cljrs_types::span::Span::new(std::sync::Arc::new("<defrecord>".into()), 0, 0, 1, 1);
2230 let make_form = |kind: FK| Form {
2231 kind,
2232 span: dummy_span.clone(),
2233 };
2234 let mut kv_forms: Vec<Form> = Vec::new();
2235 for f in &field_names {
2236 kv_forms.push(make_form(FK::Keyword(f.as_ref().to_string())));
2237 kv_forms.push(make_form(FK::Symbol(f.as_ref().to_string())));
2238 }
2239 let map_form = make_form(FK::Map(kv_forms));
2240 let body = vec![make_form(FK::List(vec![
2241 make_form(FK::Symbol("make-type-instance".into())),
2242 make_form(FK::Str(type_tag.as_ref().to_string())),
2243 map_form,
2244 ]))];
2245 let arity = CljxFnArity {
2246 params,
2247 rest_param,
2248 body,
2249 destructure_params: vec![],
2250 destructure_rest: None,
2251 ir_arity_id: crate::interp::arity::fresh_arity_id(),
2252 param_hints: vec![],
2253 rest_hint: None,
2254 };
2255 let fn_name: Arc<str> = Arc::from(format!("->{}", type_name));
2256 let ctor = CljxFn::new(
2257 Some(fn_name.clone()),
2258 vec![arity],
2259 vec![],
2260 vec![],
2261 false,
2262 Arc::clone(&ns),
2263 );
2264 globals.intern(&ns, fn_name, Value::Fn(GcPtr::new(ctor)));
2265 }
2266
2267 {
2269 use cljrs_reader::form::FormKind as FK;
2270 let dummy_span =
2271 cljrs_types::span::Span::new(std::sync::Arc::new("<defrecord>".into()), 0, 0, 1, 1);
2272 let make_form = |kind: FK| Form {
2273 kind,
2274 span: dummy_span.clone(),
2275 };
2276 let m_sym: Arc<str> = Arc::from("m__");
2277 let body = vec![make_form(FK::List(vec![
2278 make_form(FK::Symbol("make-type-instance".into())),
2279 make_form(FK::Str(type_tag2.as_ref().to_string())),
2280 make_form(FK::Symbol(m_sym.as_ref().to_string())),
2281 ]))];
2282 let arity = CljxFnArity {
2283 params: vec![m_sym],
2284 rest_param: None,
2285 body,
2286 destructure_params: vec![],
2287 destructure_rest: None,
2288 ir_arity_id: crate::interp::arity::fresh_arity_id(),
2289 param_hints: vec![],
2290 rest_hint: None,
2291 };
2292 let fn_name: Arc<str> = Arc::from(format!("map->{}", type_name));
2293 let ctor = CljxFn::new(
2294 Some(fn_name.clone()),
2295 vec![arity],
2296 vec![],
2297 vec![],
2298 false,
2299 Arc::clone(&ns),
2300 );
2301 globals.intern(&ns, fn_name, Value::Fn(GcPtr::new(ctor)));
2302 }
2303
2304 let type_sym = cljrs_value::Symbol::simple(type_name);
2306 globals.intern(
2307 &ns,
2308 Arc::from(type_name),
2309 Value::Symbol(GcPtr::new(type_sym)),
2310 );
2311 Ok(Value::Nil)
2312}
2313
2314fn eval_reify(args: &[Form], env: &mut Env) -> EvalResult {
2317 let n = crate::builtins::builtins::GENSYM_COUNTER
2320 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2321 let type_tag: Arc<str> = Arc::from(format!("reify__{}", n));
2322
2323 register_impls_for_tag(&type_tag, args, env)?;
2325
2326 Ok(Value::TypeInstance(GcPtr::new(TypeInstance {
2328 type_tag,
2329 fields: MapValue::empty(),
2330 })))
2331}
2332
2333fn register_impls_for_tag(type_tag: &Arc<str>, forms: &[Form], env: &mut Env) -> EvalResult<()> {
2338 let mut current_proto: Option<GcPtr<cljrs_value::Protocol>> = None;
2339
2340 for form in forms {
2341 match &form.kind {
2342 FormKind::Symbol(s) => {
2343 let val = env.globals.lookup_in_ns(&env.current_ns, s);
2344 match val {
2345 Some(Value::Protocol(p)) => {
2346 current_proto = Some(p);
2347 }
2348 _ => {
2349 return Err(EvalError::Runtime(format!(
2350 "reify/defrecord: {} is not a protocol",
2351 s
2352 )));
2353 }
2354 }
2355 }
2356 FormKind::List(parts) => {
2357 let proto = current_proto.as_ref().ok_or_else(|| {
2358 EvalError::Runtime("reify/defrecord: method impl before protocol name".into())
2359 })?;
2360 if parts.is_empty() {
2361 continue;
2362 }
2363 let method_name = match &parts[0].kind {
2364 FormKind::Symbol(s) => Arc::from(s.as_str()),
2365 _ => continue,
2366 };
2367 let fn_val = build_impl_fn(parts, env)?;
2368 let mut impls = proto.get().impls.lock().unwrap();
2369 impls
2370 .entry(type_tag.clone())
2371 .or_default()
2372 .insert(method_name, fn_val);
2373 drop(impls);
2374 cljrs_value::bump_protocol_generation();
2375 }
2376 _ => {}
2377 }
2378 }
2379 Ok(())
2380}
2381
2382pub fn sync_star_ns(env: &mut Env) {
2387 if let Some(star_ns_var) = env.globals.lookup_var("clojure.core", "*ns*") {
2388 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
2389 star_ns_var.get().bind(Value::Namespace(ns_ptr));
2390 }
2391}
2392
2393fn require_sym<'a>(args: &'a [Form], idx: usize, form_name: &str) -> EvalResult<&'a str> {
2394 match args.get(idx).map(|f| &f.kind) {
2395 Some(FormKind::Symbol(s)) => Ok(s.as_str()),
2396 _ => Err(EvalError::Runtime(format!(
2397 "{form_name} requires a symbol at position {idx}"
2398 ))),
2399 }
2400}
2401
2402fn eval_with_out_str(body: &[Form], env: &mut Env) -> EvalResult {
2405 crate::builtins::builtins::push_output_capture();
2406 let result = eval_body(body, env);
2407 let captured = crate::builtins::builtins::pop_output_capture().unwrap_or_default();
2408 result?;
2410 Ok(Value::string(captured))
2411}
2412
2413fn eval_await(args: &[Form], env: &mut Env) -> EvalResult {
2422 if args.is_empty() {
2423 return Err(EvalError::Runtime("await requires one argument".into()));
2424 }
2425 let val = eval(&args[0], env)?;
2426 match val {
2427 Value::Future(f) => {
2428 let mut guard = f.get().state.lock().unwrap();
2429 loop {
2430 match &*guard {
2431 FutureState::Done(v) => {
2432 f.get().mark_observed();
2433 return Ok(v.clone());
2434 }
2435 FutureState::Failed(v) => {
2436 f.get().mark_observed();
2437 return Err(EvalError::Thrown(v.clone()));
2438 }
2439 FutureState::GasExhausted => {
2440 f.get().mark_observed();
2441 return Err(EvalError::GasExhausted);
2442 }
2443 FutureState::Cancelled => {
2444 return Err(EvalError::Runtime("future was cancelled".into()));
2445 }
2446 FutureState::Running => {
2447 guard = f.get().cond.wait(guard).unwrap();
2448 }
2449 }
2450 }
2451 }
2452 Value::Promise(p) => Ok(p.get().deref_blocking()),
2453 other => Ok(other),
2454 }
2455}