Skip to main content

hara_native/
fiber.rs

1use super::*;
2use crate::lang::data::{List as PList, OrderedSet};
3
4#[path = "fiber/coroutine.rs"]
5pub(crate) mod coroutine;
6#[cfg(test)]
7#[path = "fiber/coroutine_tests.rs"]
8mod coroutine_tests;
9
10/// Core special forms that must be routed through the synchronous `eval` path
11/// because they need unevaluated arguments, structural handling, or namespace
12/// side effects. Forms with dedicated CPS arms in `list` are listed here too
13/// so that they do not accidentally reach `application`, but the dedicated arms
14/// take precedence.
15const SYNC_SPECIAL_FORMS: &[&str] = &[
16    ".",
17    "binding",
18    "comment",
19    "declare",
20    "def",
21    "defmacro",
22    "defn",
23    "do",
24    "eval",
25    "field",
26    "fn",
27    "if",
28    "intern-var",
29    "let",
30    "letfn",
31    "loop",
32    "ns",
33    "ns+",
34    "ns-alias-state",
35    "read-forms",
36    "recur",
37    "require",
38    "resolve",
39    "set!",
40    "syntax-quote",
41    "throw",
42    "try",
43    "var",
44    "var/set",
45];
46
47/// Completion names retained for the evaluator-free core surface.
48///
49/// This is a user-interface inventory, not an evaluator dispatch table. Actual
50/// callable resolution goes through the Foundation namespace or the native
51/// callable catalog; only `SYNC_SPECIAL_FORMS` controls fiber fallback.
52pub(crate) const COMPLETION_SYMBOLS: &[&str] = &[
53    "=",
54    "+",
55    "-",
56    "*",
57    "/",
58    "%",
59    "mod",
60    "<",
61    ">",
62    "<=",
63    ">=",
64    ".",
65    "abs",
66    "acos",
67    "acosh",
68    "alter-var-root",
69    "any?",
70    "array",
71    "atom",
72    "asin",
73    "asinh",
74    "assoc",
75    "assoc-in",
76    "atan",
77    "atan2",
78    "atanh",
79    "binding",
80    "bit-and",
81    "bit-or",
82    "bit-xor",
83    "bit-not",
84    "bit-shift-left",
85    "bit-shift-right",
86    "bytes",
87    "bytes/copy",
88    "bytes/count",
89    "bytes/get",
90    "bytes/set",
91    "bytes/s8",
92    "bytes/slice",
93    "bytes/u8",
94    "cas!",
95    "ceil",
96    "char?",
97    "comp",
98    "comp2",
99    "comp3",
100    "complement",
101    "concat",
102    "conj",
103    "cons",
104    "constantly",
105    "cos",
106    "cosh",
107    "ns-current",
108    "cycle",
109    "dec",
110    "declare",
111    "def",
112    "defmacro",
113    "defn",
114    "do",
115    "drop",
116    "drop-while",
117    "double?",
118    "empty",
119    "empty?",
120    "eval",
121    "eval-in-ns",
122    "even?",
123    "every?",
124    "exp",
125    "false?",
126    "file/read",
127    "file/join",
128    "file/resolve",
129    "file/write",
130    "file/exists?",
131    "file/stat",
132    "file/entries",
133    "file/list",
134    "file/walk",
135    "file/mkdir",
136    "file/delete",
137    "file/copy",
138    "file/move",
139    "file/temp-file",
140    "file/temp-directory",
141    "filter",
142    "field",
143    "first",
144    "floor",
145    "fn",
146    "hash",
147    "identity",
148    "if",
149    "inc",
150    "instance?",
151    "intern-var",
152    "interleave",
153    "interpose",
154    "iter",
155    "iter-close",
156    "iter-concat",
157    "iter-cycle",
158    "iter-drop",
159    "iter-drop-while",
160    "iter-every?",
161    "iter-any?",
162    "iter-finite?",
163    "iter-next?",
164    "iter-interleave",
165    "iter-interpose",
166    "iter-iterate",
167    "iter-keep",
168    "iter-map",
169    "iter-mapcat",
170    "iter-materialize",
171    "iter-next",
172    "iter-partition-pair",
173    "iter-partition",
174    "iter-partition-all",
175    "iter-range",
176    "iter-repeatedly",
177    "iter-constantly",
178    "iter-filter",
179    "iter-take",
180    "iter-take-while",
181    "iter-zip",
182    "iter?",
183    "iterate",
184    "keep",
185    "key",
186    "keys",
187    "keyword",
188    "keyword?",
189    "last",
190    "let",
191    "letfn",
192    "list",
193    "list?",
194    "load-string",
195    "long?",
196    "bigint?",
197    "integer?",
198    "loop",
199    "map",
200    "map?",
201    "mapcat",
202    "neg?",
203    "name",
204    "namespace",
205    "nil?",
206    "number?",
207    "ns",
208    "ns-alias-state",
209    "ns-loaded?",
210    "ns-state",
211    "ns-create",
212    "ns-find",
213    "ns-info",
214    "ns-list",
215    "ns-aliases",
216    "ns-name",
217    "ns-publics",
218    "ns-vars",
219    "nth",
220    "not",
221    "peek",
222    "not-empty",
223    "object",
224    "odd?",
225    "p",
226    "pair",
227    "partition-pair",
228    "partition",
229    "partition-all",
230    "pointer",
231    "pos?",
232    "pow",
233    "quot",
234    "pr-str",
235    "capture",
236    "Printer/capture",
237    "println",
238    "promise",
239    "promise/run",
240    "promise?",
241    "promise/all",
242    "promise/cancel",
243    "promise/delay",
244    "promise/from",
245    "promise/new",
246    "range",
247    "read-forms",
248    "read-string",
249    "recur",
250    "repeat",
251    "repeatedly",
252    "require",
253    "resolve",
254    "rem",
255    "reset!",
256    "rest",
257    "reverse",
258    "second",
259    "seq",
260    "seq?",
261    "set!",
262    "set?",
263    "string?",
264    "symbol?",
265    "swap!",
266    "sin",
267    "sinh",
268    "socket/close",
269    "socket/connect",
270    "socket/send",
271    "str",
272    "str/decode-utf8",
273    "str/encode-utf8",
274    "str/length",
275    "str/blank?",
276    "str/includes?",
277    "str/starts-with?",
278    "str/ends-with?",
279    "str/char-at",
280    "str/slice",
281    "str/index-of",
282    "str/last-index-of",
283    "str/split",
284    "str/split-lines",
285    "str/join",
286    "str/repeat",
287    "str/replace",
288    "str/replace-first",
289    "str/trim-left",
290    "str/trim-right",
291    "str/upper",
292    "str/lower",
293    "str/capitalize",
294    "str/decapitalize",
295    "str/pad-left",
296    "str/pad-right",
297    "str/reverse",
298    "sqrt",
299    "symbol",
300    "take",
301    "take-while",
302    "tan",
303    "tanh",
304    "throw",
305    "true?",
306    "try",
307    "tup",
308    "update",
309    "update-in",
310    "val",
311    "vals",
312    "var",
313    "var-sym",
314    "var/set",
315    "vector",
316    "vector?",
317    "fn?",
318    "function?",
319    "hash-map",
320    "hash-set",
321    "zero?",
322    "zip",
323    "__map-transform",
324    "__iterator-transform",
325];
326
327pub(crate) fn completion_symbols() -> &'static [&'static str] {
328    COMPLETION_SYMBOLS
329}
330
331pub(crate) type Cont = Box<dyn FnOnce(Result<Value, String>) -> Step>;
332pub type Resume = Box<dyn FnOnce(PromiseState) -> Step>;
333pub enum Step {
334    Done(Result<Value, String>),
335    Wait(Promise, Resume),
336    Yield(Value, Box<dyn FnOnce(Value) -> Step>),
337    /// Defers the next synchronous continuation to the fiber driver.  Without
338    /// this trampoline, a document with many top-level forms keeps one Rust
339    /// stack frame per completed form (and can exhaust the smaller WASM stack).
340    Continue(Box<dyn FnOnce() -> Step>),
341}
342
343fn with_trace_stack_step(trace: Vec<TraceFrame>, step: Step) -> Step {
344    match step {
345        Step::Continue(next) => Step::Continue(Box::new(move || {
346            let step = with_trace_stack(&trace, next);
347            with_trace_stack_step(trace, step)
348        })),
349        Step::Wait(promise, resume) => Step::Wait(
350            promise,
351            Box::new(move |state| {
352                let step = with_trace_stack(&trace, || resume(state));
353                with_trace_stack_step(trace, step)
354            }),
355        ),
356        Step::Yield(value, resume) => Step::Yield(
357            value,
358            Box::new(move |value| {
359                let step = with_trace_stack(&trace, || resume(value));
360                with_trace_stack_step(trace, step)
361            }),
362        ),
363        Step::Done(result) => Step::Done(result),
364    }
365}
366
367#[derive(Debug, Clone, PartialEq)]
368pub enum EvalFiberState {
369    Running,
370    Suspended,
371    Completed(Value),
372    Failed(String),
373    Cancelled,
374}
375
376pub struct EvalFiber {
377    env: Rc<RefCell<HashMap<String, Value>>>,
378    namespace_registry: NamespaceRegistry<Value>,
379    pending: Option<Promise>,
380    resume: Option<Resume>,
381    state: EvalFiberState,
382}
383impl EvalFiber {
384    pub fn start(source: &str, env: HashMap<String, Value>) -> Result<Self, String> {
385        let forms = crate::kernel::read_forms(source).map_err(|error| error.to_string())?;
386        Self::start_forms(
387            forms
388                .iter()
389                .map(crate::core::attach_exception_sites)
390                .collect(),
391            env,
392        )
393    }
394    pub fn start_forms(forms: Vec<Form>, env: HashMap<String, Value>) -> Result<Self, String> {
395        let (namespace_registry, environment) = execution_context(env);
396        let env = Rc::new(RefCell::new(environment));
397        let step = with_namespace_registry(&namespace_registry, || {
398            forms_cps(
399                Rc::new(forms),
400                0,
401                Value::Nil,
402                env.clone(),
403                Box::new(Step::Done),
404            )
405        });
406        let mut fiber = Self {
407            env,
408            namespace_registry,
409            pending: None,
410            resume: None,
411            state: EvalFiberState::Running,
412        };
413        fiber.accept(step);
414        Ok(fiber)
415    }
416    pub fn state(&self) -> EvalFiberState {
417        self.state.clone()
418    }
419    pub fn pending(&self) -> Option<Promise> {
420        self.pending.clone()
421    }
422    pub fn environment(&self) -> HashMap<String, Value> {
423        self.env.borrow().clone()
424    }
425    pub fn resume(&mut self, state: PromiseState) -> EvalFiberState {
426        if !matches!(self.state, EvalFiberState::Suspended) {
427            return self.state();
428        }
429        let Some(resume) = self.resume.take() else {
430            self.state = EvalFiberState::Failed("fiber continuation missing".into());
431            return self.state();
432        };
433        self.pending = None;
434        self.state = EvalFiberState::Running;
435        let step = with_namespace_registry(&self.namespace_registry, || resume(state));
436        self.accept(step);
437        self.state()
438    }
439    pub fn cancel(&mut self) -> bool {
440        if matches!(
441            self.state,
442            EvalFiberState::Completed(_) | EvalFiberState::Failed(_) | EvalFiberState::Cancelled
443        ) {
444            return false;
445        }
446        if let Some(pending) = self.pending.take() {
447            pending.notify_cancel();
448        }
449        self.resume = None;
450        self.state = EvalFiberState::Cancelled;
451        true
452    }
453    pub fn drive_sync(&mut self) -> Result<Value, String> {
454        loop {
455            match self.state() {
456                EvalFiberState::Completed(v) => return Ok(v),
457                EvalFiberState::Failed(e) => return Err(e),
458                EvalFiberState::Cancelled => return Err("eval cancelled".into()),
459                EvalFiberState::Running => return Err("fiber is running".into()),
460                EvalFiberState::Suspended => {
461                    let Some(pending) = self.pending() else {
462                        return Err("fiber suspended without promise".into());
463                    };
464                    match pending.wait_state() {
465                        PromiseState::Fulfilled(v) => {
466                            self.resume(PromiseState::Fulfilled(v));
467                        }
468                        PromiseState::Rejected(e) => {
469                            self.resume(PromiseState::Rejected(e));
470                        }
471                        PromiseState::Pending => {
472                            #[cfg(not(target_arch = "wasm32"))]
473                            self.resume(pending.wait_state());
474                            #[cfg(target_arch = "wasm32")]
475                            return Err(
476                                "deref cannot block on a pending promise outside an HTA fiber"
477                                    .into(),
478                            );
479                        }
480                    }
481                }
482            }
483        }
484    }
485    fn accept(&mut self, mut step: Step) {
486        loop {
487            match step {
488                Step::Continue(next) => {
489                    step = with_namespace_registry(&self.namespace_registry, next)
490                }
491                Step::Done(Ok(v)) => {
492                    self.state = EvalFiberState::Completed(v);
493                    return;
494                }
495                Step::Done(Err(e)) => {
496                    self.state = EvalFiberState::Failed(e);
497                    return;
498                }
499                Step::Wait(p, r) => {
500                    self.pending = Some(p);
501                    self.resume = Some(r);
502                    self.state = EvalFiberState::Suspended;
503                    return;
504                }
505                Step::Yield(_, _) => {
506                    self.state = EvalFiberState::Failed(
507                        "coroutine/yield used outside of a coroutine".into(),
508                    );
509                    return;
510                }
511            }
512        }
513    }
514}
515
516fn forms_cps(
517    forms: Rc<Vec<Form>>,
518    i: usize,
519    last: Value,
520    env: Rc<RefCell<HashMap<String, Value>>>,
521    k: Cont,
522) -> Step {
523    if i == forms.len() || matches!(last, Value::Recur(_)) {
524        return k(Ok(last));
525    }
526    let next = forms.clone();
527    let e = env.clone();
528    let form = forms[i].clone();
529    let boundary_form = form.clone();
530    let boundary_env = env.clone();
531    one(
532        form,
533        env,
534        Box::new(move |r| match r {
535            Ok(v) => {
536                coroutine::semantic::record_boundary(
537                    coroutine::semantic::EvalSemanticRule::FormReturn,
538                    &boundary_form,
539                    &v,
540                    &boundary_env,
541                );
542                Step::Continue(Box::new(move || forms_cps(next, i + 1, v, e, k)))
543            }
544            Err(x) => {
545                coroutine::semantic::record_error(
546                    coroutine::semantic::EvalSemanticRule::ErrorRaise,
547                    &boundary_form,
548                    &x,
549                    false,
550                    &boundary_env,
551                );
552                k(Err(x))
553            }
554        }),
555    )
556}
557fn values_cps(
558    forms: Rc<Vec<Form>>,
559    i: usize,
560    values: Vec<Value>,
561    env: Rc<RefCell<HashMap<String, Value>>>,
562    k: Box<dyn FnOnce(Result<Vec<Value>, String>) -> Step>,
563) -> Step {
564    if i == forms.len() {
565        return k(Ok(values));
566    }
567    let next = forms.clone();
568    let e = env.clone();
569    let form = forms[i].clone();
570    let boundary_form = form.clone();
571    let boundary_env = env.clone();
572    one(
573        form,
574        env,
575        Box::new(move |r| match r {
576            Ok(v) => {
577                coroutine::semantic::record_boundary(
578                    coroutine::semantic::EvalSemanticRule::ValueReturn,
579                    &boundary_form,
580                    &v,
581                    &boundary_env,
582                );
583                let mut values = values;
584                values.push(v);
585                Step::Continue(Box::new(move || values_cps(next, i + 1, values, e, k)))
586            }
587            Err(x) => {
588                coroutine::semantic::record_error(
589                    coroutine::semantic::EvalSemanticRule::ErrorRaise,
590                    &boundary_form,
591                    &x,
592                    false,
593                    &boundary_env,
594                );
595                k(Err(x))
596            }
597        }),
598    )
599}
600fn one(form: Form, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
601    if let Err(error) = super::check_evaluation_interrupt() {
602        return k(Err(error));
603    }
604    match form {
605        Form::Map(entries) => {
606            let flat = Rc::new(entries.into_iter().flat_map(|(a, b)| [a, b]).collect());
607            values_cps(
608                flat,
609                0,
610                Vec::new(),
611                env,
612                Box::new(move |r| {
613                    k(r.map(|v| {
614                        Value::Map(
615                            v.chunks_exact(2)
616                                .map(|p| (p[0].clone(), p[1].clone()))
617                                .collect::<PMap<Value, Value>>(),
618                        )
619                    }))
620                }),
621            )
622        }
623        Form::Set(v) => values_cps(
624            Rc::new(v),
625            0,
626            Vec::new(),
627            env,
628            Box::new(move |r| {
629                k(r.map(|v| {
630                    Value::OrderedSet(Box::new(
631                        unique_values(v).into_iter().collect::<OrderedSet<Value>>(),
632                    ))
633                }))
634            }),
635        ),
636        Form::Vector(v) => values_cps(
637            Rc::new(v),
638            0,
639            Vec::new(),
640            env,
641            Box::new(move |r| k(r.and_then(vector_literal))),
642        ),
643        Form::List(v) if v.is_empty() => k(Ok(Value::List(PList::new()))),
644        Form::List(v) if v.len() == 2 && matches!(&v[0],Form::Symbol(n)if n=="quote") => {
645            k(literal_value(&v[1]))
646        }
647        Form::List(v) => list(v, env, k),
648        simple => sync(simple, env, k),
649    }
650}
651fn sync(form: Form, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
652    let result = {
653        let mut borrowed = env.borrow_mut();
654        eval(&form, &mut borrowed)
655    };
656    k(result)
657}
658fn list(v: Vec<Form>, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
659    let head = match &v[0] {
660        Form::Symbol(n) => Some(n.as_str()),
661        _ => None,
662    };
663    match head {
664        Some("do") => forms_cps(Rc::new(v[1..].to_vec()), 0, Value::Nil, env, k),
665        Some("if") => {
666            if v.len() != 3 && v.len() != 4 {
667                return k(Err("if expects 2 or 3 arguments".into()));
668            }
669            let vv = v.clone();
670            let e = env.clone();
671            one(
672                v[1].clone(),
673                env,
674                Box::new(move |r| match r {
675                    Ok(x) if x.truthy() => one(vv[2].clone(), e, k),
676                    Ok(_) if vv.len() == 4 => one(vv[3].clone(), e, k),
677                    Ok(_) => k(Ok(Value::Nil)),
678                    Err(x) => k(Err(x)),
679                }),
680            )
681        }
682        Some("and") => and_cps(Rc::new(v[1..].to_vec()), 0, Value::Bool(true), env, k),
683        Some("or") => or_cps(Rc::new(v[1..].to_vec()), 0, Value::Nil, env, k),
684        Some("cond") => {
685            if v.len() % 2 == 0 {
686                return k(Err("cond expects test/expression pairs".into()));
687            }
688            cond_cps(Rc::new(v[1..].to_vec()), 0, env, k)
689        }
690        Some("let") => scoped(v, env, k, false),
691        Some("loop") => scoped(v, env, k, true),
692        Some("recur") => values_cps(
693            Rc::new(v[1..].to_vec()),
694            0,
695            Vec::new(),
696            env,
697            Box::new(move |r| k(r.map(Value::Recur))),
698        ),
699        Some("try") => try_cps(v, env, k),
700        Some("throw") => {
701            if v.len() != 2 {
702                return k(Err("throw expects one value".into()));
703            }
704            one(
705                v[1].clone(),
706                env,
707                Box::new(move |r| match r {
708                    Ok(x) if matches!(x, Value::ExceptionInfo(_)) => k(Err(thrown_error(x))),
709                    Ok(_) => k(Err("throw expects an Exception value created by ex".into())),
710                    Err(x) => k(Err(x)),
711                }),
712            )
713        }
714        Some("std.foundation.coroutine/resume") => coroutine::resume_form(v, env, k),
715        Some("std.protocol.icoroutine.ICoroutine/resume") => {
716            coroutine::resume_protocol_form(v, env, k)
717        }
718        Some("def") | Some("var/set") => bind_form(v, env, k),
719        Some("set!") => set_form(v, env, k),
720        Some("resolve") if matches!(env.borrow().get("resolve"), Some(value) if !matches!(value, Value::Var(_))) => {
721            application(v, env, k)
722        }
723        Some(name) if SYNC_SPECIAL_FORMS.contains(&name) => sync(Form::List(v), env, k),
724        _ => application(v, env, k),
725    }
726}
727
728fn and_cps(
729    forms: Rc<Vec<Form>>,
730    index: usize,
731    last: Value,
732    env: Rc<RefCell<HashMap<String, Value>>>,
733    k: Cont,
734) -> Step {
735    if index == forms.len() || !last.truthy() {
736        return k(Ok(last));
737    }
738    let next = forms.clone();
739    let e = env.clone();
740    one(
741        forms[index].clone(),
742        env,
743        Box::new(move |result| match result {
744            Ok(value) => Step::Continue(Box::new(move || and_cps(next, index + 1, value, e, k))),
745            Err(error) => k(Err(error)),
746        }),
747    )
748}
749
750fn or_cps(
751    forms: Rc<Vec<Form>>,
752    index: usize,
753    last: Value,
754    env: Rc<RefCell<HashMap<String, Value>>>,
755    k: Cont,
756) -> Step {
757    if index == forms.len() {
758        return k(Ok(last));
759    }
760    let next = forms.clone();
761    let e = env.clone();
762    one(
763        forms[index].clone(),
764        env,
765        Box::new(move |result| match result {
766            Ok(value) if value.truthy() => k(Ok(value)),
767            Ok(value) => Step::Continue(Box::new(move || or_cps(next, index + 1, value, e, k))),
768            Err(error) => k(Err(error)),
769        }),
770    )
771}
772
773fn cond_cps(
774    clauses: Rc<Vec<Form>>,
775    index: usize,
776    env: Rc<RefCell<HashMap<String, Value>>>,
777    k: Cont,
778) -> Step {
779    if index == clauses.len() {
780        return k(Ok(Value::Nil));
781    }
782    let next = clauses.clone();
783    let e = env.clone();
784    one(
785        clauses[index].clone(),
786        env,
787        Box::new(move |result| match result {
788            Ok(value) if value.truthy() => one(next[index + 1].clone(), e, k),
789            Ok(_) => Step::Continue(Box::new(move || cond_cps(next, index + 2, e, k))),
790            Err(error) => k(Err(error)),
791        }),
792    )
793}
794
795type Previous = Vec<(String, Option<Value>)>;
796fn bindings(forms: &[Form], op: &str) -> Result<Vec<Form>, String> {
797    let v = match forms.get(1) {
798        Some(Form::List(v)) | Some(Form::Vector(v)) => v.clone(),
799        _ => return Err(format!("{op} expects bindings")),
800    };
801    if v.len() % 2 != 0 {
802        return Err(format!("{op} bindings require name/value pairs"));
803    }
804    Ok(v)
805}
806fn bind_values(
807    v: Rc<Vec<Form>>,
808    i: usize,
809    old: Previous,
810    env: Rc<RefCell<HashMap<String, Value>>>,
811    k: Box<dyn FnOnce(Result<Previous, String>, Rc<RefCell<HashMap<String, Value>>>) -> Step>,
812) -> Step {
813    if i == v.len() {
814        return k(Ok(old), env);
815    }
816    let pattern = v[i].clone();
817    let vv = v.clone();
818    let e = env.clone();
819    one(
820        v[i + 1].clone(),
821        env,
822        Box::new(move |r| match r {
823            Ok(x) => {
824                let mut old = old;
825                let before = e.borrow().clone();
826                let mut names = Vec::new();
827                let binding = {
828                    let mut environment = e.borrow_mut();
829                    crate::core::bind_pattern(&pattern, x, &mut environment, &mut names, None)
830                };
831                if let Err(error) = binding {
832                    return k(Err(format!("destructuring failed: {error}")), e);
833                }
834                for name in names {
835                    old.push((name.clone(), before.get(&name).cloned()));
836                }
837                Step::Continue(Box::new(move || bind_values(vv, i + 2, old, e, k)))
838            }
839            Err(x) => k(Err(x), e),
840        }),
841    )
842}
843fn restore(env: &mut HashMap<String, Value>, old: Previous) {
844    for (n, v) in old.into_iter().rev() {
845        if let Some(v) = v {
846            env.insert(n, v);
847        } else {
848            env.remove(&n);
849        }
850    }
851}
852fn scoped(v: Vec<Form>, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont, is_loop: bool) -> Step {
853    if v.len() < 3 {
854        return k(Err("binding form expects bindings and body".into()));
855    }
856    let b = match bindings(&v, if is_loop { "loop" } else { "let" }) {
857        Ok(x) => x,
858        Err(x) => return k(Err(x)),
859    };
860    let patterns = Rc::new(b.chunks(2).map(|pair| pair[0].clone()).collect());
861    let body = if v.len() == 3 {
862        v[2].clone()
863    } else {
864        Form::List(
865            std::iter::once(Form::Symbol("do".into()))
866                .chain(v[2..].iter().cloned())
867                .collect(),
868        )
869    };
870    bind_values(
871        Rc::new(b),
872        0,
873        Vec::new(),
874        env,
875        Box::new(move |r, e| match r {
876            Ok(old) if is_loop => loop_body(patterns, body, old, e, k),
877            Ok(old) => {
878                let re = e.clone();
879                one(
880                    body,
881                    e,
882                    Box::new(move |r| {
883                        restore(&mut re.borrow_mut(), old);
884                        k(r)
885                    }),
886                )
887            }
888            Err(x) => k(Err(x)),
889        }),
890    )
891}
892fn loop_body(
893    patterns: Rc<Vec<Form>>,
894    body: Form,
895    old: Previous,
896    env: Rc<RefCell<HashMap<String, Value>>>,
897    k: Cont,
898) -> Step {
899    let pp = patterns.clone();
900    let bb = body.clone();
901    let oo = old.clone();
902    let ee = env.clone();
903    one(
904        body,
905        env,
906        Box::new(move |r| match r {
907            Ok(Value::Recur(v)) => {
908                if v.len() != pp.len() {
909                    restore(&mut ee.borrow_mut(), oo);
910                    return k(Err("loop recur arity mismatch".into()));
911                }
912                for (pattern, value) in pp.iter().zip(v) {
913                    let mut names = Vec::new();
914                    if let Err(error) = crate::core::bind_pattern(
915                        pattern,
916                        value,
917                        &mut ee.borrow_mut(),
918                        &mut names,
919                        None,
920                    ) {
921                        restore(&mut ee.borrow_mut(), oo);
922                        return k(Err(format!("loop destructuring failed: {error}")));
923                    }
924                }
925                Step::Continue(Box::new(move || loop_body(pp, bb, oo, ee, k)))
926            }
927            r => {
928                restore(&mut ee.borrow_mut(), oo);
929                k(r)
930            }
931        }),
932    )
933}
934
935fn set_form(v: Vec<Form>, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
936    let effect_form = Form::List(v.clone());
937    if v.len() != 3 {
938        return k(Err("set! expects a place and value".into()));
939    }
940    if matches!(&v[1], Form::Symbol(_) | Form::Metadata(_, _)) {
941        return bind_form(v, env, k);
942    }
943    let Form::List(place) = &v[1] else {
944        return k(Err("set! expects a name symbol or field place".into()));
945    };
946    if !matches!(place.first(), Some(Form::Symbol(operation)) if operation == "field") {
947        return k(Err("set! expects a name symbol or field place".into()));
948    }
949    if place.len() != 3 {
950        return k(Err("set! field place expects a receiver and field".into()));
951    }
952    let field = match &place[2] {
953        Form::Keyword(field) | Form::Symbol(field) if !field.contains('/') => field.clone(),
954        _ => {
955            return k(Err(
956                "set! field place expects an unqualified literal field".into()
957            ))
958        }
959    };
960    let receiver = place[1].clone();
961    let replacement = v[2].clone();
962    let replacement_env = env.clone();
963    let effect_env = replacement_env.clone();
964    one(
965        receiver,
966        env,
967        Box::new(move |receiver_result| match receiver_result {
968            Ok(receiver) => one(
969                replacement,
970                replacement_env,
971                Box::new(move |replacement_result| match replacement_result {
972                    Ok(replacement) => {
973                        let after = replacement.clone();
974                        match crate::core::mutable_field_set(&receiver, &field, replacement) {
975                            Ok(result) => {
976                                coroutine::semantic::record_effect(
977                                    coroutine::semantic::EvalSemanticRule::FieldSet,
978                                    &effect_form,
979                                    field,
980                                    None,
981                                    after,
982                                    &effect_env,
983                                );
984                                k(Ok(result))
985                            }
986                            Err(error) => k(Err(error)),
987                        }
988                    }
989                    Err(error) => k(Err(error)),
990                }),
991            ),
992            Err(error) => k(Err(error)),
993        }),
994    )
995}
996
997fn bind_form(v: Vec<Form>, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
998    let effect_form = Form::List(v.clone());
999    if v.len() != 3 {
1000        return k(Err("binding form expects symbol and value".into()));
1001    }
1002    let op = match &v[0] {
1003        Form::Symbol(n) => n.clone(),
1004        _ => unreachable!(),
1005    };
1006    let (name, metadata) = match &v[1] {
1007        Form::Symbol(n) => (n.clone(), None),
1008        Form::Metadata(meta, value) => match value.as_ref() {
1009            Form::Symbol(n) => match crate::core::metadata_from_form(meta) {
1010                Ok(metadata) => (n.clone(), Some(metadata)),
1011                Err(error) => return k(Err(error)),
1012            },
1013            _ => return k(Err(format!("{op} name must be a symbol"))),
1014        },
1015        _ => return k(Err(format!("{op} name must be a symbol"))),
1016    };
1017    let e = env.clone();
1018    one(
1019        v[2].clone(),
1020        env,
1021        Box::new(move |r| match r {
1022            Ok(x) => {
1023                let effect_after = x.clone();
1024                let mut effect_before = None;
1025                let effect_target;
1026                let mut env = e.borrow_mut();
1027                let result = if op == "def" {
1028                    let origin = crate::core::definition_origin();
1029                    let var = if let Some(Value::Var(var)) = env.get(&name) {
1030                        effect_before = Some(var.deref_value());
1031                        if crate::core::binding_is_local(var) {
1032                            var.reset_value(x.clone());
1033                            var.set_origin(origin);
1034                            if let Some(meta) = &metadata {
1035                                var.set_hara_metadata(Some(meta.clone()));
1036                            }
1037                            var.clone()
1038                        } else {
1039                            let var = crate::kernel::Var::new(
1040                                crate::core::local_var_name(&name),
1041                                x.clone(),
1042                            );
1043                            var.set_origin(origin);
1044                            if let Some(meta) = &metadata {
1045                                var.set_hara_metadata(Some(meta.clone()));
1046                            }
1047                            env.insert(name.clone(), Value::Var(var.clone()));
1048                            var
1049                        }
1050                    } else {
1051                        let var =
1052                            crate::kernel::Var::new(crate::core::local_var_name(&name), x.clone());
1053                        var.set_origin(origin);
1054                        if let Some(meta) = &metadata {
1055                            var.set_hara_metadata(Some(meta.clone()));
1056                        }
1057                        env.insert(name.clone(), Value::Var(var.clone()));
1058                        var
1059                    };
1060                    effect_target = var.display();
1061                    Value::Var(var)
1062                } else {
1063                    let Some(c) = binding_var(&mut env, &name) else {
1064                        return k(Err(format!("unbound var: {name}")));
1065                    };
1066                    effect_before = Some(c.deref_value());
1067                    effect_target = c.display();
1068                    c.reset_value(x.clone());
1069                    if let Some(meta) = metadata {
1070                        c.set_hara_metadata(Some(meta));
1071                    }
1072                    x
1073                };
1074                drop(env);
1075                coroutine::semantic::record_effect(
1076                    if op == "def" {
1077                        coroutine::semantic::EvalSemanticRule::VarDefine
1078                    } else {
1079                        coroutine::semantic::EvalSemanticRule::VarSet
1080                    },
1081                    &effect_form,
1082                    effect_target,
1083                    effect_before,
1084                    effect_after,
1085                    &e,
1086                );
1087                k(Ok(result))
1088            }
1089            Err(x) => k(Err(x)),
1090        }),
1091    )
1092}
1093
1094fn try_cps(v: Vec<Form>, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
1095    let mut body = Vec::new();
1096    let mut catches = Vec::new();
1097    let mut finals = Vec::new();
1098    let mut clauses_started = false;
1099    for f in v.into_iter().skip(1) {
1100        match &f {
1101            Form::List(p) if !p.is_empty() && matches!(&p[0],Form::Symbol(n)if n=="catch") => {
1102                clauses_started = true;
1103                catches.push(p.clone())
1104            }
1105            Form::List(p) if !p.is_empty() && matches!(&p[0],Form::Symbol(n)if n=="finally") => {
1106                clauses_started = true;
1107                finals.extend_from_slice(&p[1..])
1108            }
1109            _ if !clauses_started => body.push(f),
1110            _ => return k(Err("try clauses must follow body".into())),
1111        }
1112    }
1113    let e = env.clone();
1114    forms_cps(
1115        Rc::new(body),
1116        0,
1117        Value::Nil,
1118        env,
1119        Box::new(move |r| finish_try(r, catches, finals, e, k)),
1120    )
1121}
1122fn finish_try(
1123    r: Result<Value, String>,
1124    catches: Vec<Vec<Form>>,
1125    finals: Vec<Form>,
1126    env: Rc<RefCell<HashMap<String, Value>>>,
1127    k: Cont,
1128) -> Step {
1129    match r {
1130        Err(x) => {
1131            let mut selected = None;
1132            let mut saw_unconditional = false;
1133            for parts in catches {
1134                if saw_unconditional {
1135                    return k(Err(
1136                        "unconditional catch must be the last catch clause".into()
1137                    ));
1138                }
1139                let parsed = match parse_catch_clause(&parts) {
1140                    Ok(parsed) => parsed,
1141                    Err(error) => return k(Err(error)),
1142                };
1143                saw_unconditional = parsed.0.is_none();
1144                if parsed
1145                    .0
1146                    .as_deref()
1147                    .is_none_or(|selector| crate::core::catch_matches(&x, selector))
1148                {
1149                    selected = Some((parts, parsed.1, parsed.2));
1150                    break;
1151                }
1152            }
1153            let Some((p, binding_index, body_index)) = selected else {
1154                return finally(Err(x), finals, env, k);
1155            };
1156            let catch_form = Form::List(p.clone());
1157            let n = match &p[binding_index] {
1158                Form::Symbol(n) => n.clone(),
1159                _ => return k(Err("catch name must be symbol".into())),
1160            };
1161            let old = env.borrow_mut().insert(n.clone(), caught_error(&x));
1162            coroutine::semantic::record_error(
1163                coroutine::semantic::EvalSemanticRule::ErrorCatch,
1164                &catch_form,
1165                &x,
1166                true,
1167                &env,
1168            );
1169            let e = env.clone();
1170            forms_cps(
1171                Rc::new(p[body_index..].to_vec()),
1172                0,
1173                Value::Nil,
1174                env,
1175                Box::new(move |r| {
1176                    restore(&mut e.borrow_mut(), vec![(n, old)]);
1177                    finally(r, finals, e, k)
1178                }),
1179            )
1180        }
1181        result => finally(result, finals, env, k),
1182    }
1183}
1184
1185fn parse_catch_clause(parts: &[Form]) -> Result<(Option<String>, usize, usize), String> {
1186    match parts {
1187        [_, Form::Symbol(name), _] if name != "Exception" && name != "Throwable" => {
1188            Ok((None, 1, 2))
1189        }
1190        [_, Form::Symbol(name), body, ..]
1191            if name != "Exception"
1192                && name != "Throwable"
1193                && !matches!(body, Form::Symbol(_)) =>
1194        {
1195            Ok((None, 1, 2))
1196        }
1197        [_, Form::Symbol(class), Form::Symbol(_), _, ..] => {
1198            Ok((Some(class.clone()), 2, 3))
1199        }
1200        [_, Form::Keyword(code), Form::Symbol(_), _, ..] if code.contains('/') => {
1201            Ok((Some(format!(":{code}")), 2, 3))
1202        }
1203        [_, Form::Vector(codes), Form::Symbol(_), _, ..]
1204            if !codes.is_empty()
1205                && codes
1206                    .iter()
1207                    .all(|code| matches!(code, Form::Keyword(name) if name.contains('/'))) =>
1208        {
1209            let selectors = codes
1210                .iter()
1211                .map(|code| match code {
1212                    Form::Keyword(name) => format!(":{name}"),
1213                    _ => unreachable!(),
1214                })
1215                .collect::<Vec<_>>()
1216                .join(",");
1217            Ok((Some(format!("[{selectors}]")), 2, 3))
1218        }
1219        _ => Err("catch selector must be a namespaced keyword, a non-empty vector of namespaced keywords, or omitted".into()),
1220    }
1221}
1222fn finally(
1223    result: Result<Value, String>,
1224    v: Vec<Form>,
1225    env: Rc<RefCell<HashMap<String, Value>>>,
1226    k: Cont,
1227) -> Step {
1228    forms_cps(
1229        Rc::new(v),
1230        0,
1231        Value::Nil,
1232        env,
1233        Box::new(move |r| match r {
1234            Err(x) => k(Err(x)),
1235            Ok(_) => k(result),
1236        }),
1237    )
1238}
1239
1240thread_local! {static TEMP:Cell<u64>=const{Cell::new(0)};}
1241fn temp() -> String {
1242    TEMP.with(|x| {
1243        let n = x.get();
1244        x.set(n + 1);
1245        format!("__fiber_{n}")
1246    })
1247}
1248fn application(v: Vec<Form>, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
1249    if let Some(Form::Symbol(name)) = v.first() {
1250        if crate::core::resolve_macro(name).is_some() {
1251            let result = {
1252                let mut environment = env.borrow_mut();
1253                eval(&Form::List(v), &mut environment)
1254            };
1255            return k(result);
1256        }
1257    }
1258
1259    let head_symbol = match &v[0] {
1260        Form::Symbol(name) => Some(name.as_str()),
1261        _ => None,
1262    };
1263    if let Some(name) = head_symbol {
1264        if let Ok(registry) = namespace_registry() {
1265            let mut environment = env.borrow_mut();
1266            if let Err(error) =
1267                ensure_foundation_namespace_for_symbol(&registry, &mut environment, name)
1268            {
1269                return k(Err(error));
1270            }
1271        }
1272    }
1273    let bound = head_symbol.and_then(|name| binding_value(&env.borrow(), name));
1274    if let Some(Value::Function(function)) = bound {
1275        let call_form = Form::List(v.clone());
1276        let call_name = function
1277            .name
1278            .clone()
1279            .unwrap_or_else(|| "<anonymous>".into());
1280        let call_environment = env.clone();
1281        return values_cps(
1282            Rc::new(v[1..].to_vec()),
1283            0,
1284            Vec::new(),
1285            env,
1286            Box::new(move |arguments| match arguments {
1287                Ok(arguments) => {
1288                    coroutine::semantic::record_call(
1289                        &call_form,
1290                        call_name,
1291                        &arguments,
1292                        &call_environment,
1293                    );
1294                    call(function, arguments, k)
1295                }
1296                Err(error) => k(Err(error)),
1297            }),
1298        );
1299    }
1300
1301    if head_symbol.is_some_and(|name| SYNC_SPECIAL_FORMS.contains(&name)) {
1302        return eval_special_form(v, env, k);
1303    }
1304
1305    let forms = Rc::new(v[1..].to_vec());
1306    let arguments_environment = env.clone();
1307    let call_form = Form::List(v.clone());
1308    let function_call_form = call_form.clone();
1309    let function_call_environment = arguments_environment.clone();
1310    let value_call_environment = arguments_environment.clone();
1311    one(
1312        v[0].clone(),
1313        env,
1314        Box::new(move |result| match result {
1315            Ok(Value::Function(function)) => {
1316                let call_name = function
1317                    .name
1318                    .clone()
1319                    .unwrap_or_else(|| "<anonymous>".into());
1320                values_cps(
1321                    forms,
1322                    0,
1323                    Vec::new(),
1324                    arguments_environment,
1325                    Box::new(move |arguments| match arguments {
1326                        Ok(arguments) => {
1327                            coroutine::semantic::record_call(
1328                                &function_call_form,
1329                                call_name,
1330                                &arguments,
1331                                &function_call_environment,
1332                            );
1333                            call(function, arguments, k)
1334                        }
1335                        Err(error) => k(Err(error)),
1336                    }),
1337                )
1338            }
1339            Ok(value) => {
1340                let call_name = crate::core::portable_type_name(&value).to_owned();
1341                values_cps(
1342                    forms,
1343                    0,
1344                    Vec::new(),
1345                    arguments_environment,
1346                    Box::new(move |arguments| match arguments {
1347                        Ok(arguments) => {
1348                            coroutine::semantic::record_call(
1349                                &call_form,
1350                                call_name,
1351                                &arguments,
1352                                &value_call_environment,
1353                            );
1354                            k(crate::core::call_value(value, arguments))
1355                        }
1356                        Err(error) => k(Err(error)),
1357                    }),
1358                )
1359            }
1360            Err(error) => k(Err(error)),
1361        }),
1362    )
1363}
1364
1365fn execution_context(
1366    environment: HashMap<String, Value>,
1367) -> (NamespaceRegistry<Value>, HashMap<String, Value>) {
1368    if let Ok(registry) = namespace_registry() {
1369        return (registry, environment);
1370    }
1371    let (registry, mut runtime_environment) = crate::Runtime::new().standalone_eval_context();
1372    runtime_environment.extend(environment);
1373    (registry, runtime_environment)
1374}
1375
1376fn eval_special_form(v: Vec<Form>, env: Rc<RefCell<HashMap<String, Value>>>, k: Cont) -> Step {
1377    let call_form = Form::List(v.clone());
1378    let op = v[0].clone();
1379    let call_name = match &op {
1380        Form::Symbol(name) => name.clone(),
1381        _ => "<callable>".into(),
1382    };
1383    let e = env.clone();
1384    values_cps(
1385        Rc::new(v[1..].to_vec()),
1386        0,
1387        Vec::new(),
1388        env,
1389        Box::new(move |r| match r {
1390            Ok(values) => {
1391                coroutine::semantic::record_call(&call_form, call_name, &values, &e);
1392                let mut env = e.borrow_mut();
1393                let mut old = Vec::new();
1394                let mut list = vec![op];
1395                for x in values {
1396                    let n = temp();
1397                    let prior = env.insert(n.clone(), x);
1398                    old.push((n.clone(), prior));
1399                    list.push(Form::Symbol(n));
1400                }
1401                let r = eval(&Form::List(list), &mut env);
1402                restore(&mut env, old);
1403                drop(env);
1404                k(r)
1405            }
1406            Err(x) => k(Err(x)),
1407        }),
1408    )
1409}
1410fn call(f: Rc<Function>, args: Vec<Value>, k: Cont) -> Step {
1411    if !f.clauses.is_empty() {
1412        let Some(clause) = select_clause(&f.clauses, args.len()) else {
1413            let name = f.name.clone().unwrap_or_else(|| "<anonymous>".into());
1414            return k(Err(format!(
1415                "{name} has no arity accepting {} arguments",
1416                args.len()
1417            )));
1418        };
1419        return call(clause, args, k);
1420    }
1421    if let Some(fiber_native) = &f.fiber_native {
1422        return fiber_native(args, k);
1423    }
1424    if f.native.is_some() {
1425        return k(crate::core::call_function(&f, args));
1426    }
1427    if f.variadic.is_none() && f.params.len() != args.len() {
1428        if f.namespace.as_deref() == Some("std.foundation") && f.name.as_deref() == Some("type") {
1429            return k(Err("type expects one value".into()));
1430        }
1431        return k(Err(format!(
1432            "function expects {} arguments",
1433            f.params.len()
1434        )));
1435    }
1436    if args.len() < f.params.len() {
1437        return k(Err(format!(
1438            "function expects at least {} arguments",
1439            f.params.len()
1440        )));
1441    }
1442    let tracing = tracing_enabled();
1443    if tracing {
1444        TRACE_STACK.with(|stack| {
1445            stack.borrow_mut().push(trace_frame(
1446                f.name.clone().unwrap_or_else(|| "<anonymous>".into()),
1447                f.namespace.clone(),
1448                current_exception_site(),
1449            ))
1450        });
1451    }
1452    let caller_scoped_foundation = f.namespace.as_deref() == Some("std.foundation")
1453        && (f.is_macro
1454            || matches!(
1455                f.name.as_deref(),
1456                Some(
1457                    "macroexpand"
1458                        | "macroexpand-1"
1459                        | "ns-current"
1460                        | "env-snapshot"
1461                        | "ns-vars"
1462                        | "ns-list"
1463                        | "ns-info"
1464                        | "env-module"
1465                )
1466            ));
1467    let namespace_scope = namespace_registry().ok().and_then(|registry| {
1468        (!caller_scoped_foundation)
1469            .then_some(())
1470            .and_then(|_| f.namespace.as_ref())
1471            .map(|namespace| {
1472                let previous = registry.current().name().as_str().to_owned();
1473                registry.set_current(namespace);
1474                (registry, previous)
1475            })
1476    });
1477    let mut env = f.captured.borrow().clone();
1478    for (n, x) in f.params.iter().zip(args.iter()) {
1479        env.insert(n.clone(), x.clone());
1480    }
1481    let mut bound = Vec::new();
1482    for (pattern, value) in f.patterns.iter().zip(args.iter()) {
1483        if let Err(error) =
1484            crate::core::bind_pattern(pattern, value.clone(), &mut env, &mut bound, None)
1485        {
1486            if let Some((registry, previous)) = namespace_scope {
1487                registry.set_current(&previous);
1488            }
1489            let error = append_trace(error);
1490            if tracing {
1491                TRACE_STACK.with(|stack| {
1492                    stack.borrow_mut().pop();
1493                });
1494            }
1495            return k(Err(format!("function destructuring failed: {error}")));
1496        }
1497    }
1498    if let Some(n) = &f.variadic {
1499        let skip = f.params.len();
1500        let rest = Value::List(args.into_iter().skip(skip).collect());
1501        env.insert(n.clone(), rest.clone());
1502        if let Some(pattern) = &f.variadic_pattern {
1503            if let Err(error) = crate::core::bind_pattern(pattern, rest, &mut env, &mut bound, None)
1504            {
1505                if let Some((registry, previous)) = namespace_scope {
1506                    registry.set_current(&previous);
1507                }
1508                let error = append_trace(error);
1509                if tracing {
1510                    TRACE_STACK.with(|stack| {
1511                        stack.borrow_mut().pop();
1512                    });
1513                }
1514                return k(Err(format!("function destructuring failed: {error}")));
1515            }
1516        }
1517    }
1518    forms_cps(
1519        Rc::new(f.body.clone()),
1520        0,
1521        Value::Nil,
1522        Rc::new(RefCell::new(env)),
1523        Box::new(move |r| match r {
1524            Ok(Value::Recur(_)) => {
1525                if let Some((registry, previous)) = namespace_scope {
1526                    registry.set_current(&previous);
1527                }
1528                let result = append_trace("recur must be inside loop".into());
1529                if tracing {
1530                    TRACE_STACK.with(|stack| {
1531                        stack.borrow_mut().pop();
1532                    });
1533                }
1534                k(Err(result))
1535            }
1536            r => {
1537                if let Some((registry, previous)) = namespace_scope {
1538                    registry.set_current(&previous);
1539                }
1540                let r = r.map_err(append_trace);
1541                if tracing {
1542                    TRACE_STACK.with(|stack| {
1543                        stack.borrow_mut().pop();
1544                    });
1545                }
1546                k(r)
1547            }
1548        }),
1549    )
1550}
1551
1552pub(crate) fn invoke_function_sync(
1553    function: Rc<Function>,
1554    arguments: Vec<Value>,
1555) -> Result<Value, String> {
1556    let (namespace_registry, environment) = execution_context(HashMap::new());
1557    let env = Rc::new(RefCell::new(environment));
1558    let mut fiber = EvalFiber {
1559        env,
1560        namespace_registry,
1561        pending: None,
1562        resume: None,
1563        state: EvalFiberState::Running,
1564    };
1565    let step = with_namespace_registry(&fiber.namespace_registry, || {
1566        call(function, arguments, Box::new(Step::Done))
1567    });
1568    fiber.accept(step);
1569    fiber.drive_sync()
1570}
1571
1572#[cfg(test)]
1573mod tests {
1574    use super::*;
1575    use std::cell::Cell;
1576
1577    #[test]
1578    fn def_returns_the_qualified_var() {
1579        let registry = crate::kernel::NamespaceRegistry::new("user");
1580        crate::core::with_namespace_registry(&registry, || {
1581            let mut fiber = EvalFiber::start("(def player 1)", HashMap::new()).unwrap();
1582            let Value::Var(var) = fiber.drive_sync().unwrap() else {
1583                panic!("def must return a Var")
1584            };
1585            assert_eq!(var.display(), "#'user/player");
1586            assert_eq!(var.deref_value(), Value::Number(1));
1587        });
1588    }
1589
1590    #[test]
1591    fn fallback_def_takes_ownership_from_a_bootstrap_library_var() {
1592        let registry = crate::kernel::NamespaceRegistry::new("user");
1593        crate::core::with_namespace_registry(&registry, || {
1594            let seed = registry.current().intern_with_origin(
1595                "optimized",
1596                Value::Number(7),
1597                crate::kernel::VarOrigin::RustLibrary,
1598            );
1599            let mut environment = HashMap::new();
1600            environment.insert("optimized".into(), Value::Var(seed.clone()));
1601
1602            let result =
1603                crate::core::with_definition_origin(crate::kernel::VarOrigin::HalFallback, || {
1604                    let mut fiber = EvalFiber::start("(def optimized 9)", environment).unwrap();
1605                    fiber.drive_sync().unwrap()
1606                });
1607            let Value::Var(var) = result else {
1608                panic!("def must return a Var")
1609            };
1610            assert!(seed.same_identity(&var));
1611            assert_eq!(var.origin(), crate::kernel::VarOrigin::HalFallback);
1612            assert_eq!(var.deref_value(), Value::Number(9));
1613        });
1614    }
1615
1616    #[test]
1617    fn named_value_constructors_are_visible_to_later_forms_in_the_same_do() {
1618        let cases = [
1619            (
1620                "(do (defstruct Point [x y]) \
1621                 (+ (get (Point 1 2) :x) \
1622                    (get (->Point 3 4) :x) \
1623                    (get (map->Point {:x 5}) :x)))",
1624                Value::Number(9),
1625            ),
1626            (
1627                "(do (defmutable Cursor [x y]) \
1628                 (+ (field (Cursor 1 2) :x) \
1629                    (field (->Cursor 3 4) :x) \
1630                    (field (map->Cursor {:x 5}) :x)))",
1631                Value::Number(9),
1632            ),
1633        ];
1634        for (source, expected) in cases {
1635            let mut fiber = EvalFiber::start(source, HashMap::new()).unwrap();
1636            assert_eq!(fiber.drive_sync(), Ok(expected));
1637        }
1638    }
1639
1640    #[test]
1641    fn mutable_field_set_place_updates_and_returns_replacement() {
1642        let mut fiber = EvalFiber::start(
1643            "(do (defmutable Cursor [x y]) \
1644             (def cursor (Cursor 1 2)) \
1645             (if (= (set! (field cursor :x) 42) 42) \
1646               (field cursor :x) \
1647               -1))",
1648            HashMap::new(),
1649        )
1650        .unwrap();
1651        assert_eq!(fiber.drive_sync(), Ok(Value::Number(42)));
1652    }
1653
1654    #[test]
1655    fn mutable_field_set_place_resumes_after_replacement_suspends() {
1656        let promise = Promise::new();
1657        let mut environment = HashMap::new();
1658        environment.insert("replacement".into(), Value::Promise(promise.clone()));
1659        let mut fiber = EvalFiber::start(
1660            "(do (defmutable Cursor [x]) \
1661             (def cursor (Cursor 1)) \
1662             (set! (field cursor :x) (deref replacement)) \
1663             (field cursor :x))",
1664            environment,
1665        )
1666        .unwrap();
1667        assert_eq!(fiber.state(), EvalFiberState::Suspended);
1668        promise.resolve(Value::Number(42));
1669        assert_eq!(
1670            fiber.resume(promise.state()),
1671            EvalFiberState::Completed(Value::Number(42))
1672        );
1673    }
1674
1675    #[test]
1676    fn mutable_field_set_place_resumes_receiver_before_evaluating_replacement() {
1677        let ready = Promise::new();
1678        let mut environment = HashMap::new();
1679        environment.insert("ready".into(), Value::Promise(ready.clone()));
1680        let mut fiber = EvalFiber::start(
1681            "(do (def order []) \
1682             (defmutable Cursor [x]) \
1683             (def cursor (Cursor 1)) \
1684             (set! (field (do (deref ready) cursor) :x) \
1685                   (do (set! order (conj order :replacement)) 42)) \
1686             [order (field cursor :x)])",
1687            environment,
1688        )
1689        .unwrap();
1690        assert_eq!(fiber.state(), EvalFiberState::Suspended);
1691        ready.resolve(Value::Bool(true));
1692        assert_eq!(
1693            fiber.resume(ready.state()),
1694            EvalFiberState::Completed(Value::Vector(
1695                [
1696                    Value::Vector([Value::Keyword("replacement".into())].into_iter().collect()),
1697                    Value::Number(42),
1698                ]
1699                .into_iter()
1700                .collect(),
1701            ))
1702        );
1703    }
1704
1705    #[test]
1706    fn anonymous_namespace_form_is_a_session_local_noop() {
1707        let registry = crate::kernel::NamespaceRegistry::new("user");
1708        crate::core::with_namespace_registry(&registry, || {
1709            let mut fiber = EvalFiber::start("(ns+)", HashMap::new()).unwrap();
1710            assert_eq!(fiber.drive_sync(), Ok(Value::Nil));
1711            assert_eq!(registry.current().name().as_str(), "user");
1712        });
1713    }
1714
1715    #[test]
1716    fn resumes_nested() {
1717        let p = Promise::new();
1718        let mut e = HashMap::new();
1719        e.insert("p".into(), Value::Promise(p.clone()));
1720        let mut f = EvalFiber::start("(let [x 1] (+ x (deref p)))", e).unwrap();
1721        assert_eq!(f.state(), EvalFiberState::Suspended);
1722        p.resolve(Value::Number(41));
1723        assert_eq!(
1724            f.resume(p.state()),
1725            EvalFiberState::Completed(Value::Number(42))
1726        );
1727    }
1728
1729    #[test]
1730    fn drive_sync_waits_for_a_deferred_promise() {
1731        let mut fiber =
1732            EvalFiber::start("(deref (promise/delay 1 (fn [] 42)))", HashMap::new()).unwrap();
1733        assert_eq!(fiber.drive_sync(), Ok(Value::Number(42)));
1734    }
1735
1736    #[test]
1737    fn cancelling_a_suspended_fiber_notifies_its_pending_promise() {
1738        let promise = Promise::new();
1739        let cancelled = Rc::new(Cell::new(false));
1740        let observed = cancelled.clone();
1741        promise.set_cancel_hook(Rc::new(move || observed.set(true)));
1742        let mut environment = HashMap::new();
1743        environment.insert("p".into(), Value::Promise(promise));
1744        let mut fiber = EvalFiber::start("(deref p)", environment).unwrap();
1745        assert_eq!(fiber.state(), EvalFiberState::Suspended);
1746        assert!(fiber.cancel());
1747        assert!(cancelled.get());
1748        assert_eq!(fiber.state(), EvalFiberState::Cancelled);
1749    }
1750    #[test]
1751    fn resumes_function_finally() {
1752        let p = Promise::new();
1753        let mut e = HashMap::new();
1754        e.insert("p".into(), Value::Promise(p.clone()));
1755        let mut f = EvalFiber::start(
1756            "(do (def f (fn [x] (try (+ x (deref p)) (finally nil)))) (f 2))",
1757            e,
1758        )
1759        .unwrap();
1760        assert_eq!(f.state(), EvalFiberState::Suspended);
1761        p.resolve(Value::Number(40));
1762        assert_eq!(
1763            f.resume(p.state()),
1764            EvalFiberState::Completed(Value::Number(42))
1765        );
1766    }
1767    #[test]
1768    fn resumes_multi_arity_dispatch() {
1769        let p = Promise::new();
1770        let mut e = HashMap::new();
1771        e.insert("p".into(), Value::Promise(p.clone()));
1772        let mut f = EvalFiber::start(
1773            "(do (defn g ([x] (+ x 1)) ([x y] (+ x y (deref p)))) (g 1 2))",
1774            e,
1775        )
1776        .unwrap();
1777        assert_eq!(f.state(), EvalFiberState::Suspended);
1778        p.resolve(Value::Number(39));
1779        assert_eq!(
1780            f.resume(p.state()),
1781            EvalFiberState::Completed(Value::Number(42))
1782        );
1783        let mut f = EvalFiber::start(
1784            "(do (defn h ([x] (+ x 1)) ([x y] (+ x y))) (h 41))",
1785            HashMap::new(),
1786        )
1787        .unwrap();
1788        assert_eq!(f.state(), EvalFiberState::Completed(Value::Number(42)));
1789    }
1790
1791    #[test]
1792    fn computed_function_head_can_suspend() {
1793        let promise = Promise::new();
1794        let mut environment = HashMap::new();
1795        environment.insert("p".into(), Value::Promise(promise.clone()));
1796        let mut fiber = EvalFiber::start(
1797            "(do (def entry [:task (fn [] (std.native.Coroutine/await p))]) \
1798             ((nth entry 1)))",
1799            environment,
1800        )
1801        .unwrap();
1802        assert_eq!(fiber.state(), EvalFiberState::Suspended);
1803        promise.resolve(Value::Number(42));
1804        assert_eq!(
1805            fiber.resume(promise.state()),
1806            EvalFiberState::Completed(Value::Number(42))
1807        );
1808    }
1809
1810    #[test]
1811    fn logical_forms_short_circuit_without_evaluating_later_branches() {
1812        let cases = [
1813            ("(cond true 42 :else (count :invalid))", Value::Number(42)),
1814            ("(and false (count :invalid))", Value::Bool(false)),
1815            ("(or 42 (count :invalid))", Value::Number(42)),
1816        ];
1817        for (source, expected) in cases {
1818            let fiber = EvalFiber::start(source, HashMap::new()).unwrap();
1819            assert_eq!(fiber.state(), EvalFiberState::Completed(expected));
1820        }
1821    }
1822
1823    #[test]
1824    fn numeric_and_boolean_predicates_match_foundation_types() {
1825        let cases = [
1826            ("(long? 42)", Value::Bool(true)),
1827            ("(bigint? 9223372036854775808)", Value::Bool(true)),
1828            ("(integer? 9223372036854775808)", Value::Bool(true)),
1829            ("(integer? 1.0)", Value::Bool(false)),
1830            ("(double? 42.0)", Value::Bool(true)),
1831            ("(number? 42)", Value::Bool(true)),
1832            ("(boolean? false)", Value::Bool(true)),
1833            ("(boolean? nil)", Value::Bool(false)),
1834        ];
1835        for (source, expected) in cases {
1836            let fiber = EvalFiber::start(source, HashMap::new()).unwrap();
1837            assert_eq!(fiber.state(), EvalFiberState::Completed(expected));
1838        }
1839    }
1840
1841    #[test]
1842    fn character_predicate_matches_foundation_types() {
1843        let cases = [
1844            ("(char? \\x)", Value::Bool(true)),
1845            ("(char? \"x\")", Value::Bool(false)),
1846        ];
1847        for (source, expected) in cases {
1848            let fiber = EvalFiber::start(source, HashMap::new()).unwrap();
1849            assert_eq!(fiber.state(), EvalFiberState::Completed(expected));
1850        }
1851    }
1852
1853    #[test]
1854    fn loop_recur_trampolines_large_iteration_counts() {
1855        let mut fiber = EvalFiber::start(
1856            "(loop [i 0] (if (< i 50000) (recur (inc i)) i))",
1857            HashMap::new(),
1858        )
1859        .unwrap();
1860        assert_eq!(fiber.drive_sync(), Ok(Value::Number(50000)));
1861    }
1862}