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
10const 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
47pub(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 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(®istry, &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(®istry, || {
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(®istry, || {
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(®istry, || {
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}