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
154pub fn compile_meta_form(meta: &Form, env: &mut Env) -> EvalResult<Value> {
161 crate::builtins::form::expand_meta_annotation(meta, &mut |f| eval(f, env))
162}
163
164pub fn meta_form_is_async(meta: &Form) -> bool {
171 match &meta.kind {
172 FormKind::Keyword(k) => k == "async",
173 FormKind::Map(entries) => entries.chunks(2).any(|kv| {
174 matches!(&kv[0].kind, FormKind::Keyword(k) if k == "async")
175 && !matches!(
176 kv.get(1).map(|f| &f.kind),
177 None | Some(FormKind::Bool(false)) | Some(FormKind::Nil)
178 )
179 }),
180 _ => false,
181 }
182}
183
184fn eval_fn(args: &[Form], env: &mut Env) -> EvalResult {
185 let mut is_async = false;
188 let peeled: Vec<Form>;
189 let args: &[Form] = if matches!(args.first().map(|f| &f.kind), Some(FormKind::Meta(..))) {
190 let (metas, head) = args[0].peel_meta();
191 is_async |= metas.iter().any(|m| meta_form_is_async(m));
192 peeled = std::iter::once(head.clone())
193 .chain(args[1..].iter().cloned())
194 .collect();
195 &peeled
196 } else {
197 args
198 };
199
200 let mut idx = 0;
201 let mut name: Option<Arc<str>> = None;
202
203 if let Some(FormKind::Symbol(s)) = args.first().map(|f| &f.kind)
205 && !is_special_form(s)
206 {
207 name = Some(Arc::from(s.as_str()));
208 idx = 1;
209 }
210
211 let rest = &args[idx..];
212 if rest.is_empty() {
213 return Err(EvalError::Runtime("fn* requires params and body".into()));
214 }
215
216 let arities = match &rest[0].unmeta().kind {
219 FormKind::Vector(_) => {
220 vec![parse_arity(&rest[0], &rest[1..])?]
222 }
223 FormKind::List(_) => {
224 rest.iter()
226 .map(|arity_form| {
227 if let Some(forms) = arity_form.as_list() {
228 if forms.is_empty() {
229 return Err(EvalError::Runtime("arity clause requires params".into()));
230 }
231 parse_arity(&forms[0], &forms[1..])
232 } else {
233 Err(EvalError::Runtime("expected arity clause (list)".into()))
234 }
235 })
236 .collect::<EvalResult<Vec<_>>>()?
237 }
238 _ => {
239 return Err(EvalError::Runtime(
240 "fn* expects vector or arity clauses".into(),
241 ));
242 }
243 };
244
245 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
247
248 let mut cljrs_fn = CljxFn::new(
249 name.clone(),
250 arities,
251 closed_over_names,
252 closed_over_vals,
253 false,
254 Arc::clone(&env.current_ns),
255 );
256 cljrs_fn.is_async = is_async;
257
258 env.on_fn_defined(&cljrs_fn);
259
260 let mut ptr = GcPtr::new(cljrs_fn);
264 if ptr.get().name.is_some() {
268 let self_clone = ptr.clone();
269 ptr.get_mut().self_ptr = Some(self_clone);
270 }
271 Ok(Value::Fn(ptr))
272}
273
274pub fn parse_arity(params_form: &Form, body: &[Form]) -> EvalResult<CljxFnArity> {
276 let Some(param_forms) = params_form.as_vector() else {
277 return Err(EvalError::Runtime(
278 "fn arity params must be a vector".into(),
279 ));
280 };
281
282 let mut params: Vec<Arc<str>> = Vec::new();
283 let mut param_hints: Vec<Option<TypeHint>> = Vec::new();
284 let mut rest_param: Option<Arc<str>> = None;
285 let mut rest_hint: Option<TypeHint> = None;
286 let mut destructure_params: Vec<(usize, Form)> = Vec::new();
287 let mut destructure_rest: Option<Form> = None;
288 let mut saw_amp = false;
289
290 for p in param_forms {
291 let (hint, p) = peel_param_hint(p);
297 match &p.kind {
298 FormKind::Symbol(s) if s == "&" => {
299 saw_amp = true;
300 }
301 FormKind::Symbol(s) => {
302 if saw_amp {
303 rest_param = Some(Arc::from(s.as_str()));
304 rest_hint = hint;
305 break;
306 } else {
307 params.push(Arc::from(s.as_str()));
308 param_hints.push(hint);
309 }
310 }
311 FormKind::Vector(_) | FormKind::Map(_) => {
313 if saw_amp {
314 let gensym = format!("__destructure_rest_{}", params.len());
315 rest_param = Some(Arc::from(gensym.as_str()));
316 destructure_rest = Some(p.clone());
317 break;
318 } else {
319 let idx = params.len();
320 let gensym = format!("__destructure_{idx}");
321 params.push(Arc::from(gensym.as_str()));
322 param_hints.push(None);
324 destructure_params.push((idx, p.clone()));
325 }
326 }
327 _ => {
328 return Err(EvalError::Runtime(
329 "fn params must be symbols, vectors, or maps".into(),
330 ));
331 }
332 }
333 }
334
335 let body = desugar_pre_post_conditions(body);
336
337 Ok(CljxFnArity {
338 params,
339 rest_param,
340 body,
341 destructure_params,
342 destructure_rest,
343 ir_arity_id: crate::interp::arity::fresh_arity_id(),
344 param_hints,
345 rest_hint,
346 })
347}
348
349fn desugar_pre_post_conditions(body: &[Form]) -> Vec<Form> {
367 let first = match body.first() {
368 Some(f) => f,
369 None => return body.to_vec(),
370 };
371
372 let entries = match first.as_map() {
373 Some(entries) => entries,
374 None => return body.to_vec(),
375 };
376
377 let mut pre_conds: Vec<Form> = Vec::new();
378 let mut post_conds: Vec<Form> = Vec::new();
379 let mut has_conditions = false;
380
381 for chunk in entries.chunks(2) {
382 if chunk.len() < 2 {
383 break;
384 }
385 let (key, val) = (&chunk[0], &chunk[1]);
386 match &key.kind {
387 FormKind::Keyword(k) if k == "pre" => {
388 if let FormKind::Vector(conds) = &val.kind {
389 pre_conds.extend_from_slice(conds);
390 has_conditions = true;
391 }
392 }
393 FormKind::Keyword(k) if k == "post" => {
394 if let FormKind::Vector(conds) = &val.kind {
395 post_conds.extend_from_slice(conds);
396 has_conditions = true;
397 }
398 }
399 _ => {}
400 }
401 }
402
403 if !has_conditions {
404 return body.to_vec();
405 }
406
407 let real_body = &body[1..]; let span = first.span.clone();
409 let mut new_body: Vec<Form> = Vec::new();
410
411 for cond in &pre_conds {
413 new_body.push(make_assert_call(cond, &span));
414 }
415
416 if post_conds.is_empty() {
417 new_body.extend_from_slice(real_body);
418 } else {
419 let percent = Form::new(FormKind::Symbol("%".to_string()), span.clone());
422
423 let body_expr = if real_body.len() == 1 {
424 real_body[0].clone()
425 } else {
426 let mut do_forms = vec![Form::new(FormKind::Symbol("do".to_string()), span.clone())];
427 do_forms.extend_from_slice(real_body);
428 Form::new(FormKind::List(do_forms), span.clone())
429 };
430
431 let binding_vec = Form::new(
432 FormKind::Vector(vec![percent.clone(), body_expr]),
433 span.clone(),
434 );
435
436 let mut let_forms = vec![
437 Form::new(FormKind::Symbol("let*".to_string()), span.clone()),
438 binding_vec,
439 ];
440 for cond in &post_conds {
441 let_forms.push(make_assert_call(cond, &span));
442 }
443 let_forms.push(percent);
444
445 new_body.push(Form::new(FormKind::List(let_forms), span));
446 }
447
448 new_body
449}
450
451fn make_assert_call(cond: &Form, span: &cljrs_types::span::Span) -> Form {
453 Form::new(
454 FormKind::List(vec![
455 Form::new(FormKind::Symbol("assert".to_string()), span.clone()),
456 cond.clone(),
457 ]),
458 span.clone(),
459 )
460}
461
462fn peel_param_hint(p: &Form) -> (Option<TypeHint>, &Form) {
466 if let FormKind::Meta(meta, inner) = &p.kind {
467 let hint = tag_name_of_meta(meta).and_then(|n| TypeHint::from_tag(&n));
468 let (inner_hint, inner_form) = peel_param_hint(inner);
470 (hint.or(inner_hint), inner_form)
471 } else {
472 (None, p)
473 }
474}
475
476fn tag_name_of_meta(meta: &Form) -> Option<Arc<str>> {
479 match &meta.kind {
480 FormKind::Symbol(s) => Some(strip_tag_ns(s)),
482 FormKind::Map(entries) => entries.chunks(2).find_map(|kv| {
484 let is_tag = matches!(&kv[0].kind, FormKind::Keyword(k) if k == "tag");
485 if !is_tag {
486 return None;
487 }
488 match kv.get(1).map(|f| &f.kind) {
489 Some(FormKind::Symbol(s)) => Some(strip_tag_ns(s)),
490 Some(FormKind::Str(s)) => Some(strip_tag_ns(s)),
491 _ => None,
492 }
493 }),
494 _ => None,
495 }
496}
497
498fn strip_tag_ns(s: &str) -> Arc<str> {
500 match s.rfind('/') {
501 Some(pos) if pos + 1 < s.len() => Arc::from(&s[pos + 1..]),
502 _ => Arc::from(s),
503 }
504}
505
506fn eval_if(args: &[Form], env: &mut Env) -> EvalResult {
509 if args.is_empty() {
510 return Err(EvalError::Runtime("if requires a test".into()));
511 }
512 let test = eval(&args[0], env)?;
513 let truthy = !matches!(test, Value::Nil | Value::Bool(false));
514 if truthy {
515 if args.len() > 1 {
516 eval(&args[1], env)
517 } else {
518 Ok(Value::Nil)
519 }
520 } else if args.len() > 2 {
521 eval(&args[2], env)
522 } else {
523 Ok(Value::Nil)
524 }
525}
526
527fn eval_let(args: &[Form], env: &mut Env) -> EvalResult {
530 let bindings = match args.first().and_then(|f| f.as_vector()) {
531 Some(v) => expand_pairs(v)
532 .map_err(|_| EvalError::Runtime("let* binding vector must have even length".into()))?
533 .into_owned(),
534 None => return Err(EvalError::Runtime("let* requires a binding vector".into())),
535 };
536
537 let body = &args[1..];
538
539 let chains = crate::interp::virtualize::detect_let_chains(&bindings);
541 let virtualizable_chains = find_virtualizable_chains(&chains, &bindings, body);
542
543 env.push_frame();
544
545 let pairs: Vec<_> = bindings.chunks(2).collect();
546 let mut i = 0;
547 while i < pairs.len() {
548 if let Some(chain) = virtualizable_chains.iter().find(|c| c.start == i) {
550 match eval_virtualized_chain(chain, &pairs, env) {
551 Ok(()) => {
552 i += chain.len;
553 continue;
554 }
555 Err(e) => {
556 env.pop_frame();
557 return Err(e);
558 }
559 }
560 }
561
562 let pair = pairs[i];
564 let val = match eval(&pair[1], env) {
565 Ok(v) => v,
566 Err(e) => {
567 env.pop_frame();
568 return Err(e);
569 }
570 };
571 if let Err(e) = bind_pattern(&pair[0], val, env) {
572 env.pop_frame();
573 return Err(e);
574 }
575 i += 1;
576 }
577
578 let result = eval_body(body, env);
579 env.pop_frame();
580 result
581}
582
583fn find_virtualizable_chains<'a>(
588 chains: &'a [crate::interp::virtualize::LetChain],
589 bindings: &[Form],
590 body: &[Form],
591) -> Vec<&'a crate::interp::virtualize::LetChain> {
592 chains
593 .iter()
594 .filter(|chain| {
595 for j in chain.start..(chain.start + chain.len - 1) {
598 let name = match &bindings[j * 2].kind {
599 FormKind::Symbol(s) => s.as_str(),
600 _ => return false,
601 };
602 if crate::interp::virtualize::binding_used_in_body(name, body) {
603 return false;
604 }
605 if crate::interp::virtualize::binding_used_in_other_bindings(
606 name,
607 bindings,
608 chain.start,
609 chain.len,
610 ) {
611 return false;
612 }
613 }
614 true
615 })
616 .collect()
617}
618
619fn eval_virtualized_chain(
629 chain: &crate::interp::virtualize::LetChain,
630 pairs: &[&[Form]],
631 env: &mut Env,
632) -> Result<(), EvalError> {
633 use crate::builtins::transients::{
634 builtin_assoc_bang, builtin_conj_bang, builtin_persistent_bang, builtin_transient,
635 };
636
637 let first_pair = pairs[chain.start];
639 let first_expr_forms = match &first_pair[1].kind {
640 FormKind::List(forms) => forms,
641 _ => unreachable!("chain detection ensures this is a list"),
642 };
643 let root_collection = eval(&first_expr_forms[1], env)?;
644
645 let mut transient = match builtin_transient(std::slice::from_ref(&root_collection)) {
647 Ok(t) => t,
648 Err(_) => {
649 return eval_chain_normally(chain, pairs, env);
652 }
653 };
654
655 for j in 0..chain.len {
657 let pair_idx = chain.start + j;
658 let pair = pairs[pair_idx];
659 let expr_forms = match &pair[1].kind {
660 FormKind::List(forms) => forms,
661 _ => unreachable!(),
662 };
663
664 let mut args = vec![transient.clone()];
666 for arg_form in expr_forms.iter().skip(2) {
667 args.push(eval(arg_form, env)?);
668 }
669
670 transient = match chain.ops[j] {
672 crate::interp::virtualize::ChainOpKind::Assoc => {
673 builtin_assoc_bang(&args).map_err(|e| EvalError::Runtime(e.to_string()))?
674 }
675 crate::interp::virtualize::ChainOpKind::Conj => {
676 builtin_conj_bang(&args).map_err(|e| EvalError::Runtime(e.to_string()))?
677 }
678 };
679
680 if j < chain.len - 1 {
684 let name = match &pair[0].kind {
685 FormKind::Symbol(s) => s.clone(),
686 _ => unreachable!(),
687 };
688 env.bind(Arc::from(name.as_str()), Value::Nil);
690 }
691 }
692
693 let persistent =
695 builtin_persistent_bang(&[transient]).map_err(|e| EvalError::Runtime(e.to_string()))?;
696
697 let last_pair = pairs[chain.start + chain.len - 1];
699 bind_pattern(&last_pair[0], persistent, env)?;
700
701 Ok(())
702}
703
704fn eval_chain_normally(
706 chain: &crate::interp::virtualize::LetChain,
707 pairs: &[&[Form]],
708 env: &mut Env,
709) -> Result<(), EvalError> {
710 for j in 0..chain.len {
711 let pair_idx = chain.start + j;
712 let pair = pairs[pair_idx];
713 let val = eval(&pair[1], env)?;
714 bind_pattern(&pair[0], val, env)?;
715 }
716 Ok(())
717}
718
719pub fn eval_loop(args: &[Form], env: &mut Env) -> EvalResult {
722 let bindings = match args.first().and_then(|f| f.as_vector()) {
723 Some(v) => expand_pairs(v)
724 .map_err(|_| EvalError::Runtime("loop* binding vector must have even length".into()))?
725 .into_owned(),
726 None => return Err(EvalError::Runtime("loop* requires a binding vector".into())),
727 };
728
729 let body = &args[1..];
730
731 let patterns: Vec<Form> = bindings.iter().step_by(2).cloned().collect();
733 let mut current_vals: Vec<Value> = Vec::new();
734
735 for i in (1..bindings.len()).step_by(2) {
737 current_vals.push(eval(&bindings[i], env)?);
738 }
739
740 loop {
741 let _vals_root = crate::env::gc_roots::root_values(¤t_vals);
743
744 crate::env::gc_roots::gc_safepoint(env);
747
748 #[cfg(feature = "no-gc")]
752 let mut scratch = cljrs_gc::alloc_ctx::ScratchGuard::new();
753
754 #[cfg(not(feature = "no-gc"))]
765 let _iter_frame = cljrs_gc::push_alloc_frame();
766
767 env.push_frame();
768 for (pat, val) in patterns.iter().zip(current_vals.iter()) {
769 if let Err(e) = bind_pattern(pat, val.clone(), env) {
770 env.pop_frame();
771 return Err(e);
772 }
773 }
774
775 #[cfg(not(feature = "no-gc"))]
778 let result = eval_body_recur(body, env);
779 #[cfg(feature = "no-gc")]
780 let result = eval_body_with_scratch_loop(body, &mut scratch, env);
781
782 env.pop_frame();
783 match result {
787 Ok(v) => return Ok(v),
788 Err(EvalError::Recur(new_vals)) => {
789 if new_vals.len() != patterns.len() {
790 return Err(EvalError::Arity {
791 name: "recur".into(),
792 expected: patterns.len().to_string(),
793 got: new_vals.len(),
794 });
795 }
796 current_vals = new_vals;
799 }
800 Err(e) => return Err(e),
801 }
802 }
803}
804
805fn eval_recur(args: &[Form], env: &mut Env) -> EvalResult {
806 let vals: Vec<Value> = args
807 .iter()
808 .map(|f| eval(f, env))
809 .collect::<EvalResult<_>>()?;
810 Err(EvalError::Recur(vals))
811}
812
813pub fn eval_body_recur(body: &[Form], env: &mut Env) -> EvalResult {
815 let mut result = Value::Nil;
816 for form in body {
817 result = eval(form, env)?;
818 }
819 Ok(result)
820}
821
822#[cfg(feature = "no-gc")]
828fn eval_body_with_scratch_loop(
829 body: &[Form],
830 scratch: &mut cljrs_gc::alloc_ctx::ScratchGuard,
831 env: &mut Env,
832) -> EvalResult {
833 if body.is_empty() {
834 scratch.pop_for_return();
835 return Ok(Value::Nil);
836 }
837 for form in &body[..body.len() - 1] {
838 eval(form, env)?;
839 }
840 scratch.pop_for_return();
841 eval(&body[body.len() - 1], env)
842}
843
844fn eval_quote(args: &[Form], env: &Env) -> EvalResult {
847 match args.first() {
848 Some(f) => form_to_value(&resolve_auto_forms(f, env)?),
852 None => Err(EvalError::Runtime("quote requires an argument".into())),
853 }
854}
855
856fn eval_var(args: &[Form], env: &mut Env) -> EvalResult {
859 let sym = match args.first().map(|f| &f.kind) {
860 Some(FormKind::Symbol(s)) => s.clone(),
861 _ => return Err(EvalError::Runtime("var requires a symbol".into())),
862 };
863 let parsed = cljrs_value::Symbol::parse(&sym);
864 let ns: Arc<str> = match parsed.namespace.as_deref() {
865 Some(ns_part) => env
866 .globals
867 .resolve_alias(&env.current_ns, ns_part)
868 .unwrap_or_else(|| Arc::from(ns_part)),
869 None => env.current_ns.clone(),
870 };
871 let name = parsed.name.as_ref();
872 env.globals
873 .lookup_var_in_ns(&ns, name)
874 .map(Value::Var)
875 .ok_or_else(|| EvalError::UnboundSymbol(sym))
876}
877
878fn eval_set_bang(args: &[Form], env: &mut Env) -> EvalResult {
881 let sym = match args.first().map(|f| &f.kind) {
882 Some(FormKind::Symbol(s)) => s.clone(),
883 _ => return Err(EvalError::Runtime("set! requires a symbol".into())),
884 };
885 let val = if args.len() > 1 {
886 eval(&args[1], env)?
887 } else {
888 Value::Nil
889 };
890 let parsed = cljrs_value::Symbol::parse(&sym);
891 let ns = parsed.namespace.as_deref().unwrap_or(&env.current_ns);
892 let var = env
893 .globals
894 .lookup_var_in_ns(ns, &parsed.name)
895 .ok_or_else(|| EvalError::UnboundSymbol(sym))?;
896 if !crate::env::dynamics::set_thread_local(&var, val.clone()) {
898 var.get().bind(val.clone());
899 }
900 Ok(val)
901}
902
903fn eval_throw(args: &[Form], env: &mut Env) -> EvalResult {
906 let val = match args.first() {
907 Some(f) => eval(f, env)?,
908 None => Value::Nil,
909 };
910 let val = match val {
913 Value::Error(_) => val,
914 other => {
915 let msg = format!("{}", other);
916 Value::Error(GcPtr::new(ExceptionInfo::new(
917 ValueError::Other(msg.clone()),
918 msg,
919 None,
920 None,
921 )))
922 }
923 };
924 Err(EvalError::Thrown(val))
925}
926
927pub struct CatchClause<'a> {
934 pub type_sym: &'a str,
935 pub binding: &'a str,
936 pub body: &'a [Form],
937}
938
939pub fn eval_error_to_value(err: &EvalError) -> Value {
944 let msg = err.to_string();
945 Value::Error(GcPtr::new(ExceptionInfo::new(
946 ValueError::Other(msg.clone()),
947 msg,
948 None,
949 None,
950 )))
951}
952
953pub fn catch_type_matches(type_name: &str, val: &Value) -> bool {
957 let short = type_name.rsplit('.').next().unwrap_or(type_name);
958 match short {
959 "Object" | "Exception" | "Throwable" | "Error" | "default" => true,
963 "ExceptionInfo" => matches!(val, Value::Error(_)),
965 _ => false,
966 }
967}
968
969fn eval_try(args: &[Form], env: &mut Env) -> EvalResult {
970 let (body, catches, fin_body) = parse_try_args(args);
971
972 let mut result = eval_body(body, env);
973
974 let err_opt = match std::mem::replace(&mut result, Ok(Value::Nil)) {
976 Ok(v) => {
977 result = Ok(v);
978 None
979 }
980 Err(EvalError::Recur(args)) => {
981 result = Err(EvalError::Recur(args));
982 None
983 }
984 Err(EvalError::GasExhausted) => {
985 result = Err(EvalError::GasExhausted);
986 None
987 }
988 Err(other) => Some(other),
989 };
990
991 if let Some(err) = err_opt {
992 let thrown_val = match err {
993 EvalError::Thrown(v) => v,
994 ref other => eval_error_to_value(other),
995 };
996 let mut handled = false;
997 for c in &catches {
998 if catch_type_matches(c.type_sym, &thrown_val) {
999 env.push_frame();
1000 env.bind(Arc::from(c.binding), thrown_val.clone());
1001 result = eval_body(c.body, env);
1002 env.pop_frame();
1003 handled = true;
1004 break;
1005 }
1006 }
1007 if !handled {
1008 result = Err(EvalError::Thrown(thrown_val));
1010 }
1011 }
1012
1013 if !fin_body.is_empty() {
1017 eval_body(fin_body, env)?;
1018 }
1019
1020 result
1021}
1022
1023fn catch_target(f: &Form) -> Option<&str> {
1025 f.as_symbol().or_else(|| f.as_keyword())
1026}
1027
1028pub fn parse_try_args(args: &[Form]) -> (&[Form], Vec<CatchClause<'_>>, &[Form]) {
1032 let mut body_end = args.len();
1033 let mut catches: Vec<CatchClause<'_>> = Vec::new();
1034 let mut fin_body: &[Form] = &[];
1035
1036 for (i, form) in args.iter().enumerate() {
1037 if let Some(parts) = form.as_list()
1038 && let Some(s) = parts.first().and_then(|f| f.as_symbol())
1039 {
1040 if s == "catch" {
1041 if i < body_end {
1042 body_end = i;
1043 }
1044 let type_sym = match parts.get(1) {
1049 Some(f) => match catch_target(f) {
1050 Some(name) => name,
1051 None => match &f.unmeta().kind {
1052 FormKind::ReaderCond {
1053 splicing: false,
1054 clauses,
1055 } => match select_reader_cond(clauses).and_then(catch_target) {
1056 Some(name) => name,
1057 None => continue,
1058 },
1059 _ => continue,
1060 },
1061 },
1062 None => continue,
1063 };
1064 let binding = match parts.get(2).and_then(|f| f.as_symbol()) {
1065 Some(s) => s,
1066 None => continue,
1067 };
1068 catches.push(CatchClause {
1069 type_sym,
1070 binding,
1071 body: &parts[3..],
1072 });
1073 continue;
1074 }
1075 if s == "finally" {
1076 if i < body_end {
1077 body_end = i;
1078 }
1079 fin_body = &parts[1..];
1080 continue;
1081 }
1082 }
1083 }
1084
1085 (&args[..body_end], catches, fin_body)
1086}
1087
1088pub fn eval_defn(args: &[Form], env: &mut Env) -> EvalResult {
1091 let name_form = args
1093 .first()
1094 .ok_or_else(|| EvalError::Runtime("defn requires a symbol name".into()))?;
1095 let (name_metas, name_sym) = name_form.peel_meta();
1096 let (name, mut is_async) = match &name_sym.kind {
1097 FormKind::Symbol(s) => (s.clone(), name_metas.iter().any(|m| meta_form_is_async(m))),
1098 _ => return Err(EvalError::Runtime("defn name must be a symbol".into())),
1099 };
1100 let mut rest_start = 1;
1104 let mut docstring: Option<String> = None;
1105 if rest_start < args.len()
1106 && let Some(s) = args[rest_start].as_string()
1107 {
1108 docstring = Some(s.to_string());
1109 rest_start += 1;
1110 }
1111 let mut attr_meta: Option<Value> = None;
1112 if rest_start < args.len() && args[rest_start].as_map().is_some() {
1113 is_async |= meta_form_is_async(&args[rest_start]);
1115 attr_meta = Some(eval(&args[rest_start], env)?);
1116 rest_start += 1;
1117 }
1118 let mut fn_args = vec![Form::new(
1120 FormKind::Symbol(name.to_string()),
1121 args[0].span.clone(),
1122 )];
1123 fn_args.extend_from_slice(&args[rest_start..]);
1124 #[cfg(feature = "no-gc")]
1127 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1128 let mut fn_val = eval_fn(&fn_args, env)?;
1129 if is_async && let Value::Fn(ref mut f) = fn_val {
1130 f.get_mut().is_async = true;
1131 }
1132 let var = env
1133 .globals
1134 .intern(&env.current_ns, Arc::from(name.as_str()), fn_val.clone());
1135 let mut meta = attr_meta;
1136 if let Some(doc) = &docstring {
1137 meta = merge_meta(meta, Some(doc_meta(doc)));
1138 }
1139 meta = merge_meta(meta, arglists_meta(&fn_val, 0));
1140 if let Some(meta_val) = meta {
1141 var.get().set_meta(meta_val);
1142 }
1143 Ok(Value::Var(var))
1144}
1145
1146fn prepend_macro_params(form: &Form) -> Form {
1154 let span = form.span.clone();
1155 match &form.unmeta().kind {
1156 FormKind::Vector(params) => {
1157 let mut new_params = vec![
1158 Form::new(FormKind::Symbol("&form".to_string()), span.clone()),
1159 Form::new(FormKind::Symbol("&env".to_string()), span.clone()),
1160 ];
1161 new_params.extend_from_slice(params);
1162 Form::new(FormKind::Vector(new_params), span)
1163 }
1164 FormKind::List(forms) => {
1165 if let Some(first) = forms.first() {
1167 let new_params_form = prepend_macro_params(first);
1168 let mut new_forms = vec![new_params_form];
1169 new_forms.extend_from_slice(&forms[1..]);
1170 Form::new(FormKind::List(new_forms), span)
1171 } else {
1172 form.clone()
1173 }
1174 }
1175 _ => form.clone(),
1176 }
1177}
1178
1179fn eval_defmacro(args: &[Form], env: &mut Env) -> EvalResult {
1180 let mut current = args
1183 .first()
1184 .ok_or_else(|| EvalError::Runtime("defmacro requires a symbol at position 0".into()))?
1185 .clone();
1186 let mut name_meta: Option<Value> = None;
1187 while let FormKind::Meta(meta_form, inner) = current.kind {
1188 let meta_val = compile_meta_form(&meta_form, env)?;
1189 name_meta = merge_meta(name_meta, Some(meta_val));
1190 current = *inner;
1191 }
1192 let name = match ¤t.kind {
1193 FormKind::Symbol(s) => s.clone(),
1194 _ => {
1195 return Err(EvalError::Runtime(
1196 "defmacro requires a symbol at position 0".into(),
1197 ));
1198 }
1199 };
1200
1201 let mut rest_start = 1;
1202 let mut docstring: Option<String> = None;
1203 if rest_start < args.len()
1204 && let FormKind::Str(s) = &args[rest_start].kind
1205 {
1206 docstring = Some(s.clone());
1207 rest_start += 1;
1208 }
1209 let mut attr_meta = None;
1210 if rest_start < args.len() && matches!(args[rest_start].kind, FormKind::Map(_)) {
1211 attr_meta = Some(eval(&args[rest_start], env)?);
1212 rest_start += 1;
1213 }
1214 let mut fn_args = vec![Form::new(
1216 FormKind::Symbol(name.to_string()),
1217 args[0].span.clone(),
1218 )];
1219 for form in &args[rest_start..] {
1220 fn_args.push(prepend_macro_params(form));
1221 }
1222 #[cfg(feature = "no-gc")]
1225 let _static_ctx = cljrs_gc::alloc_ctx::StaticCtxGuard::new();
1226 let fn_val = eval_fn(&fn_args, env)?;
1227
1228 let macro_val = match fn_val {
1230 Value::Fn(f) => {
1231 let mut mfn = f.get().clone();
1232 mfn.is_macro = true;
1233 Value::Macro(GcPtr::new(mfn))
1234 }
1235 other => other,
1236 };
1237
1238 let var = env
1239 .globals
1240 .intern(&env.current_ns, Arc::from(name.as_str()), macro_val.clone());
1241 let mut meta = merge_meta(name_meta, attr_meta);
1242 if let Some(doc) = &docstring {
1243 meta = merge_meta(meta, Some(doc_meta(doc)));
1244 }
1245 meta = merge_meta(meta, arglists_meta(¯o_val, 2));
1247 if let Some(m) = meta {
1248 var.get().set_meta(m);
1249 }
1250 Ok(Value::Var(var))
1251}
1252
1253fn eval_defonce(args: &[Form], env: &mut Env) -> EvalResult {
1256 if args.is_empty() {
1257 return Err(EvalError::Runtime("defonce requires a name".into()));
1258 }
1259 let (name, _meta) = extract_def_name(&args[0], env)?;
1262 if let Some(var) = env.globals.lookup_var(&env.current_ns, &name)
1264 && var.get().is_bound()
1265 {
1266 return Ok(Value::Var(var));
1267 }
1268 eval_def(args, env)
1269}
1270
1271fn eval_and(args: &[Form], env: &mut Env) -> EvalResult {
1274 let mut result = Value::Bool(true);
1275 for form in args {
1276 result = eval(form, env)?;
1277 if matches!(result, Value::Nil | Value::Bool(false)) {
1278 return Ok(result);
1279 }
1280 }
1281 Ok(result)
1282}
1283
1284fn eval_or(args: &[Form], env: &mut Env) -> EvalResult {
1285 let mut last = Value::Nil;
1286 for form in args {
1287 last = eval(form, env)?;
1288 if !matches!(last, Value::Nil | Value::Bool(false)) {
1289 return Ok(last);
1290 }
1291 }
1292 Ok(last)
1293}
1294
1295fn eval_require(args: &[Form], env: &mut Env) -> EvalResult {
1298 for arg in args {
1299 let val = eval(arg, env)?;
1300 let spec = parse_require_spec_val(val).map_err(EvalError::Runtime)?;
1301 load_ns(env.globals.clone(), &spec, &env.current_ns)?;
1302 }
1303 Ok(Value::Nil)
1304}
1305
1306fn parse_require_spec_val(val: Value) -> Result<RequireSpec, String> {
1311 match val {
1312 Value::Symbol(s) => {
1313 let sym = s.get();
1314 Ok(RequireSpec {
1315 ns: sym.name.clone(),
1316 version: sym.version.clone(),
1317 alias: None,
1318 refer: RequireRefer::None,
1319 })
1320 }
1321 Value::Vector(v) => {
1322 let items: Vec<Value> = v.get().iter().cloned().collect();
1323 if items.is_empty() {
1324 return Err("require spec vector must not be empty".into());
1325 }
1326 let (ns, version) = match &items[0] {
1327 Value::Symbol(s) => {
1328 let sym = s.get();
1329 (sym.name.clone(), sym.version.clone())
1330 }
1331 other => {
1332 return Err(format!(
1333 "require spec: first element must be a symbol, got {}",
1334 other.type_name()
1335 ));
1336 }
1337 };
1338 let mut alias = None;
1339 let mut refer = RequireRefer::None;
1340 let mut i = 1;
1341 while i < items.len() {
1342 match &items[i] {
1343 Value::Keyword(k) if k.get().name.as_ref() == "as" => {
1344 i += 1;
1345 alias = Some(match items.get(i) {
1346 Some(Value::Symbol(s)) => s.get().name.clone(),
1347 _ => return Err("require :as expects a symbol".into()),
1348 });
1349 }
1350 Value::Keyword(k) if k.get().name.as_ref() == "refer" => {
1351 i += 1;
1352 refer = match items.get(i) {
1353 Some(Value::Keyword(k2)) if k2.get().name.as_ref() == "all" => {
1354 RequireRefer::All
1355 }
1356 Some(Value::Vector(rv)) => {
1357 let names: Vec<Arc<str>> = rv
1358 .get()
1359 .iter()
1360 .map(|v| match v {
1361 Value::Symbol(s) => Ok(s.get().name.clone()),
1362 other => Err(format!(
1363 "require :refer expects symbols, got {}",
1364 other.type_name()
1365 )),
1366 })
1367 .collect::<Result<_, _>>()?;
1368 RequireRefer::Named(names)
1369 }
1370 _ => {
1371 return Err(
1372 "require :refer expects :all or a vector of symbols".into()
1373 );
1374 }
1375 };
1376 }
1377 other => {
1378 return Err(format!(
1379 "require spec: unexpected option {}",
1380 other.type_name()
1381 ));
1382 }
1383 }
1384 i += 1;
1385 }
1386 Ok(RequireSpec {
1387 ns,
1388 version,
1389 alias,
1390 refer,
1391 })
1392 }
1393 other => Err(format!(
1394 "require expects a symbol or vector, got {}",
1395 other.type_name()
1396 )),
1397 }
1398}
1399
1400fn spec_element(form: &Form) -> Option<&Form> {
1404 match &form.kind {
1405 FormKind::ReaderCond { clauses, .. } => select_reader_cond(clauses),
1406 _ => Some(form),
1407 }
1408}
1409
1410pub fn parse_require_spec_form(form: &Form) -> Result<RequireSpec, String> {
1417 match &form.kind {
1418 FormKind::Symbol(s) => {
1419 let sym = cljrs_value::Symbol::parse(s);
1420 Ok(RequireSpec {
1421 ns: sym.name.clone(),
1422 version: sym.version.clone(),
1423 alias: None,
1424 refer: RequireRefer::None,
1425 })
1426 }
1427 FormKind::Vector(items) => {
1428 if items.is_empty() {
1429 return Err("require spec vector must not be empty".into());
1430 }
1431 let head = spec_element(&items[0]).ok_or_else(|| {
1432 "require spec: no reader-conditional branch matched for the namespace".to_string()
1433 })?;
1434 let (ns, version) = match &head.kind {
1435 FormKind::Symbol(s) => {
1436 let sym = cljrs_value::Symbol::parse(s);
1437 (sym.name.clone(), sym.version.clone())
1438 }
1439 _ => return Err("require spec: first element must be a symbol".into()),
1440 };
1441 let mut alias = None;
1442 let mut refer = RequireRefer::None;
1443 let mut i = 1;
1444 while i < items.len() {
1445 let Some(item) = spec_element(&items[i]) else {
1448 i += 1;
1449 continue;
1450 };
1451 match &item.kind {
1452 FormKind::Keyword(k) if k == "as" => {
1453 i += 1;
1454 alias = Some(match items.get(i).map(|f| &f.kind) {
1455 Some(FormKind::Symbol(s)) => Arc::from(s.as_str()),
1456 _ => return Err("require :as expects a symbol".into()),
1457 });
1458 }
1459 FormKind::Keyword(k) if k == "refer" => {
1460 i += 1;
1461 refer = match items.get(i).map(|f| &f.kind) {
1462 Some(FormKind::Keyword(k2)) if k2 == "all" => RequireRefer::All,
1463 Some(FormKind::Vector(rv)) => {
1464 let names: Vec<Arc<str>> = rv
1465 .iter()
1466 .map(|f| match &f.kind {
1467 FormKind::Symbol(s) => Ok(Arc::from(s.as_str())),
1468 _ => Err("require :refer expects symbols".to_string()),
1469 })
1470 .collect::<Result<_, _>>()?;
1471 RequireRefer::Named(names)
1472 }
1473 _ => return Err("require :refer expects :all or a vector".into()),
1474 };
1475 }
1476 _ => return Err(format!("require spec: unexpected form at position {i}")),
1477 }
1478 i += 1;
1479 }
1480 Ok(RequireSpec {
1481 ns,
1482 version,
1483 alias,
1484 refer,
1485 })
1486 }
1487 _ => Err("require spec must be a symbol or vector".into()),
1488 }
1489}
1490
1491fn extract_ns_name_form(form: Option<&Form>, env: &mut Env) -> EvalResult<(String, Option<Value>)> {
1497 let mut current = form
1498 .ok_or_else(|| EvalError::Runtime("ns requires a symbol at position 0".into()))?
1499 .clone();
1500 let mut meta_acc: Option<Value> = None;
1501 while let FormKind::Meta(meta_form, inner) = current.kind {
1502 let meta_val = compile_meta_form(&meta_form, env)?;
1503 meta_acc = merge_meta(meta_acc, Some(meta_val));
1504 current = *inner;
1505 }
1506 match ¤t.kind {
1507 FormKind::Symbol(s) => Ok((s.clone(), meta_acc)),
1508 _ => Err(EvalError::Runtime(
1509 "ns requires a symbol at position 0".into(),
1510 )),
1511 }
1512}
1513
1514fn merge_meta(base: Option<Value>, overlay: Option<Value>) -> Option<Value> {
1517 match (base, overlay) {
1518 (None, None) => None,
1519 (Some(b), None) => Some(b),
1520 (None, Some(o)) => Some(o),
1521 (Some(Value::Map(b)), Some(Value::Map(o))) => {
1522 let mut merged = b;
1523 for (k, v) in o.iter() {
1524 merged = merged.assoc(k.clone(), v.clone());
1525 }
1526 Some(Value::Map(merged))
1527 }
1528 (_, Some(o)) => Some(o),
1529 }
1530}
1531
1532fn parse_refer_clojure_clause(items: &[Form]) -> Result<ReferClojureFilter, String> {
1536 let mut filter = ReferClojureFilter::default();
1537 let items = expand_reader_conds(items);
1538 let mut i = 0;
1539 while i < items.len() {
1540 let FormKind::Keyword(k) = &items[i].kind else {
1541 return Err(":refer-clojure expects keyword options (:exclude, :only, :rename)".into());
1542 };
1543 let arg = items
1544 .get(i + 1)
1545 .ok_or_else(|| format!(":refer-clojure :{k} expects a value"))?;
1546 match k.as_str() {
1547 "exclude" => filter.exclude = symbol_name_set(arg, "exclude")?,
1548 "only" => filter.only = Some(symbol_name_set(arg, "only")?),
1549 "rename" => {
1550 let FormKind::Map(entries) = &arg.kind else {
1551 return Err(":refer-clojure :rename expects a map".into());
1552 };
1553 if entries.len() % 2 != 0 {
1554 return Err(":refer-clojure :rename expects an even-sized map".into());
1555 }
1556 for pair in entries.chunks(2) {
1557 match (&pair[0].kind, &pair[1].kind) {
1558 (FormKind::Symbol(from), FormKind::Symbol(to)) => {
1559 filter
1560 .rename
1561 .insert(Arc::from(from.as_str()), Arc::from(to.as_str()));
1562 }
1563 _ => {
1564 return Err(
1565 ":refer-clojure :rename expects symbol keys and values".into()
1566 );
1567 }
1568 }
1569 }
1570 }
1571 other => return Err(format!(":refer-clojure does not support :{other}")),
1572 }
1573 i += 2;
1574 }
1575 Ok(filter)
1576}
1577
1578fn symbol_name_set(form: &Form, opt: &str) -> Result<HashSet<Arc<str>>, String> {
1580 let FormKind::Vector(items) = &form.kind else {
1581 return Err(format!(":refer-clojure :{opt} expects a vector of symbols"));
1582 };
1583 expand_reader_conds(items)
1584 .iter()
1585 .map(|f| match &f.kind {
1586 FormKind::Symbol(sym) => Ok(Arc::from(sym.as_str())),
1587 _ => Err(format!(":refer-clojure :{opt} expects symbols")),
1588 })
1589 .collect()
1590}
1591
1592fn eval_ns(args: &[Form], env: &mut Env) -> EvalResult {
1593 let (name, name_meta) = extract_ns_name_form(args.first(), env)?;
1594 env.globals.get_or_create_ns(&name);
1595 env.current_ns = Arc::from(name.as_str());
1596 if name != "clojure.core" {
1598 env.globals.refer_core(&name);
1599 }
1600 sync_star_ns(env);
1601
1602 let mut rest = &args[1..];
1604 if matches!(rest.first().map(|f| &f.kind), Some(FormKind::Str(_))) {
1605 rest = &rest[1..];
1606 }
1607 let mut attr_meta = None;
1608 if matches!(rest.first().map(|f| &f.kind), Some(FormKind::Map(_))) {
1609 attr_meta = Some(eval(&rest[0], env)?);
1610 rest = &rest[1..];
1611 }
1612
1613 if let Some(m) = merge_meta(name_meta, attr_meta) {
1614 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1615 ns_ptr.get().set_meta(m);
1616 }
1617
1618 let mut refer_clojure = None;
1629 for clause in rest {
1630 if let FormKind::List(items) = &clause.kind
1631 && matches!(items.first().map(|f| &f.kind), Some(FormKind::Keyword(k)) if k == "refer-clojure")
1632 {
1633 refer_clojure =
1634 Some(parse_refer_clojure_clause(&items[1..]).map_err(EvalError::Runtime)?);
1635 }
1636 }
1637 if name != "clojure.core" {
1638 env.globals
1639 .set_refer_clojure_filter(&name, refer_clojure)
1640 .map_err(EvalError::Runtime)?;
1641 }
1642
1643 for clause in rest {
1644 if let FormKind::List(items) = &clause.kind {
1645 match items.first().map(|f| &f.kind) {
1646 Some(FormKind::Keyword(k)) if k == "require" => {
1647 let expanded = expand_reader_conds(&items[1..]);
1649 for spec_form in &expanded {
1650 let spec =
1651 parse_require_spec_form(spec_form).map_err(EvalError::Runtime)?;
1652 load_ns(env.globals.clone(), &spec, &name)?;
1653 }
1654 }
1655 _ => {}
1658 }
1659 }
1660 }
1661
1662 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1663 Ok(Value::Namespace(ns_ptr))
1664}
1665
1666fn eval_load_file(args: &[Form], env: &mut Env) -> EvalResult {
1669 if args.is_empty() {
1670 return Err(EvalError::Runtime(
1671 "load-file requires a path argument".into(),
1672 ));
1673 }
1674 let path_val = eval(&args[0], env)?;
1675 let path = match &path_val {
1676 Value::Str(s) => s.get().clone(),
1677 v => {
1678 return Err(EvalError::Runtime(format!(
1679 "load-file: expected string, got {}",
1680 v.type_name()
1681 )));
1682 }
1683 };
1684 let src = std::fs::read_to_string(&path)
1685 .map_err(|e| EvalError::Runtime(format!("load-file: {e}")))?;
1686 let mut parser = cljrs_reader::Parser::new(src, path.clone());
1687 let forms = parser
1688 .parse_all()
1689 .map_err(|e| EvalError::Runtime(format!("load-file parse error: {e}")))?;
1690 let mut result = Value::Nil;
1691 for form in forms {
1692 let _alloc_frame = cljrs_gc::push_alloc_frame();
1693 result = eval(&form, env)?;
1694 }
1695 Ok(result)
1696}
1697
1698fn eval_letfn(args: &[Form], env: &mut Env) -> EvalResult {
1701 let bindings = match args.first().and_then(|f| f.as_vector()) {
1703 Some(v) => expand_reader_conds_cow(v).into_owned(),
1704 None => return Err(EvalError::Runtime("letfn requires a binding vector".into())),
1705 };
1706
1707 env.push_frame();
1708
1709 for binding in &bindings {
1710 if let Some(parts) = binding.as_list() {
1711 if parts.is_empty() {
1712 continue;
1713 }
1714 let fn_val = match eval_fn(parts, env) {
1718 Ok(v) => v,
1719 Err(e) => {
1720 env.pop_frame();
1721 return Err(e);
1722 }
1723 };
1724 let Some(name) = parts[0].as_symbol() else {
1725 env.pop_frame();
1726 return Err(EvalError::Runtime(
1727 "letfn binding name must be a symbol".into(),
1728 ));
1729 };
1730 env.bind(Arc::from(name), fn_val);
1731 }
1732 }
1733
1734 let body = &args[1..];
1735 let result = eval_body(body, env);
1736 env.pop_frame();
1737 result
1738}
1739
1740fn eval_in_ns(args: &[Form], env: &mut Env) -> EvalResult {
1743 if args.is_empty() {
1745 return Err(EvalError::Runtime("in-ns requires a namespace name".into()));
1746 }
1747 let ns_val = eval(&args[0], env)?;
1748 let ns_name = extract_ns_name(&ns_val)?;
1749 env.globals.get_or_create_ns(&ns_name);
1750 env.globals.refer_core(&ns_name);
1751 env.current_ns = Arc::from(ns_name.as_str());
1752 sync_star_ns(env);
1753 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1754 Ok(Value::Namespace(ns_ptr))
1755}
1756
1757fn eval_alias(args: &[Form], env: &mut Env) -> EvalResult {
1760 if args.len() < 2 {
1762 return Err(EvalError::Runtime(
1763 "alias requires alias-sym and namespace-sym".into(),
1764 ));
1765 }
1766 let alias_val = eval(&args[0], env)?;
1767 let ns_val = eval(&args[1], env)?;
1768
1769 let alias_name = extract_ns_name(&alias_val)?;
1770 let full_ns = extract_ns_name(&ns_val)?;
1771
1772 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
1773 let mut aliases = ns_ptr.get().aliases.lock().unwrap();
1774 aliases.insert(Arc::from(alias_name.as_str()), Arc::from(full_ns.as_str()));
1775 Ok(Value::Nil)
1776}
1777
1778fn extract_ns_name(v: &Value) -> EvalResult<String> {
1780 match v {
1781 Value::Symbol(s) => {
1782 Ok(s.get().name.as_ref().to_string())
1784 }
1785 Value::Str(s) => Ok(s.get().clone()),
1786 Value::Keyword(k) => Ok(k.get().name.as_ref().to_string()),
1787 other => Err(EvalError::Runtime(format!(
1788 "expected a symbol or string for namespace name, got {}",
1789 other.type_name()
1790 ))),
1791 }
1792}
1793
1794fn eval_defprotocol(args: &[Form], env: &mut Env) -> EvalResult {
1797 let name = require_sym(args, 0, "defprotocol")?;
1799 let proto_name: Arc<str> = Arc::from(name);
1800
1801 let methods_start = if args.len() > 1 && args[1].as_string().is_some() {
1803 2
1804 } else {
1805 1
1806 };
1807
1808 let mut methods: Vec<ProtocolMethod> = Vec::new();
1809 let mut extend_via_metadata = false;
1810
1811 let rest = &args[methods_start..];
1812 let mut i = 0;
1813 while i < rest.len() {
1814 if let Some(kw) = rest[i].as_keyword() {
1817 if kw == "extend-via-metadata" {
1818 extend_via_metadata = matches!(
1819 rest.get(i + 1).map(|f| &f.unmeta().kind),
1820 Some(FormKind::Bool(true))
1821 );
1822 }
1823 i += 2;
1824 continue;
1825 }
1826 let form = &rest[i];
1827 i += 1;
1828 let parts = match form.as_list() {
1830 Some(parts) => parts,
1831 None => continue, };
1833 if parts.is_empty() {
1834 continue;
1835 }
1836 let method_name: Arc<str> = match parts[0].as_symbol() {
1837 Some(s) => Arc::from(s),
1838 None => continue,
1839 };
1840 let (min_arity, variadic) = match parts.iter().find_map(|f| f.as_vector()) {
1842 Some(param_forms) => {
1843 let is_amp = |p: &Form| p.as_symbol() == Some("&");
1844 let variadic = param_forms.iter().any(is_amp);
1845 let fixed = param_forms.iter().filter(|p| !is_amp(p)).count();
1846 (fixed, variadic)
1847 }
1848 None => (1, false),
1849 };
1850 methods.push(ProtocolMethod {
1851 name: method_name,
1852 min_arity,
1853 variadic,
1854 });
1855 }
1856
1857 let ns: Arc<str> = env.current_ns.clone();
1858 let proto = Protocol::new(proto_name.clone(), ns, methods.clone(), extend_via_metadata);
1859 let proto_ptr = GcPtr::new(proto);
1860
1861 let proto_var = env.globals.intern(
1863 &env.current_ns,
1864 proto_name.clone(),
1865 Value::Protocol(proto_ptr.clone()),
1866 );
1867
1868 for method in &methods {
1870 let pf = ProtocolFn {
1871 protocol: proto_ptr.clone(),
1872 method_name: method.name.clone(),
1873 min_arity: method.min_arity,
1874 variadic: method.variadic,
1875 };
1876 env.globals.intern(
1877 &env.current_ns,
1878 method.name.clone(),
1879 Value::ProtocolFn(GcPtr::new(pf)),
1880 );
1881 }
1882
1883 Ok(Value::Var(proto_var))
1884}
1885
1886fn eval_extend_type(args: &[Form], env: &mut Env) -> EvalResult {
1889 if args.is_empty() {
1891 return Err(EvalError::Runtime(
1892 "extend-type requires a type symbol".into(),
1893 ));
1894 }
1895 let Some(type_sym) = args[0].as_symbol() else {
1896 return Err(EvalError::Runtime(
1897 "extend-type: first arg must be a type symbol".into(),
1898 ));
1899 };
1900 let type_tag = crate::interp::apply::resolve_type_tag(type_sym);
1901
1902 let mut current_proto: Option<GcPtr<Protocol>> = None;
1903
1904 for form in &args[1..] {
1905 match &form.unmeta().kind {
1906 FormKind::Symbol(s) => {
1907 let val = env.globals.lookup_in_ns(&env.current_ns, s);
1909 match val {
1910 Some(Value::Protocol(p)) => {
1911 current_proto = Some(p);
1912 }
1913 _ => {
1914 return Err(EvalError::Runtime(format!(
1915 "extend-type: {} is not a protocol",
1916 s
1917 )));
1918 }
1919 }
1920 }
1921 FormKind::List(parts) => {
1922 let proto = current_proto.as_ref().ok_or_else(|| {
1924 EvalError::Runtime("extend-type: method before protocol name".into())
1925 })?;
1926 if parts.is_empty() {
1927 continue;
1928 }
1929 let method_name: Arc<str> = match parts[0].as_symbol() {
1930 Some(s) => Arc::from(s),
1931 None => continue,
1932 };
1933 let fn_val = build_impl_fn(parts, env)?;
1934 let mut impls = proto.get().impls.lock().unwrap();
1935 impls
1936 .entry(type_tag.clone())
1937 .or_default()
1938 .insert(method_name, fn_val);
1939 drop(impls);
1940 cljrs_value::bump_protocol_generation();
1941 }
1942 _ => {}
1943 }
1944 }
1945
1946 Ok(Value::Nil)
1947}
1948
1949fn eval_extend_protocol(args: &[Form], env: &mut Env) -> EvalResult {
1952 if args.is_empty() {
1954 return Err(EvalError::Runtime(
1955 "extend-protocol requires a protocol".into(),
1956 ));
1957 }
1958 let Some(proto_sym) = args[0].as_symbol() else {
1959 return Err(EvalError::Runtime(
1960 "extend-protocol: first arg must be a protocol symbol".into(),
1961 ));
1962 };
1963 let proto_val = env.globals.lookup_in_ns(&env.current_ns, proto_sym);
1964 let proto_ptr = match proto_val {
1965 Some(Value::Protocol(p)) => p,
1966 _ => {
1967 return Err(EvalError::Runtime(format!(
1968 "extend-protocol: {} is not a protocol",
1969 proto_sym
1970 )));
1971 }
1972 };
1973
1974 let mut current_type: Option<Arc<str>> = None;
1975
1976 for form in &args[1..] {
1977 match &form.unmeta().kind {
1978 FormKind::Symbol(s) => {
1979 current_type = Some(crate::interp::apply::resolve_type_tag(s));
1980 }
1981 FormKind::List(parts) => {
1982 let type_tag = current_type.as_ref().ok_or_else(|| {
1983 EvalError::Runtime("extend-protocol: method before type name".into())
1984 })?;
1985 if parts.is_empty() {
1986 continue;
1987 }
1988 let method_name: Arc<str> = match parts[0].as_symbol() {
1989 Some(s) => Arc::from(s),
1990 None => continue,
1991 };
1992 let fn_val = build_impl_fn(parts, env)?;
1993 let mut impls = proto_ptr.get().impls.lock().unwrap();
1994 impls
1995 .entry(type_tag.clone())
1996 .or_default()
1997 .insert(method_name, fn_val);
1998 drop(impls);
1999 cljrs_value::bump_protocol_generation();
2000 }
2001 _ => {}
2002 }
2003 }
2004
2005 Ok(Value::Nil)
2006}
2007
2008fn build_impl_fn(parts: &[Form], env: &mut Env) -> EvalResult<Value> {
2013 if parts.len() < 2 {
2014 return Err(EvalError::Runtime(
2015 "protocol method impl requires params and body".into(),
2016 ));
2017 }
2018 let params_form = &parts[1];
2020 let body = &parts[2..];
2021 let arity = parse_arity(params_form, body)?;
2022 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
2023 let fn_name: Option<Arc<str>> = parts[0].as_symbol().map(Arc::from);
2024 let cljrs_fn = CljxFn::new(
2025 fn_name,
2026 vec![arity],
2027 closed_over_names,
2028 closed_over_vals,
2029 false,
2030 Arc::clone(&env.current_ns),
2031 );
2032 Ok(Value::Fn(GcPtr::new(cljrs_fn)))
2033}
2034
2035fn eval_defmulti(args: &[Form], env: &mut Env) -> EvalResult {
2038 let name = require_sym(args, 0, "defmulti")?;
2040 let name_arc: Arc<str> = Arc::from(name);
2041
2042 let rest_start = if args.len() > 2 && args[1].as_string().is_some() {
2043 2
2044 } else {
2045 1
2046 };
2047
2048 if args.len() <= rest_start {
2049 return Err(EvalError::Runtime(
2050 "defmulti requires a dispatch function".into(),
2051 ));
2052 }
2053
2054 let dispatch_fn = eval(&args[rest_start], env)?;
2055
2056 let mut default_dispatch = ":default".to_string();
2058 let mut i = rest_start + 1;
2059 while i + 1 < args.len() {
2060 if let FormKind::Keyword(k) = &args[i].kind
2061 && k == "default"
2062 {
2063 let dv = eval(&args[i + 1], env)?;
2064 default_dispatch = format!("{}", dv);
2065 }
2066 i += 2;
2067 }
2068
2069 let mfn = MultiFn::new(name_arc.clone(), dispatch_fn, default_dispatch);
2070 let var = env
2071 .globals
2072 .intern(&env.current_ns, name_arc, Value::MultiFn(GcPtr::new(mfn)));
2073 Ok(Value::Var(var))
2074}
2075
2076fn eval_defmethod(args: &[Form], env: &mut Env) -> EvalResult {
2079 if args.len() < 3 {
2081 return Err(EvalError::Runtime(
2082 "defmethod requires name, dispatch-val, params, and body".into(),
2083 ));
2084 }
2085 let multi_name = require_sym(args, 0, "defmethod")?;
2086
2087 let mf_ptr = match env.globals.lookup_in_ns(&env.current_ns, multi_name) {
2088 Some(Value::MultiFn(mf)) => mf,
2089 _ => {
2090 return Err(EvalError::Runtime(format!(
2091 "defmethod: {} is not a multimethod",
2092 multi_name
2093 )));
2094 }
2095 };
2096
2097 let dispatch_val = eval(&args[1], env)?;
2098 let key = format!("{}", dispatch_val);
2099
2100 let params_form = &args[2];
2102 let body = &args[3..];
2103 let arity = parse_arity(params_form, body)?;
2104 let (closed_over_names, closed_over_vals) = env.all_local_bindings();
2105 let fn_name = Some(Arc::from(multi_name));
2106 let cljrs_fn = CljxFn::new(
2107 fn_name,
2108 vec![arity],
2109 closed_over_names,
2110 closed_over_vals,
2111 false,
2112 Arc::clone(&env.current_ns),
2113 );
2114 let fn_val = Value::Fn(GcPtr::new(cljrs_fn));
2115
2116 mf_ptr
2117 .get()
2118 .methods
2119 .lock()
2120 .unwrap()
2121 .insert(key.clone(), fn_val);
2122 mf_ptr
2123 .get()
2124 .dispatch_vals
2125 .lock()
2126 .unwrap()
2127 .insert(key, dispatch_val);
2128
2129 Ok(Value::MultiFn(mf_ptr))
2130}
2131
2132fn eval_binding(args: &[Form], env: &mut Env) -> EvalResult {
2135 let pairs = match args.first().and_then(|f| f.as_vector()) {
2136 Some(v) => expand_pairs(v)
2137 .map_err(|_| EvalError::Runtime("binding vector must have even count".into()))?
2138 .into_owned(),
2139 None => return Err(EvalError::Runtime("binding requires a vector".into())),
2140 };
2141
2142 let mut frame: HashMap<usize, Value> = HashMap::new();
2143 for pair in pairs.chunks(2) {
2144 let Some(sym_str) = pair[0].as_symbol() else {
2145 return Err(EvalError::Runtime("binding targets must be symbols".into()));
2146 };
2147 let parsed = cljrs_value::Symbol::parse(sym_str);
2148 let ns_part: Arc<str> = match parsed.namespace.as_deref() {
2149 Some(ns_part) => env
2153 .globals
2154 .resolve_alias(&env.current_ns, ns_part)
2155 .unwrap_or_else(|| Arc::from(ns_part)),
2156 None => env.current_ns.clone(),
2157 };
2158 let var_ptr = env
2159 .globals
2160 .lookup_var_in_ns(&ns_part, &parsed.name)
2161 .ok_or_else(|| EvalError::UnboundSymbol(sym_str.to_string()))?;
2162 let val = eval(&pair[1], env)?;
2163 frame.insert(crate::env::dynamics::var_key_of(&var_ptr), val);
2164 }
2165
2166 let _guard = crate::env::dynamics::push_frame(frame);
2167 eval_body(&args[1..], env)
2168 }
2170
2171fn eval_defrecord(args: &[Form], env: &mut Env) -> EvalResult {
2174 if args.len() < 2 {
2176 return Err(EvalError::Runtime(
2177 "defrecord requires a name and field vector".into(),
2178 ));
2179 }
2180 let type_name = require_sym(args, 0, "defrecord")?;
2181 let type_tag: Arc<str> = Arc::from(type_name);
2182
2183 let Some(fields) = args[1].as_vector() else {
2185 return Err(EvalError::Runtime(
2186 "defrecord requires a field vector as second arg".into(),
2187 ));
2188 };
2189 let field_names: Vec<Arc<str>> = fields
2190 .iter()
2191 .map(|f| {
2192 f.as_symbol()
2193 .map(Arc::from)
2194 .ok_or_else(|| EvalError::Runtime("defrecord field names must be symbols".into()))
2195 })
2196 .collect::<EvalResult<_>>()?;
2197
2198 register_impls_for_tag(&type_tag, &args[2..], env)?;
2200
2201 let ns = env.current_ns.clone();
2205 let globals = env.globals.clone();
2206 let type_tag2 = type_tag.clone();
2207
2208 {
2210 let params: Vec<Arc<str>> = field_names.clone();
2211 let rest_param = None;
2212 use cljrs_reader::form::FormKind as FK;
2214 let dummy_span =
2215 cljrs_types::span::Span::new(std::sync::Arc::new("<defrecord>".into()), 0, 0, 1, 1);
2216 let make_form = |kind: FK| Form {
2217 kind,
2218 span: dummy_span.clone(),
2219 };
2220 let mut kv_forms: Vec<Form> = Vec::new();
2221 for f in &field_names {
2222 kv_forms.push(make_form(FK::Keyword(f.as_ref().to_string())));
2223 kv_forms.push(make_form(FK::Symbol(f.as_ref().to_string())));
2224 }
2225 let map_form = make_form(FK::Map(kv_forms));
2226 let body = vec![make_form(FK::List(vec![
2227 make_form(FK::Symbol("make-type-instance".into())),
2228 make_form(FK::Str(type_tag.as_ref().to_string())),
2229 map_form,
2230 ]))];
2231 let arity = CljxFnArity {
2232 params,
2233 rest_param,
2234 body,
2235 destructure_params: vec![],
2236 destructure_rest: None,
2237 ir_arity_id: crate::interp::arity::fresh_arity_id(),
2238 param_hints: vec![],
2239 rest_hint: None,
2240 };
2241 let fn_name: Arc<str> = Arc::from(format!("->{}", type_name));
2242 let ctor = CljxFn::new(
2243 Some(fn_name.clone()),
2244 vec![arity],
2245 vec![],
2246 vec![],
2247 false,
2248 Arc::clone(&ns),
2249 );
2250 globals.intern(&ns, fn_name, Value::Fn(GcPtr::new(ctor)));
2251 }
2252
2253 {
2255 use cljrs_reader::form::FormKind as FK;
2256 let dummy_span =
2257 cljrs_types::span::Span::new(std::sync::Arc::new("<defrecord>".into()), 0, 0, 1, 1);
2258 let make_form = |kind: FK| Form {
2259 kind,
2260 span: dummy_span.clone(),
2261 };
2262 let m_sym: Arc<str> = Arc::from("m__");
2263 let body = vec![make_form(FK::List(vec![
2264 make_form(FK::Symbol("make-type-instance".into())),
2265 make_form(FK::Str(type_tag2.as_ref().to_string())),
2266 make_form(FK::Symbol(m_sym.as_ref().to_string())),
2267 ]))];
2268 let arity = CljxFnArity {
2269 params: vec![m_sym],
2270 rest_param: None,
2271 body,
2272 destructure_params: vec![],
2273 destructure_rest: None,
2274 ir_arity_id: crate::interp::arity::fresh_arity_id(),
2275 param_hints: vec![],
2276 rest_hint: None,
2277 };
2278 let fn_name: Arc<str> = Arc::from(format!("map->{}", type_name));
2279 let ctor = CljxFn::new(
2280 Some(fn_name.clone()),
2281 vec![arity],
2282 vec![],
2283 vec![],
2284 false,
2285 Arc::clone(&ns),
2286 );
2287 globals.intern(&ns, fn_name, Value::Fn(GcPtr::new(ctor)));
2288 }
2289
2290 let type_sym = cljrs_value::Symbol::simple(type_name);
2292 globals.intern(
2293 &ns,
2294 Arc::from(type_name),
2295 Value::Symbol(GcPtr::new(type_sym)),
2296 );
2297 Ok(Value::Nil)
2298}
2299
2300fn eval_reify(args: &[Form], env: &mut Env) -> EvalResult {
2303 let n = crate::builtins::builtins::GENSYM_COUNTER
2306 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
2307 let type_tag: Arc<str> = Arc::from(format!("reify__{}", n));
2308
2309 register_impls_for_tag(&type_tag, args, env)?;
2311
2312 Ok(Value::TypeInstance(GcPtr::new(TypeInstance {
2314 type_tag,
2315 fields: MapValue::empty(),
2316 })))
2317}
2318
2319fn register_impls_for_tag(type_tag: &Arc<str>, forms: &[Form], env: &mut Env) -> EvalResult<()> {
2324 let mut current_proto: Option<GcPtr<cljrs_value::Protocol>> = None;
2325
2326 for form in forms {
2327 match &form.unmeta().kind {
2328 FormKind::Symbol(s) => {
2329 let val = env.globals.lookup_in_ns(&env.current_ns, s);
2330 match val {
2331 Some(Value::Protocol(p)) => {
2332 current_proto = Some(p);
2333 }
2334 _ => {
2335 return Err(EvalError::Runtime(format!(
2336 "reify/defrecord: {} is not a protocol",
2337 s
2338 )));
2339 }
2340 }
2341 }
2342 FormKind::List(parts) => {
2343 let proto = current_proto.as_ref().ok_or_else(|| {
2344 EvalError::Runtime("reify/defrecord: method impl before protocol name".into())
2345 })?;
2346 if parts.is_empty() {
2347 continue;
2348 }
2349 let method_name: Arc<str> = match parts[0].as_symbol() {
2350 Some(s) => Arc::from(s),
2351 None => continue,
2352 };
2353 let fn_val = build_impl_fn(parts, env)?;
2354 let mut impls = proto.get().impls.lock().unwrap();
2355 impls
2356 .entry(type_tag.clone())
2357 .or_default()
2358 .insert(method_name, fn_val);
2359 drop(impls);
2360 cljrs_value::bump_protocol_generation();
2361 }
2362 _ => {}
2363 }
2364 }
2365 Ok(())
2366}
2367
2368pub fn sync_star_ns(env: &mut Env) {
2373 if let Some(star_ns_var) = env.globals.lookup_var("clojure.core", "*ns*") {
2374 let ns_ptr = env.globals.get_or_create_ns(&env.current_ns);
2375 star_ns_var.get().bind(Value::Namespace(ns_ptr));
2376 }
2377}
2378
2379fn require_sym<'a>(args: &'a [Form], idx: usize, form_name: &str) -> EvalResult<&'a str> {
2380 args.get(idx).and_then(|f| f.as_symbol()).ok_or_else(|| {
2381 EvalError::Runtime(format!("{form_name} requires a symbol at position {idx}"))
2382 })
2383}
2384
2385fn eval_with_out_str(body: &[Form], env: &mut Env) -> EvalResult {
2388 crate::builtins::builtins::push_output_capture();
2389 let result = eval_body(body, env);
2390 let captured = crate::builtins::builtins::pop_output_capture().unwrap_or_default();
2391 result?;
2393 Ok(Value::string(captured))
2394}
2395
2396fn eval_await(args: &[Form], env: &mut Env) -> EvalResult {
2405 if args.is_empty() {
2406 return Err(EvalError::Runtime("await requires one argument".into()));
2407 }
2408 let val = eval(&args[0], env)?;
2409 match val {
2410 Value::Future(f) => {
2411 let mut guard = f.get().state.lock().unwrap();
2412 loop {
2413 match &*guard {
2414 FutureState::Done(v) => {
2415 f.get().mark_observed();
2416 return Ok(v.clone());
2417 }
2418 FutureState::Failed(v) => {
2419 f.get().mark_observed();
2420 return Err(EvalError::Thrown(v.clone()));
2421 }
2422 FutureState::GasExhausted => {
2423 f.get().mark_observed();
2424 return Err(EvalError::GasExhausted);
2425 }
2426 FutureState::Cancelled => {
2427 return Err(EvalError::Runtime("future was cancelled".into()));
2428 }
2429 FutureState::Running => {
2430 guard = f.get().cond.wait(guard).unwrap();
2431 }
2432 }
2433 }
2434 }
2435 Value::Promise(p) => Ok(p.get().deref_blocking()),
2436 other => Ok(other),
2437 }
2438}