1use super::host;
2use super::{code, rc_exp, rc_val, Env, EnvChunk, Exp, Prim1, Prim2, RcExp, RcVal, Shared, Val};
3use std::collections::HashSet;
4
5type FunTable = Shared<Vec<(FunKey, usize)>>;
8
9#[derive(Clone)]
10struct FunKey {
11 env: Env,
12 body: RcExp,
13}
14
15fn env_equal(a: &Env, b: &Env) -> bool {
18 Env::ptr_eq(a, b) || (a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x == y))
19}
20
21#[derive(Debug, PartialEq)]
24pub enum Fault {
25 Throw(Val),
26 Bug(String),
27}
28
29impl std::fmt::Display for Fault {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 Fault::Throw(v) => write!(f, "{v}"),
33 Fault::Bug(s) => write!(f, "bug: {s}"),
34 }
35 }
36}
37
38pub fn throw(tag: &str, detail: Val) -> Fault {
39 Fault::Throw(Val::Pair(rc_val(Val::Sym(tag.into())), rc_val(detail)))
40}
41
42fn wrong_type(op: &str) -> Fault {
43 throw("wrong-type", Val::Sym(op.into()))
44}
45
46fn as_syntax(v: &Val) -> Option<RcExp> {
50 match v {
51 Val::Code(e) => Some(RcExp::clone(e)),
52 Val::Num(n) => Some(rc_exp(Exp::Lit(*n))),
53 Val::Flo(x) => Some(rc_exp(Exp::Flo(*x))),
54 Val::Sym(s) => Some(rc_exp(Exp::Sym(s.clone()))),
55 Val::Atom(a) => Some(rc_exp(Exp::Atom(a.clone()))),
56 Val::Nil => Some(rc_exp(Exp::Nil)),
57 _ => None,
58 }
59}
60
61fn kind_of(v: &Val) -> &'static str {
62 match v {
63 Val::Num(_) => "number",
64 Val::Flo(_) => "float",
65 Val::Sym(_) => "symbol",
66 Val::Atom(_) => "atom",
67 Val::Nil => "nil",
68 Val::Pair(_, _) => "pair",
69 Val::Clo(_, _) => "closure",
70 Val::Code(_) => "code",
71 Val::Cell(_) => "cell",
72 Val::Raise(_) => "raise",
73 }
74}
75
76fn has_holes<M: Mail>(v: &Val, h: &Store<M>) -> bool {
82 let mut vals: HashSet<*const Val> = HashSet::new();
83 let mut envs: HashSet<*const EnvChunk> = HashSet::new();
84 let mut work = vec![Val::clone(v)];
85 while let Some(x) = work.pop() {
86 match x {
87 Val::Code(_) => return true,
88 Val::Pair(a, b) => {
89 for c in [a, b] {
90 if vals.insert(&*c as *const Val) {
91 work.push(Val::clone(&c));
92 }
93 }
94 }
95 Val::Raise(a) => {
96 if vals.insert(&*a as *const Val) {
97 work.push(Val::clone(&a));
98 }
99 }
100 Val::Cell(i) => work.push(h.cells[i].clone()),
103 Val::Clo(env, _) => {
104 let mut cur = Some(env);
105 while let Some(e) = cur {
106 if !envs.insert(Shared::as_ptr(&e.0)) {
107 break;
108 }
109 work.extend(e.0.vals.iter().cloned());
110 cur = e.0.parent.clone();
111 }
112 }
113 _ => {}
114 }
115 }
116 false
117}
118
119fn cons_syntax<M: Mail>(v: &Val, refusal: &'static str, h: &mut Store<M>) -> Result<Exp, Fault> {
124 let mut work: Vec<Option<&Val>> = vec![Some(v)];
126 let mut done: Vec<RcExp> = Vec::new();
127 while let Some(step) = work.pop() {
128 match step {
129 Some(Val::Pair(a, b)) => {
130 work.push(None);
131 work.push(Some(b));
132 work.push(Some(a));
133 }
134 Some(leaf) => done.push(
135 as_syntax(leaf).ok_or_else(|| throw(refusal, Val::Sym(kind_of(leaf).into())))?,
136 ),
137 None => {
138 let cdr = done.pop().expect("cdr");
139 let car = done.pop().expect("car");
140 let named = h.reflect(Exp::Prim2(Prim2::Cons, car, cdr));
141 done.push(rc_exp(named));
142 }
143 }
144 }
145 Ok(RcExp::unwrap_or_clone(done.pop().expect("one result")))
146}
147
148fn staged_operands(vs: &[Val], op: &str) -> Option<Result<Vec<RcExp>, Fault>> {
151 if !vs.iter().any(|v| matches!(v, Val::Code(_))) {
152 return None;
153 }
154 Some(
155 vs.iter()
156 .map(|v| as_syntax(v).ok_or_else(|| wrong_type(op)))
157 .collect(),
158 )
159}
160
161pub trait Mail: Send {
164 fn spawn(&mut self, thunk: Val) -> Result<Val, Val>;
165 fn send(&mut self, addr: &Val, msg: Val) -> Result<Val, Val>;
166 fn receive(&mut self) -> Option<Val>;
169 fn monitor(&mut self, addr: &Val) -> Result<Val, Val>;
170 fn limit(&mut self, addr: &Val, turns: i64) -> Result<Val, Val>;
171}
172
173#[derive(Default)]
176pub struct NoMail;
177
178impl Mail for NoMail {
179 fn spawn(&mut self, _: Val) -> Result<Val, Val> {
180 Err(Val::Sym("no-scheduler".into()))
181 }
182 fn send(&mut self, _: &Val, _: Val) -> Result<Val, Val> {
183 Err(Val::Sym("no-scheduler".into()))
184 }
185 fn receive(&mut self) -> Option<Val> {
186 None
187 }
188 fn monitor(&mut self, _: &Val) -> Result<Val, Val> {
189 Err(Val::Sym("no-scheduler".into()))
190 }
191 fn limit(&mut self, _: &Val, _: i64) -> Result<Val, Val> {
192 Err(Val::Sym("no-scheduler".into()))
193 }
194}
195
196pub struct Store<M: Mail = NoMail> {
201 pub fresh: usize,
202 pub block: Vec<Exp>,
205 fun: FunTable,
206 lams: Shared<Vec<usize>>,
209 pub level: usize,
210 pub cells: Vec<Val>,
212 pub mail: M,
213}
214
215impl<M: Mail + Default> Default for Store<M> {
216 fn default() -> Self {
217 Store::new(M::default())
218 }
219}
220
221impl<M: Mail> Store<M> {
222 pub fn new(mail: M) -> Store<M> {
223 Store {
224 fresh: 0,
225 block: Vec::new(),
226 fun: Shared::new(Vec::new()),
227 lams: Shared::new(Vec::new()),
228 level: 0,
229 cells: Vec::new(),
230 mail,
231 }
232 }
233
234 pub fn fresh_var(&mut self) -> usize {
235 let v = self.fresh;
236 self.fresh += 1;
237 v
238 }
239
240 fn find_fun(&self, env: &Env, body: &RcExp) -> Option<usize> {
241 self.fun.iter().find_map(|(k, level)| {
244 let same_body = RcExp::ptr_eq(&k.body, body) || *k.body == **body;
245 (same_body && env_equal(&k.env, env)).then_some(*level)
246 })
247 }
248
249 fn register_fun(&mut self, level: usize, env: &Env, body: &RcExp) {
250 Shared::make_mut(&mut self.fun).push((
251 FunKey {
252 env: env.clone(),
253 body: RcExp::clone(body),
254 },
255 level,
256 ));
257 }
258
259 fn register_lam(&mut self, level: usize) {
263 Shared::make_mut(&mut self.lams).push(level);
264 }
265
266 fn is_lam(&self, e: &Exp) -> bool {
267 matches!(e, Exp::Var(n) if self.lams.contains(n))
268 }
269
270 pub fn reflect(&mut self, e: Exp) -> Exp {
272 self.block.push(e);
273 Exp::Var(self.fresh_var())
274 }
275
276 pub fn reflectc(&mut self, e: Exp) -> Val {
277 code(self.reflect(e))
278 }
279}
280
281pub struct Scope {
283 fresh: usize,
284 block: Vec<Exp>,
285 fun: FunTable,
286 lams: Shared<Vec<usize>>,
287}
288
289impl Scope {
290 fn save<M: Mail>(h: &mut Store<M>) -> Scope {
293 Scope {
294 fresh: h.fresh,
295 block: std::mem::take(&mut h.block),
296 fun: Shared::clone(&h.fun),
299 lams: Shared::clone(&h.lams),
300 }
301 }
302
303 fn restore<M: Mail>(self, h: &mut Store<M>) {
306 h.fresh = self.fresh;
307 h.block = self.block;
308 h.fun = self.fun;
309 h.lams = self.lams;
310 }
311}
312
313pub fn drain(stmts: Vec<Exp>, tail: Exp) -> Exp {
316 stmts
317 .into_iter()
318 .rev()
319 .fold(tail, |acc, stmt| Exp::Let(rc_exp(stmt), rc_exp(acc)))
320}
321
322#[derive(Debug, Clone, Copy, PartialEq, Eq)]
324pub enum ForceMode {
325 Lift,
327 Scalar,
331 Strict,
334}
335
336pub enum Reify {
338 IfTrue { c: RcExp, env: Env, f: RcExp },
339 IfFalse { c: RcExp, t: RcExp },
340 RunStaged { b: RcExp },
341 RunNowInner { env: Env },
342 LiftRefDone { s1: RcExp },
343 CatchDone,
344 Produce,
345}
346
347pub enum Then {
349 Drain {
351 saved: Scope,
352 then: Reify,
353 },
354 WrapAsCode,
355 IsCodeStaged {
356 s1: RcExp,
357 },
358}
359
360pub enum Mode {
361 Eval { env: Env, exp: RcExp },
362 Apply { val: Val },
363}
364
365pub enum Cont {
366 Prim1Finish {
367 op: Prim1,
368 },
369 Prim2Right {
370 env: Env,
371 op: Prim2,
372 e2: RcExp,
373 },
374 Prim2Finish {
375 op: Prim2,
376 v1: Val,
377 },
378 AppArgs {
383 env: Env,
384 args: Box<[RcExp]>,
385 done: Vec<Val>,
386 },
387 ApplyArgs {
388 env: Env,
389 args: RcExp,
390 },
391 ApplyFinish {
392 f: Val,
393 },
394 LiftFunClo {
395 env: Env,
396 f: RcExp,
397 },
398 LiftFunGo {
399 arity: u16,
400 },
401 OpArgs {
402 idx: u16,
403 env: Env,
404 args: Vec<RcExp>,
405 next: usize,
406 done: Vec<Val>,
407 },
408 IfDispatch {
409 env: Env,
410 then_: RcExp,
411 else_: RcExp,
412 },
413 LetBody {
414 env: Env,
415 body: RcExp,
416 },
417 CatchExit {
420 saved: Scope,
421 },
422 ThrowFinish,
423
424 LiftFinish,
426 ForceCode {
429 mode: ForceMode,
430 then: Then,
431 },
432 LiftCloFinish {
433 arity: u16,
434 then: Then,
435 },
436 ReifyVExit {
439 saved: Scope,
440 },
441 RunNowExit {
442 saved_level: usize,
443 },
444 LiftRefDispatch {
445 env: Env,
446 e2: RcExp,
447 },
448 LiftRefPersist,
449 RunDispatch {
450 env: Env,
451 e: RcExp,
452 },
453 IsCodeRight {
454 env: Env,
455 e2: RcExp,
456 },
457 IsCodeFinish {
458 v1: Val,
459 },
460 EvalmsRight {
461 env: Env,
462 e2: RcExp,
463 },
464 EvalmsFinish {
465 env_val: Val,
466 },
467}
468
469pub struct Machine {
470 mode: Mode,
471 kont: Vec<Cont>,
472}
473
474pub enum Step {
475 Running,
476 Blocked,
479 Done(Val),
480}
481
482impl Machine {
483 pub fn new(env: Env, exp: RcExp) -> Machine {
484 Machine {
485 mode: Mode::Eval { env, exp },
486 kont: Vec::new(),
487 }
488 }
489
490 pub fn applying(f: Val, arg: Val) -> Machine {
494 let call = Exp::App(
495 rc_exp(Exp::Proc(rc_val(f))),
496 Box::new([rc_exp(Exp::Proc(rc_val(arg)))]),
497 );
498 Machine::new(Env::default(), rc_exp(call))
499 }
500
501 pub fn step<M: Mail>(&mut self, h: &mut Store<M>) -> Result<Step, Fault> {
502 if let (Mode::Apply { val }, Some(Cont::Prim1Finish { op: Prim1::Receive })) =
506 (&self.mode, self.kont.last())
507 {
508 if !matches!(val, Val::Code(_)) {
509 match h.mail.receive() {
510 Some(msg) => {
511 self.kont.pop();
512 self.mode = Mode::Apply { val: msg };
513 return Ok(Step::Running);
514 }
515 None => return Ok(Step::Blocked),
516 }
517 }
518 }
519
520 if let Mode::Apply { val } = &self.mode {
521 if self.kont.is_empty() {
522 return Ok(Step::Done(val.clone()));
523 }
524 let top = self.kont.last().expect("checked non-empty");
525 if matches!(val, Val::Raise(_)) && !receives(top) {
526 self.propagate(h);
527 return Ok(Step::Running);
528 }
529 }
530
531 let mode = std::mem::replace(&mut self.mode, Mode::Apply { val: Val::Nil });
532 let next = match mode {
533 Mode::Eval { env, exp } => self.eval(env, exp, h),
534 Mode::Apply { val } => {
535 let k = self.kont.pop().expect("checked non-empty");
536 self.resume(k, val, h)
537 }
538 };
539
540 match next {
541 Ok(mode) => {
542 self.mode = mode;
543 Ok(Step::Running)
544 }
545 Err(Fault::Throw(v)) => {
546 self.mode = Mode::Apply {
547 val: super::raise(v),
548 };
549 Ok(Step::Running)
550 }
551 Err(bug) => Err(bug),
552 }
553 }
554
555 fn propagate<M: Mail>(&mut self, h: &mut Store<M>) {
558 match self.kont.pop().expect("checked non-empty") {
559 Cont::CatchExit { saved } => {
561 saved.restore(h);
562 if let Mode::Apply { val: Val::Raise(v) } = &self.mode {
563 self.mode = Mode::Apply { val: Val::clone(v) };
564 }
565 }
566 Cont::ReifyVExit { saved }
567 | Cont::ForceCode {
568 then: Then::Drain { saved, .. },
569 ..
570 } => saved.restore(h),
571 Cont::RunNowExit { saved_level } => h.level = saved_level,
572 _ => {}
573 }
574 }
575
576 pub fn run<M: Mail>(mut self, h: &mut Store<M>) -> Result<Val, Fault> {
577 loop {
578 match self.step(h)? {
579 Step::Running => {}
580 Step::Done(v) => return Ok(v),
581 Step::Blocked => return Err(throw("blocked", Val::Sym("no-scheduler".into()))),
582 }
583 }
584 }
585
586 pub fn turn<M: Mail>(
589 &mut self,
590 h: &mut Store<M>,
591 budget: usize,
592 ) -> Result<(Step, usize), Fault> {
593 for spent in 0..budget {
594 match self.step(h)? {
595 Step::Running => {}
596 other => return Ok((other, spent + 1)),
597 }
598 }
599 Ok((Step::Running, budget))
600 }
601
602 fn direct(exp: &RcExp, env: &Env) -> Option<Val> {
605 let v = match &**exp {
606 Exp::Lit(n) => Val::Num(*n),
607 Exp::Flo(x) => Val::Flo(*x),
608 Exp::Sym(s) => Val::Sym(s.clone()),
609 Exp::Atom(a) => Val::Atom(a.clone()),
610 Exp::Nil => Val::Nil,
611 Exp::Proc(v) => Val::clone(v),
612 Exp::Var(i) => env.get(*i)?.clone(),
614 Exp::Lam(_, _) => Val::Clo(env.clone(), RcExp::clone(exp)),
615 _ => return None,
616 };
617 (!matches!(v, Val::Raise(_))).then_some(v)
618 }
619
620 fn direct_prim<M: Mail>(
623 exp: &RcExp,
624 env: &Env,
625 h: &mut Store<M>,
626 ) -> Option<Result<Val, Fault>> {
627 Some(match &**exp {
628 Exp::Prim1(op, e) if !matches!(op, Prim1::Receive) => {
629 prim1(*op, Machine::direct(e, env)?, h)
630 }
631 Exp::Prim2(op, a, b) => {
632 let x = Machine::direct(a, env)?;
633 let y = Machine::direct(b, env)?;
634 prim2(*op, x, y, h)
635 }
636 _ => return None,
637 })
638 }
639
640 fn eval<M: Mail>(&mut self, env: Env, exp: RcExp, h: &mut Store<M>) -> Result<Mode, Fault> {
641 let val = match &*exp {
642 Exp::Lit(n) => Val::Num(*n),
643 Exp::Flo(x) => Val::Flo(*x),
644 Exp::Sym(s) => Val::Sym(s.clone()),
645 Exp::Atom(a) => Val::Atom(a.clone()),
646 Exp::Nil => Val::Nil,
647 Exp::Proc(v) => Val::clone(v),
648
649 Exp::Var(i) => match env.get(*i) {
650 Some(v) => v.clone(),
651 None => return Err(throw("unbound", Val::Num(*i as i64))),
652 },
653
654 Exp::Lam(_, _) => Val::Clo(env, RcExp::clone(&exp)),
657
658 Exp::Prim1(op, e) => {
661 if !matches!(op, Prim1::Receive) {
662 if let Some(v) = Machine::direct(e, &env) {
663 return Ok(Mode::Apply {
664 val: prim1(*op, v, h)?,
665 });
666 }
667 }
668 self.kont.push(Cont::Prim1Finish { op: *op });
669 return Ok(Mode::Eval {
670 env,
671 exp: RcExp::clone(e),
672 });
673 }
674
675 Exp::Prim2(op, a, b) => {
676 if let Some(x) = Machine::direct(a, &env) {
677 return Ok(match Machine::direct(b, &env) {
678 Some(y) => Mode::Apply {
679 val: prim2(*op, x, y, h)?,
680 },
681 None => {
682 self.kont.push(Cont::Prim2Finish { op: *op, v1: x });
683 Mode::Eval {
684 env,
685 exp: RcExp::clone(b),
686 }
687 }
688 });
689 }
690 self.kont.push(Cont::Prim2Right {
691 env: env.clone(),
692 op: *op,
693 e2: RcExp::clone(b),
694 });
695 return Ok(Mode::Eval {
696 env,
697 exp: RcExp::clone(a),
698 });
699 }
700
701 Exp::App(f, args) => {
704 let mut done = Vec::with_capacity(args.len() + 1);
705 match Machine::direct(f, &env) {
706 Some(fv) => done.push(fv),
707 None => {
708 self.kont.push(Cont::AppArgs {
709 env: env.clone(),
710 args: args.clone(),
711 done,
712 });
713 return Ok(Mode::Eval {
714 env,
715 exp: RcExp::clone(f),
716 });
717 }
718 }
719 while let Some(a) = args.get(done.len() - 1) {
722 match Machine::direct(a, &env) {
723 Some(v) => done.push(v),
724 None => match Machine::direct_prim(a, &env, h) {
725 Some(Ok(v)) => done.push(v),
726 Some(Err(fault)) => {
727 self.kont.push(Cont::AppArgs {
728 env,
729 args: args.clone(),
730 done,
731 });
732 return Err(fault);
733 }
734 None => break,
735 },
736 }
737 }
738 if done.len() == args.len() + 1 {
739 return self.enter(done, h);
740 }
741 let exp = RcExp::clone(&args[done.len() - 1]);
742 self.kont.push(Cont::AppArgs {
743 env: env.clone(),
744 args: args.clone(),
745 done,
746 });
747 return Ok(Mode::Eval { env, exp });
748 }
749
750 Exp::Apply(f, args) => {
753 self.kont.push(Cont::ApplyArgs {
754 env: env.clone(),
755 args: RcExp::clone(args),
756 });
757 return Ok(Mode::Eval {
758 env,
759 exp: RcExp::clone(f),
760 });
761 }
762
763 Exp::Op(idx, args) => {
764 let mut done = Vec::with_capacity(args.len());
765 while let Some(v) = args.get(done.len()).and_then(|e| Machine::direct(e, &env)) {
766 done.push(v);
767 }
768 if done.len() == args.len() {
769 return self.run_op(*idx, done, h);
770 }
771 let exp = RcExp::clone(&args[done.len()]);
772 self.kont.push(Cont::OpArgs {
773 idx: *idx,
774 env: env.clone(),
775 args: args.clone(),
776 next: done.len() + 1,
777 done,
778 });
779 return Ok(Mode::Eval { env, exp });
780 }
781
782 Exp::If(c, t, e) => {
785 if let Some(v) = Machine::direct(c, &env) {
786 if !matches!(v, Val::Code(_)) {
787 return Ok(Mode::Eval {
788 env,
789 exp: match v {
790 Val::Num(0) | Val::Nil => RcExp::clone(e),
791 _ => RcExp::clone(t),
792 },
793 });
794 }
795 self.kont.push(Cont::IfDispatch {
796 env: env.clone(),
797 then_: RcExp::clone(t),
798 else_: RcExp::clone(e),
799 });
800 return Ok(Mode::Apply { val: v });
801 }
802 self.kont.push(Cont::IfDispatch {
803 env: env.clone(),
804 then_: RcExp::clone(t),
805 else_: RcExp::clone(e),
806 });
807 return Ok(Mode::Eval {
808 env,
809 exp: RcExp::clone(c),
810 });
811 }
812
813 Exp::Let(init, body) => {
815 let bound = match Machine::direct(init, &env) {
816 Some(v) => Some(v),
817 None => match Machine::direct_prim(init, &env, h) {
818 Some(Ok(v)) => Some(v),
819 Some(Err(f)) => {
822 self.kont.push(Cont::LetBody {
823 env,
824 body: RcExp::clone(body),
825 });
826 return Err(f);
827 }
828 None => None,
829 },
830 };
831 if let Some(v) = bound {
832 return Ok(Mode::Eval {
833 env: env.push_owned(v),
834 exp: RcExp::clone(body),
835 });
836 }
837 self.kont.push(Cont::LetBody {
838 env: env.clone(),
839 body: RcExp::clone(body),
840 });
841 return Ok(Mode::Eval {
842 env,
843 exp: RcExp::clone(init),
844 });
845 }
846
847 Exp::Catch(body) => {
848 let saved = Scope::save(h);
849 self.kont.push(Cont::CatchExit { saved });
850 return Ok(Mode::Eval {
851 env,
852 exp: RcExp::clone(body),
853 });
854 }
855
856 Exp::Throw(e) => {
857 self.kont.push(Cont::ThrowFinish);
858 return Ok(Mode::Eval {
859 env,
860 exp: RcExp::clone(e),
861 });
862 }
863
864 Exp::Lift(e) => {
865 self.kont.push(Cont::LiftFinish);
866 return Ok(Mode::Eval {
867 env,
868 exp: RcExp::clone(e),
869 });
870 }
871
872 Exp::LiftFun(n, f) => {
873 self.kont.push(Cont::LiftFunClo {
874 env: env.clone(),
875 f: RcExp::clone(f),
876 });
877 return Ok(Mode::Eval {
878 env,
879 exp: RcExp::clone(n),
880 });
881 }
882
883 Exp::LiftRef(a, b) => {
887 self.kont.push(Cont::LiftRefDispatch {
888 env: env.clone(),
889 e2: RcExp::clone(b),
890 });
891 return Ok(Mode::Eval {
892 env,
893 exp: RcExp::clone(a),
894 });
895 }
896
897 Exp::Run(b, e) => {
898 self.kont.push(Cont::RunDispatch {
899 env: env.clone(),
900 e: RcExp::clone(e),
901 });
902 return Ok(Mode::Eval {
903 env,
904 exp: RcExp::clone(b),
905 });
906 }
907
908 Exp::IsCode(a, b) => {
909 self.kont.push(Cont::IsCodeRight {
910 env: env.clone(),
911 e2: RcExp::clone(b),
912 });
913 return Ok(Mode::Eval {
914 env,
915 exp: RcExp::clone(a),
916 });
917 }
918
919 Exp::Evalms(a, b) => {
920 self.kont.push(Cont::EvalmsRight {
921 env: env.clone(),
922 e2: RcExp::clone(b),
923 });
924 return Ok(Mode::Eval {
925 env,
926 exp: RcExp::clone(a),
927 });
928 }
929 };
930 Ok(Mode::Apply { val })
931 }
932
933 fn resume<M: Mail>(&mut self, k: Cont, val: Val, h: &mut Store<M>) -> Result<Mode, Fault> {
934 match k {
935 Cont::Prim1Finish { op } => Ok(Mode::Apply {
936 val: prim1(op, val, h)?,
937 }),
938
939 Cont::Prim2Right { env, op, e2 } => {
940 self.kont.push(Cont::Prim2Finish { op, v1: val });
941 Ok(Mode::Eval { env, exp: e2 })
942 }
943
944 Cont::Prim2Finish { op, v1 } => Ok(Mode::Apply {
945 val: prim2(op, v1, val, h)?,
946 }),
947
948 Cont::AppArgs {
949 env,
950 args,
951 mut done,
952 } => {
953 done.push(val);
954 if done.len() == args.len() + 1 {
955 return self.enter(done, h);
956 }
957 let exp = RcExp::clone(&args[done.len() - 1]);
958 self.kont.push(Cont::AppArgs {
959 env: env.clone(),
960 args,
961 done,
962 });
963 Ok(Mode::Eval { env, exp })
964 }
965
966 Cont::ApplyArgs { env, args } => {
967 self.kont.push(Cont::ApplyFinish { f: val });
968 Ok(Mode::Eval { env, exp: args })
969 }
970
971 Cont::ApplyFinish { f } => {
972 let mut done = vec![f];
973 let mut rest = val;
974 loop {
975 match rest {
976 Val::Nil => break,
977 Val::Pair(a, d) => {
978 done.push(RcVal::unwrap_or_clone(a));
979 rest = RcVal::unwrap_or_clone(d);
980 }
981 _ => return Err(wrong_type("apply")),
982 }
983 }
984 self.enter(done, h)
985 }
986
987 Cont::OpArgs {
988 idx,
989 env,
990 args,
991 next,
992 mut done,
993 } => {
994 done.push(val);
995 if next == args.len() {
996 return self.run_op(idx, done, h);
997 }
998 let exp = RcExp::clone(&args[next]);
999 self.kont.push(Cont::OpArgs {
1000 idx,
1001 env: env.clone(),
1002 args,
1003 next: next + 1,
1004 done,
1005 });
1006 Ok(Mode::Eval { env, exp })
1007 }
1008
1009 Cont::IfDispatch { env, then_, else_ } => match val {
1012 Val::Code(c) => {
1013 let saved = Scope::save(h);
1014 self.kont.push(Cont::ForceCode {
1015 mode: ForceMode::Scalar,
1016 then: Then::Drain {
1017 saved,
1018 then: Reify::IfTrue {
1019 c,
1020 env: env.clone(),
1021 f: else_,
1022 },
1023 },
1024 });
1025 Ok(Mode::Eval { env, exp: then_ })
1026 }
1027 Val::Num(0) | Val::Nil => Ok(Mode::Eval { env, exp: else_ }),
1028 _ => Ok(Mode::Eval { env, exp: then_ }),
1029 },
1030
1031 Cont::LetBody { env, body } => Ok(Mode::Eval {
1032 env: env.push_owned(val),
1033 exp: body,
1034 }),
1035
1036 Cont::CatchExit { saved } => {
1040 if h.block.is_empty() && !matches!(val, Val::Code(_)) {
1041 saved.restore(h);
1042 return Ok(Mode::Apply { val });
1043 }
1044 self.kont.push(Cont::ForceCode {
1047 mode: ForceMode::Lift,
1048 then: Then::Drain {
1049 saved,
1050 then: Reify::CatchDone,
1051 },
1052 });
1053 Ok(Mode::Apply { val })
1054 }
1055
1056 Cont::ThrowFinish => match val {
1059 Val::Code(e) => Ok(Mode::Apply {
1060 val: h.reflectc(Exp::Throw(e)),
1061 }),
1062 v => Ok(Mode::Apply {
1063 val: super::raise(v),
1064 }),
1065 },
1066
1067 Cont::LiftFunClo { env, f } => {
1072 let arity = match val {
1073 Val::Num(n) => u16::try_from(n).map_err(|_| wrong_type("lift-fun"))?,
1074 _ => return Err(wrong_type("lift-fun")),
1075 };
1076 self.kont.push(Cont::LiftFunGo { arity });
1077 Ok(Mode::Eval { env, exp: f })
1078 }
1079
1080 Cont::LiftFunGo { arity } => {
1084 let saved = Scope::save(h);
1085 h.register_lam(h.fresh);
1089 let vars: Vec<Val> = (0..=arity).map(|_| code(Exp::Var(h.fresh_var()))).collect();
1090 let frame = vars
1091 .into_iter()
1092 .rev()
1093 .fold(Val::Nil, |t, v| Val::Pair(rc_val(v), rc_val(t)));
1094 self.kont.push(Cont::LiftCloFinish {
1095 arity,
1096 then: Then::WrapAsCode,
1097 });
1098 self.kont.push(Cont::ForceCode {
1101 mode: ForceMode::Scalar,
1102 then: Then::Drain {
1103 saved,
1104 then: Reify::Produce,
1105 },
1106 });
1107 self.enter(vec![val, frame], h)
1108 }
1109
1110 Cont::LiftFinish => {
1111 self.kont.push(Cont::ForceCode {
1112 mode: ForceMode::Lift,
1113 then: Then::WrapAsCode,
1114 });
1115 Ok(Mode::Apply { val })
1116 }
1117
1118 Cont::ForceCode { mode, then } => self.force(mode, then, val, h),
1119
1120 Cont::LiftCloFinish { arity, then } => {
1121 let body = match val {
1122 Val::Code(e) => RcExp::unwrap_or_clone(e),
1123 _ => return Err(wrong_type("lift")),
1124 };
1125 let produced = h.reflect(Exp::Lam(arity, rc_exp(body)));
1128 if let Exp::Var(n) = produced {
1131 h.register_lam(n);
1132 }
1133 self.dispatch_then(then, produced, h)
1134 }
1135
1136 Cont::ReifyVExit { saved } => {
1137 let stmts = std::mem::take(&mut h.block);
1138 let out = if stmts.is_empty() {
1139 val
1140 } else {
1141 match val {
1142 Val::Code(e) => code(drain(stmts, RcExp::unwrap_or_clone(e))),
1143 _ => {
1144 return Err(Fault::Bug(
1145 "reify: non-empty block with a non-code result".into(),
1146 ))
1147 }
1148 }
1149 };
1150 saved.restore(h);
1151 Ok(Mode::Apply { val: out })
1152 }
1153
1154 Cont::RunNowExit { saved_level } => {
1155 h.level = saved_level;
1156 Ok(Mode::Apply { val })
1157 }
1158
1159 Cont::LiftRefDispatch { env, e2 } => match val {
1160 Val::Code(s1) => {
1161 let saved = Scope::save(h);
1162 self.kont.push(Cont::ForceCode {
1163 mode: ForceMode::Lift,
1164 then: Then::Drain {
1165 saved,
1166 then: Reify::LiftRefDone { s1 },
1167 },
1168 });
1169 Ok(Mode::Eval { env, exp: e2 })
1170 }
1171 _ => {
1172 self.kont.push(Cont::LiftRefPersist);
1173 Ok(Mode::Eval { env, exp: e2 })
1174 }
1175 },
1176
1177 Cont::LiftRefPersist => {
1182 if has_holes(&val, h) {
1186 return Err(throw("unpersistable", Val::Sym(kind_of(&val).into())));
1187 }
1188 Ok(Mode::Apply {
1189 val: Val::Code(rc_exp(Exp::Proc(rc_val(val)))),
1190 })
1191 }
1192
1193 Cont::RunDispatch { env, e } => match val {
1194 Val::Code(b) => {
1195 let saved = Scope::save(h);
1196 self.kont.push(Cont::ForceCode {
1197 mode: ForceMode::Strict,
1198 then: Then::Drain {
1199 saved,
1200 then: Reify::RunStaged { b },
1201 },
1202 });
1203 Ok(Mode::Eval { env, exp: e })
1204 }
1205 _ => {
1208 let env_len = env.len();
1209 self.kont.push(Cont::RunNowExit {
1210 saved_level: h.level,
1211 });
1212 h.level += 1;
1213
1214 let saved_outer = Scope::save(h);
1215 self.kont.push(Cont::ReifyVExit { saved: saved_outer });
1216
1217 let saved_inner = Scope::save(h);
1218 self.kont.push(Cont::ForceCode {
1219 mode: ForceMode::Strict,
1220 then: Then::Drain {
1221 saved: saved_inner,
1222 then: Reify::RunNowInner { env: env.clone() },
1223 },
1224 });
1225
1226 h.fresh = env_len;
1229 Ok(Mode::Eval { env, exp: e })
1230 }
1231 },
1232
1233 Cont::IsCodeRight { env, e2 } => {
1234 self.kont.push(Cont::IsCodeFinish { v1: val });
1235 Ok(Mode::Eval { env, exp: e2 })
1236 }
1237
1238 Cont::IsCodeFinish { v1 } => match v1 {
1239 Val::Code(s1) => {
1240 self.kont.push(Cont::ForceCode {
1241 mode: ForceMode::Strict,
1242 then: Then::IsCodeStaged { s1 },
1243 });
1244 Ok(Mode::Apply { val })
1245 }
1246 _ => Ok(Mode::Apply {
1247 val: bool_val(matches!(val, Val::Code(_))),
1248 }),
1249 },
1250
1251 Cont::EvalmsRight { env, e2 } => {
1252 self.kont.push(Cont::EvalmsFinish { env_val: val });
1253 Ok(Mode::Eval { env, exp: e2 })
1254 }
1255
1256 Cont::EvalmsFinish { env_val } => {
1257 let env = env_from_list(&env_val)?;
1258 let exp = match val {
1259 Val::Code(e) => e,
1260 _ => return Err(wrong_type("evalms")),
1261 };
1262 let saved = Scope::save(h);
1263 self.kont.push(Cont::ReifyVExit { saved });
1264 Ok(Mode::Eval { env, exp })
1265 }
1266 }
1267 }
1268
1269 fn force<M: Mail>(
1273 &mut self,
1274 mode: ForceMode,
1275 then: Then,
1276 val: Val,
1277 h: &mut Store<M>,
1278 ) -> Result<Mode, Fault> {
1279 if let ForceMode::Strict | ForceMode::Scalar = mode {
1280 let immediate = match (mode, &val) {
1281 (ForceMode::Scalar, Val::Pair(_, _)) => {
1284 Some(rc_exp(cons_syntax(&val, "unreturnable", h)?))
1285 }
1286 (ForceMode::Scalar, v) => as_syntax(v),
1287 (_, Val::Code(e)) => Some(RcExp::clone(e)),
1288 _ => None,
1289 };
1290 return match immediate {
1291 Some(e) => {
1292 let produced = RcExp::unwrap_or_clone(e);
1293 self.dispatch_then(then, produced, h)
1294 }
1295 None if mode == ForceMode::Scalar => {
1298 Err(throw("unreturnable", Val::Sym(kind_of(&val).into())))
1299 }
1300 None => Err(wrong_type("force-code")),
1301 };
1302 }
1303 match val {
1304 Val::Code(e) => {
1305 let produced = RcExp::unwrap_or_clone(e);
1306 self.dispatch_then(then, produced, h)
1307 }
1308 Val::Num(n) => self.dispatch_then(then, Exp::Lit(n), h),
1309 Val::Flo(x) => self.dispatch_then(then, Exp::Flo(x), h),
1310 Val::Sym(s) => self.dispatch_then(then, Exp::Sym(s), h),
1311 Val::Atom(a) => self.dispatch_then(then, Exp::Atom(a), h),
1312 Val::Nil => self.dispatch_then(then, Exp::Nil, h),
1313
1314 Val::Cell(_) => Err(throw("unliftable", Val::Sym("cell".into()))),
1317
1318 v @ Val::Raise(_) => Ok(Mode::Apply { val: v }),
1321
1322 Val::Pair(a, b) => {
1323 let produced = cons_syntax(&Val::Pair(a, b), "unliftable", h)?;
1324 self.dispatch_then(then, produced, h)
1325 }
1326
1327 Val::Clo(cenv, lam) => {
1328 let Exp::Lam(arity, body) = &*lam else {
1329 return Err(Fault::Bug(format!("closure over {lam}")));
1330 };
1331 let (arity, body) = (*arity, RcExp::clone(body));
1332 if let Some(n) = h.find_fun(&cenv, &lam) {
1335 return self.dispatch_then(then, Exp::Var(n), h);
1336 }
1337 let level = h.fresh;
1338 h.register_fun(level, &cenv, &lam);
1339
1340 let saved = Scope::save(h);
1341 let mut frame = Vec::with_capacity(usize::from(arity) + 1);
1344 for _ in 0..=arity {
1345 frame.push(code(Exp::Var(h.fresh_var())));
1346 }
1347 let env = cenv.frame(frame);
1348
1349 self.kont.push(Cont::LiftCloFinish { arity, then });
1350 self.kont.push(Cont::ForceCode {
1353 mode: ForceMode::Strict,
1354 then: Then::Drain {
1355 saved,
1356 then: Reify::Produce,
1357 },
1358 });
1359 Ok(Mode::Eval { env, exp: body })
1360 }
1361 }
1362 }
1363
1364 fn dispatch_then<M: Mail>(
1365 &mut self,
1366 then: Then,
1367 produced: Exp,
1368 h: &mut Store<M>,
1369 ) -> Result<Mode, Fault> {
1370 match then {
1371 Then::WrapAsCode => Ok(Mode::Apply {
1372 val: code(produced),
1373 }),
1374 Then::IsCodeStaged { s1 } => Ok(Mode::Apply {
1375 val: h.reflectc(Exp::IsCode(s1, rc_exp(produced))),
1376 }),
1377 Then::Drain { saved, then } => {
1378 let stmts = std::mem::take(&mut h.block);
1379 let built = drain(stmts, produced);
1380 saved.restore(h);
1381 self.dispatch_reify(then, built, h)
1382 }
1383 }
1384 }
1385
1386 fn dispatch_reify<M: Mail>(
1387 &mut self,
1388 then: Reify,
1389 built: Exp,
1390 h: &mut Store<M>,
1391 ) -> Result<Mode, Fault> {
1392 match then {
1393 Reify::IfTrue { c, env, f } => {
1394 let saved = Scope::save(h);
1395 self.kont.push(Cont::ForceCode {
1396 mode: ForceMode::Scalar,
1397 then: Then::Drain {
1398 saved,
1399 then: Reify::IfFalse {
1400 c,
1401 t: rc_exp(built),
1402 },
1403 },
1404 });
1405 Ok(Mode::Eval { env, exp: f })
1406 }
1407 Reify::IfFalse { c, t } => Ok(Mode::Apply {
1408 val: h.reflectc(Exp::If(c, t, rc_exp(built))),
1409 }),
1410 Reify::RunStaged { b } => Ok(Mode::Apply {
1411 val: h.reflectc(Exp::Run(b, rc_exp(built))),
1412 }),
1413 Reify::LiftRefDone { s1 } => Ok(Mode::Apply {
1414 val: h.reflectc(Exp::LiftRef(s1, rc_exp(built))),
1415 }),
1416 Reify::RunNowInner { env } => Ok(Mode::Eval {
1419 env,
1420 exp: rc_exp(built),
1421 }),
1422 Reify::CatchDone => Ok(Mode::Apply {
1423 val: h.reflectc(Exp::Catch(rc_exp(built))),
1424 }),
1425 Reify::Produce => Ok(Mode::Apply { val: code(built) }),
1426 }
1427 }
1428
1429 fn enter<M: Mail>(&mut self, done: Vec<Val>, h: &mut Store<M>) -> Result<Mode, Fault> {
1433 let arity = done.len() - 1;
1434 match &done[0] {
1435 Val::Clo(cenv, lam) => {
1436 let Exp::Lam(n, body) = &**lam else {
1437 return Err(Fault::Bug(format!("closure over {lam}")));
1438 };
1439 if usize::from(*n) != arity {
1440 return Err(throw("arity", Val::Num(arity as i64)));
1441 }
1442 let (cenv, body) = (cenv.clone(), RcExp::clone(body));
1443 Ok(Mode::Eval {
1444 env: cenv.frame(done),
1445 exp: body,
1446 })
1447 }
1448
1449 Val::Code(_) => {
1453 let mut parts = staged_operands(&done, "app").expect("operator is code")?;
1454 let f = parts.remove(0);
1455 Ok(Mode::Apply {
1456 val: h.reflectc(Exp::App(f, parts.into())),
1457 })
1458 }
1459
1460 _ => Err(wrong_type("app")),
1461 }
1462 }
1463
1464 fn run_op<M: Mail>(
1465 &mut self,
1466 idx: u16,
1467 args: Vec<Val>,
1468 h: &mut Store<M>,
1469 ) -> Result<Mode, Fault> {
1470 let def = host::registry().get(idx);
1471 if args.len() != def.arity {
1472 return Err(throw("arity", Val::Sym(def.name.into())));
1473 }
1474 if let Some(parts) = staged_operands(&args, def.name) {
1478 return Ok(Mode::Apply {
1479 val: h.reflectc(Exp::Op(idx, parts?)),
1480 });
1481 }
1482 match (def.run)(&args) {
1483 Ok(v) => Ok(Mode::Apply { val: v }),
1484 Err(v) => Err(Fault::Throw(v)),
1485 }
1486 }
1487}
1488
1489fn bool_val(b: bool) -> Val {
1490 Val::Num(if b { 1 } else { 0 })
1491}
1492
1493fn env_from_list(v: &Val) -> Result<Env, Fault> {
1496 let mut vals = Vec::new();
1497 let mut cur = v;
1498 loop {
1499 match cur {
1500 Val::Nil => return Ok(Env::new(vals)),
1501 Val::Pair(a, b) => {
1502 vals.push(Val::clone(a));
1503 cur = b;
1504 }
1505 _ => return Err(wrong_type("evalms")),
1506 }
1507 }
1508}
1509
1510fn receives(k: &Cont) -> bool {
1516 match k {
1517 Cont::AppArgs { done, .. } => !done.is_empty(),
1520 Cont::LetBody { .. }
1521 | Cont::Prim1Finish {
1522 op: Prim1::IsRaise | Prim1::RaiseValue,
1523 } => true,
1524 _ => false,
1525 }
1526}
1527
1528fn prim1<M: Mail>(op: Prim1, v: Val, h: &mut Store<M>) -> Result<Val, Fault> {
1529 macro_rules! pred {
1532 ($ctor:expr, $pat:pat) => {
1533 match v {
1534 Val::Code(e) => Ok(h.reflectc($ctor(e))),
1535 ref x => Ok(bool_val(matches!(x, $pat))),
1536 }
1537 };
1538 }
1539 match op {
1540 Prim1::IsNum => pred!(|e| Exp::Prim1(Prim1::IsNum, e), Val::Num(_) | Val::Flo(_)),
1541 Prim1::IsSym => pred!(|e| Exp::Prim1(Prim1::IsSym, e), Val::Sym(_)),
1542 Prim1::IsNil => pred!(|e| Exp::Prim1(Prim1::IsNil, e), Val::Nil),
1543 Prim1::IsPair => pred!(|e| Exp::Prim1(Prim1::IsPair, e), Val::Pair(_, _)),
1544
1545 Prim1::Car => match v {
1546 Val::Pair(a, _) => Ok(Val::clone(&a)),
1547 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::Car, e))),
1548 _ => Err(wrong_type("car")),
1549 },
1550 Prim1::Cdr => match v {
1551 Val::Pair(_, b) => Ok(Val::clone(&b)),
1552 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::Cdr, e))),
1553 _ => Err(wrong_type("cdr")),
1554 },
1555
1556 Prim1::CellNew => match v {
1557 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::CellNew, e))),
1558 v => {
1559 h.cells.push(v);
1560 Ok(Val::Cell(h.cells.len() - 1))
1561 }
1562 },
1563 Prim1::CellRead => match v {
1564 Val::Cell(i) => Ok(h.cells[i].clone()),
1565 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::CellRead, e))),
1566 _ => Err(wrong_type("cell-read")),
1567 },
1568
1569 Prim1::Spawn => match v {
1573 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::Spawn, e))),
1574 v => h.mail.spawn(v).map_err(Fault::Throw),
1575 },
1576 Prim1::Monitor => match v {
1577 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::Monitor, e))),
1578 v => h.mail.monitor(&v).map_err(Fault::Throw),
1579 },
1580 Prim1::SpawnMonitor => match v {
1583 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::SpawnMonitor, e))),
1584 v => {
1585 let child = h.mail.spawn(v).map_err(Fault::Throw)?;
1586 h.mail.monitor(&child).map_err(Fault::Throw)?;
1587 Ok(child)
1588 }
1589 },
1590 Prim1::Receive => match v {
1593 Val::Code(e) => Ok(h.reflectc(Exp::Prim1(Prim1::Receive, e))),
1594 _ => Err(Fault::Bug("receive reached prim1".into())),
1595 },
1596
1597 Prim1::IsRaise => Ok(bool_val(matches!(v, Val::Raise(_)))),
1601 Prim1::IsCodeFun => Ok(bool_val(matches!(&v, Val::Code(e) if h.is_lam(e)))),
1602 Prim1::RaiseValue => match v {
1603 Val::Raise(e) => Ok(Val::clone(&e)),
1604 _ => Err(wrong_type("raise-value")),
1605 },
1606 }
1607}
1608
1609fn prim2<M: Mail>(op: Prim2, v1: Val, v2: Val, h: &mut Store<M>) -> Result<Val, Fault> {
1610 if let Prim2::Cons = op {
1613 return Ok(Val::Pair(rc_val(v1), rc_val(v2)));
1614 }
1615
1616 if matches!((&v1, &v2), (Val::Code(_), _) | (_, Val::Code(_))) {
1617 let (Some(a), Some(b)) = (as_syntax(&v1), as_syntax(&v2)) else {
1618 return Err(wrong_type(op.name()));
1619 };
1620 return Ok(h.reflectc(Exp::Prim2(op, a, b)));
1621 }
1622
1623 match op {
1624 Prim2::Cons => unreachable!("handled above"),
1625
1626 Prim2::Eq => Ok(bool_val(v1 == v2)),
1627
1628 Prim2::Plus | Prim2::Minus | Prim2::Times | Prim2::Div | Prim2::Mod | Prim2::Lt => {
1629 arith(op, v1, v2)
1630 }
1631
1632 Prim2::CellSet => match v1 {
1633 Val::Cell(i) => {
1634 h.cells[i] = v2.clone();
1635 Ok(v2)
1636 }
1637 _ => Err(wrong_type("cell-set!")),
1638 },
1639
1640 Prim2::Send => match is_data(&v2) {
1641 true => h.mail.send(&v1, v2).map_err(Fault::Throw),
1642 false => Err(throw("not-data", v2)),
1643 },
1644
1645 Prim2::LimitTurns => match v2 {
1646 Val::Num(n) if n > 0 => h.mail.limit(&v1, n).map_err(Fault::Throw),
1647 _ => Err(wrong_type("limit-turns")),
1648 },
1649 }
1650}
1651
1652fn is_data(v: &Val) -> bool {
1658 let mut work = vec![v];
1659 while let Some(v) = work.pop() {
1660 match v {
1661 Val::Num(_) | Val::Flo(_) | Val::Sym(_) | Val::Atom(_) | Val::Nil => {}
1662 Val::Pair(a, b) => {
1663 work.push(a);
1664 work.push(b);
1665 }
1666 Val::Clo(_, _) | Val::Code(_) | Val::Cell(_) | Val::Raise(_) => return false,
1669 }
1670 }
1671 true
1672}
1673
1674fn arith(op: Prim2, v1: Val, v2: Val) -> Result<Val, Fault> {
1675 let name = match op {
1676 Prim2::Plus => "+",
1677 Prim2::Minus => "-",
1678 Prim2::Times => "*",
1679 Prim2::Div => "/",
1680 Prim2::Mod => "%",
1681 Prim2::Lt => "<",
1682 _ => unreachable!("not arithmetic"),
1683 };
1684 match (v1, v2) {
1685 (Val::Num(a), Val::Num(b)) => match op {
1686 Prim2::Plus => Ok(Val::Num(a.wrapping_add(b))),
1687 Prim2::Minus => Ok(Val::Num(a.wrapping_sub(b))),
1688 Prim2::Times => Ok(Val::Num(a.wrapping_mul(b))),
1689 Prim2::Lt => Ok(bool_val(a < b)),
1690 Prim2::Div | Prim2::Mod if b == 0 => {
1691 Err(throw("divide-by-zero", Val::Sym(name.into())))
1692 }
1693 Prim2::Div => Ok(Val::Num(a.wrapping_div(b))),
1694 Prim2::Mod => Ok(Val::Num(a.wrapping_rem(b))),
1695 _ => unreachable!("not arithmetic"),
1696 },
1697 (a, b) if is_num(&a) && is_num(&b) => {
1700 let (x, y) = (as_f64(&a), as_f64(&b));
1701 match op {
1702 Prim2::Plus => Ok(Val::Flo(x + y)),
1703 Prim2::Minus => Ok(Val::Flo(x - y)),
1704 Prim2::Times => Ok(Val::Flo(x * y)),
1705 Prim2::Div => Ok(Val::Flo(x / y)),
1706 Prim2::Mod => Ok(Val::Flo(x % y)),
1707 Prim2::Lt => Ok(bool_val(x < y)),
1708 _ => unreachable!("not arithmetic"),
1709 }
1710 }
1711 _ => Err(wrong_type(name)),
1712 }
1713}
1714
1715fn is_num(v: &Val) -> bool {
1716 matches!(v, Val::Num(_) | Val::Flo(_))
1717}
1718
1719fn as_f64(v: &Val) -> f64 {
1720 match v {
1721 Val::Num(n) => *n as f64,
1722 Val::Flo(x) => *x,
1723 _ => unreachable!("checked by is_num"),
1724 }
1725}
1726
1727#[cfg(test)]
1728mod tests {
1729 use super::*;
1730 use crate::floor::host::Str;
1731 use crate::floor::{rc_exp, Env};
1732
1733 fn eval(e: Exp) -> Result<Val, Fault> {
1734 Machine::new(Env::default(), rc_exp(e)).run(&mut Store::<NoMail>::default())
1735 }
1736
1737 fn lam(body: Exp) -> Exp {
1738 Exp::Lam(1, rc_exp(body))
1739 }
1740 fn app(f: Exp, a: Exp) -> Exp {
1741 Exp::App(rc_exp(f), Box::new([rc_exp(a)]))
1742 }
1743 fn p1(op: Prim1, a: Exp) -> Exp {
1744 Exp::Prim1(op, rc_exp(a))
1745 }
1746 fn p2(op: Prim2, a: Exp, b: Exp) -> Exp {
1747 Exp::Prim2(op, rc_exp(a), rc_exp(b))
1748 }
1749 fn if_(c: Exp, t: Exp, f: Exp) -> Exp {
1750 Exp::If(rc_exp(c), rc_exp(t), rc_exp(f))
1751 }
1752
1753 #[test]
1754 fn arithmetic_widens_only_when_an_operand_is_float() {
1755 assert_eq!(
1756 eval(p2(Prim2::Plus, Exp::Lit(2), Exp::Lit(3))),
1757 Ok(Val::Num(5))
1758 );
1759 assert_eq!(
1760 eval(p2(Prim2::Plus, Exp::Lit(2), Exp::Flo(0.5))),
1761 Ok(Val::Flo(2.5))
1762 );
1763 assert_eq!(
1764 eval(p2(Prim2::Div, Exp::Lit(7), Exp::Lit(2))),
1765 Ok(Val::Num(3))
1766 );
1767 }
1768
1769 #[test]
1770 fn a_closure_receives_itself_so_recursion_needs_no_fixed_point() {
1771 let n = Exp::Var(1);
1773 let me = Exp::Var(0);
1774 let fact = lam(if_(
1775 p2(Prim2::Lt, n.clone(), Exp::Lit(1)),
1776 Exp::Lit(1),
1777 p2(
1778 Prim2::Times,
1779 n.clone(),
1780 app(me, p2(Prim2::Minus, n, Exp::Lit(1))),
1781 ),
1782 ));
1783 assert_eq!(eval(app(fact, Exp::Lit(5))), Ok(Val::Num(120)));
1784 }
1785
1786 #[test]
1787 fn a_cell_written_inside_an_abandoned_catch_keeps_its_write() {
1788 let body = Exp::Let(
1795 rc_exp(Exp::Catch(rc_exp(Exp::Let(
1796 rc_exp(p2(Prim2::CellSet, Exp::Var(0), Exp::Lit(2))),
1797 rc_exp(Exp::Throw(rc_exp(Exp::Sym("boom".into())))),
1798 )))),
1799 rc_exp(p1(Prim1::CellRead, Exp::Var(0))),
1800 );
1801 let prog = Exp::Let(rc_exp(p1(Prim1::CellNew, Exp::Lit(1))), rc_exp(body));
1802
1803 let mut h = Store::<NoMail>::default();
1804 let got = Machine::new(Env::default(), rc_exp(prog)).run(&mut h);
1805 assert_eq!(got, Ok(Val::Num(2)));
1806 assert!(h.block.is_empty());
1807 assert_eq!(h.fresh, 0);
1808 }
1809
1810 #[test]
1811 fn catch_yields_the_thrown_value() {
1812 assert_eq!(
1813 eval(Exp::Catch(rc_exp(Exp::Throw(rc_exp(Exp::Sym(
1814 "boom".into()
1815 )))))),
1816 Ok(Val::Sym("boom".into()))
1817 );
1818 }
1819
1820 #[test]
1821 fn an_uncaught_throw_is_the_answer_rather_than_a_failure() {
1822 assert_eq!(
1823 eval(Exp::Throw(rc_exp(Exp::Sym("boom".into())))),
1824 Ok(super::super::raise(Val::Sym("boom".into())))
1825 );
1826 }
1827
1828 #[test]
1829 fn a_raise_passed_as_an_argument_is_an_ordinary_value() {
1830 assert_eq!(
1831 eval(Exp::App(
1832 rc_exp(Exp::Lam(1, rc_exp(Exp::Lit(7)))),
1833 Box::new([rc_exp(Exp::Throw(rc_exp(Exp::Sym("boom".into()))))])
1834 )),
1835 Ok(Val::Num(7))
1836 );
1837 }
1838
1839 #[test]
1840 fn a_raise_propagates_through_a_primitive() {
1841 assert_eq!(
1842 eval(p2(
1843 Prim2::Plus,
1844 Exp::Lit(1),
1845 Exp::Throw(rc_exp(Exp::Sym("boom".into())))
1846 )),
1847 Ok(super::super::raise(Val::Sym("boom".into())))
1848 );
1849 }
1850
1851 #[test]
1852 fn a_raise_is_a_datum_in_exactly_the_positions_that_bind_one() {
1853 let let_ = |init: Exp, body: Exp| Exp::Let(rc_exp(init), rc_exp(body));
1854 let boom = || p2(Prim2::Div, Exp::Lit(1), Exp::Lit(0));
1859 let thrown = || Exp::Throw(rc_exp(Exp::Sym("boom".into())));
1860 let div0 = || {
1861 Ok(super::super::raise(Val::Pair(
1862 rc_val(Val::Sym("divide-by-zero".into())),
1863 rc_val(Val::Sym("/".into())),
1864 )))
1865 };
1866
1867 assert_eq!(eval(let_(boom(), Exp::Lit(7))), Ok(Val::Num(7)));
1870 assert_eq!(eval(let_(thrown(), Exp::Lit(7))), Ok(Val::Num(7)));
1871 assert_eq!(eval(app(lam(Exp::Lit(7)), boom())), Ok(Val::Num(7)));
1872 assert_eq!(eval(app(lam(Exp::Lit(7)), thrown())), Ok(Val::Num(7)));
1873 assert_eq!(eval(let_(boom(), Exp::Var(0))), div0());
1875 assert_eq!(eval(app(lam(Exp::Var(1)), boom())), div0());
1876
1877 assert_eq!(eval(p2(Prim2::Plus, boom(), Exp::Lit(1))), div0());
1880 assert_eq!(eval(p2(Prim2::Plus, Exp::Lit(1), boom())), div0());
1881 assert_eq!(eval(p1(Prim1::Car, boom())), div0());
1882 assert_eq!(eval(if_(boom(), Exp::Lit(1), Exp::Lit(2))), div0());
1883 assert_eq!(eval(app(boom(), Exp::Lit(1))), div0());
1884
1885 assert_eq!(eval(p1(Prim1::IsRaise, boom())), Ok(Val::Num(1)));
1888 assert_eq!(
1889 eval(p1(Prim1::RaiseValue, boom())),
1890 Ok(Val::Pair(
1891 rc_val(Val::Sym("divide-by-zero".into())),
1892 rc_val(Val::Sym("/".into()))
1893 ))
1894 );
1895
1896 let caught = || {
1901 Ok(Val::Pair(
1902 rc_val(Val::Sym("divide-by-zero".into())),
1903 rc_val(Val::Sym("/".into())),
1904 ))
1905 };
1906 assert_eq!(
1907 eval(Exp::Catch(rc_exp(let_(boom(), Exp::Var(0))))),
1908 caught()
1909 );
1910 assert_eq!(
1911 eval(Exp::Catch(rc_exp(app(lam(Exp::Var(1)), boom())))),
1912 caught()
1913 );
1914 assert_eq!(
1915 eval(Exp::Catch(rc_exp(p2(Prim2::Plus, Exp::Lit(1), boom())))),
1916 caught()
1917 );
1918
1919 assert_eq!(
1924 eval(let_(p2(Prim2::Plus, Exp::Lit(1), Exp::Lit(2)), Exp::Var(0))),
1925 Ok(Val::Num(3))
1926 );
1927 assert_eq!(
1928 eval(app(lam(Exp::Var(1)), p1(Prim1::Car, Exp::Nil))),
1929 Ok(super::super::raise(Val::Pair(
1930 rc_val(Val::Sym("wrong-type".into())),
1931 rc_val(Val::Sym("car".into()))
1932 )))
1933 );
1934 }
1935
1936 #[test]
1937 fn a_partial_primitive_throws_a_catchable_value() {
1938 let bad = p2(Prim2::Div, Exp::Lit(1), Exp::Lit(0));
1939 assert_eq!(
1940 eval(Exp::Catch(rc_exp(bad))),
1941 Ok(Val::Pair(
1942 rc_val(Val::Sym("divide-by-zero".into())),
1943 rc_val(Val::Sym("/".into()))
1944 ))
1945 );
1946 }
1947
1948 #[test]
1949 fn host_ops_run_through_the_table() {
1950 let idx = host::registry().lookup("str-append").expect("op present");
1951 let prog = Exp::Op(
1952 idx,
1953 vec![
1954 rc_exp(Exp::Atom(match Str::val("na") {
1955 Val::Atom(a) => a,
1956 _ => unreachable!(),
1957 })),
1958 rc_exp(Exp::Atom(match Str::val("rju") {
1959 Val::Atom(a) => a,
1960 _ => unreachable!(),
1961 })),
1962 ],
1963 );
1964 assert_eq!(eval(prog), Ok(Str::val("narju")));
1965 }
1966
1967 #[test]
1968 fn receive_blocks_without_consuming_its_continuation() {
1969 let mut h = Store::<NoMail>::default();
1970 let mut m = Machine::new(Env::default(), rc_exp(p1(Prim1::Receive, Exp::Nil)));
1971 for _ in 0..8 {
1974 match m.step(&mut h).expect("no fault") {
1975 Step::Blocked => return,
1976 Step::Done(v) => panic!("completed with {v}"),
1977 Step::Running => {}
1978 }
1979 }
1980 panic!("never reached the block");
1981 }
1982
1983 fn lift(e: Exp) -> Exp {
1986 Exp::Lift(rc_exp(e))
1987 }
1988 fn stage(e: Exp) -> (Val, Vec<Exp>) {
1989 let mut h = Store::<NoMail>::default();
1990 let v = Machine::new(Env::default(), rc_exp(e))
1991 .run(&mut h)
1992 .expect("no fault");
1993 (v, h.block)
1994 }
1995 fn coded(v: &Val) -> &Exp {
1996 match v {
1997 Val::Code(e) => e,
1998 other => panic!("expected code, got {other}"),
1999 }
2000 }
2001
2002 #[test]
2003 fn lifting_a_closure_eta_expands_it_into_one_binding() {
2004 let (v, block) = stage(lift(lam(p2(Prim2::Plus, Exp::Var(1), lift(Exp::Lit(1))))));
2009 assert_eq!(coded(&v), &Exp::Var(0));
2010 assert_eq!(
2011 block,
2012 vec![Exp::Lam(
2013 1,
2014 rc_exp(Exp::Let(
2015 rc_exp(p2(Prim2::Plus, Exp::Var(1), Exp::Lit(1))),
2016 rc_exp(Exp::Var(2)),
2017 ))
2018 )]
2019 );
2020 }
2021
2022 #[test]
2023 fn lifting_a_pair_builds_it_a_cons_at_a_time() {
2024 let (v, block) = stage(lift(p2(
2026 Prim2::Cons,
2027 Exp::Lit(1),
2028 p2(Prim2::Cons, lift(Exp::Lit(2)), Exp::Nil),
2029 )));
2030 assert_eq!(coded(&v), &Exp::Var(1));
2031 assert_eq!(
2032 block,
2033 vec![
2034 p2(Prim2::Cons, Exp::Lit(2), Exp::Nil),
2035 p2(Prim2::Cons, Exp::Lit(1), Exp::Var(0)),
2036 ]
2037 );
2038 }
2039
2040 #[test]
2041 fn a_variable_the_floor_emitted_a_lambda_for_says_so() {
2042 let is_fun = |e: Exp| eval(Exp::Prim1(Prim1::IsCodeFun, rc_exp(e)));
2043 assert_eq!(is_fun(lift(lam(Exp::Var(1)))), Ok(Val::Num(1)));
2044 assert_eq!(is_fun(lift(Exp::Lit(1))), Ok(Val::Num(0)));
2047 assert_eq!(
2048 is_fun(Exp::Prim1(
2049 Prim1::Car,
2050 rc_exp(p2(Prim2::Cons, lift(Exp::Lit(1)), lift(Exp::Lit(2))))
2051 )),
2052 Ok(Val::Num(0))
2053 );
2054 }
2055
2056 #[test]
2057 fn building_a_deep_structure_costs_no_stack() {
2058 let mut h = Store::<NoMail>::default();
2059 let long = (0..10_000).fold(Val::Nil, |t, i| Val::Pair(rc_val(Val::Num(i)), rc_val(t)));
2060 cons_syntax(&long, "unliftable", &mut h).expect("built");
2061 let deep = (0..10_000).fold(Val::Nil, |t, _| Val::Pair(rc_val(t), rc_val(Val::Nil)));
2062 cons_syntax(&deep, "unliftable", &mut h).expect("built");
2063 assert_eq!(h.block.len(), 20_000);
2064 }
2065
2066 #[test]
2067 fn a_closure_lifted_twice_expands_once() {
2068 let (v, block) = stage(Exp::Let(
2074 rc_exp(lam(Exp::Var(1))),
2075 rc_exp(p2(Prim2::Cons, lift(Exp::Var(0)), lift(Exp::Var(0)))),
2076 ));
2077 match v {
2078 Val::Pair(a, b) => {
2079 assert_eq!(coded(&a), &Exp::Var(0));
2080 assert_eq!(coded(&b), &Exp::Var(0));
2081 }
2082 other => panic!("expected a pair, got {other}"),
2083 }
2084 assert_eq!(block, vec![Exp::Lam(1, rc_exp(Exp::Var(1)))]);
2085 }
2086
2087 #[test]
2088 fn a_staged_if_reifies_each_branch_into_its_own_block() {
2089 let (v, block) = stage(if_(
2091 lift(Exp::Lit(1)),
2092 p2(Prim2::Plus, lift(Exp::Lit(2)), lift(Exp::Lit(3))),
2093 lift(Exp::Lit(4)),
2094 ));
2095 assert_eq!(coded(&v), &Exp::Var(0));
2096 assert_eq!(
2097 block,
2098 vec![if_(
2099 Exp::Lit(1),
2100 Exp::Let(
2102 rc_exp(p2(Prim2::Plus, Exp::Lit(2), Exp::Lit(3))),
2103 rc_exp(Exp::Var(0)),
2104 ),
2105 Exp::Lit(4),
2106 )]
2107 );
2108 }
2109
2110 #[test]
2111 fn cross_stage_persistence_carries_a_value_by_reference() {
2112 let (v, block) = stage(Exp::Let(
2117 rc_exp(lam(Exp::Var(1))),
2118 rc_exp(Exp::LiftRef(rc_exp(Exp::Lit(1)), rc_exp(Exp::Var(0)))),
2119 ));
2120 assert!(block.is_empty());
2121 assert!(matches!(coded(&v), Exp::Proc(p) if matches!(&**p, Val::Clo(_, _))));
2122 }
2123
2124 #[test]
2125 fn a_catch_whose_body_stages_residualizes() {
2126 let (v, block) = stage(Exp::Catch(rc_exp(p2(
2128 Prim2::Plus,
2129 lift(Exp::Lit(1)),
2130 lift(Exp::Lit(2)),
2131 ))));
2132 assert_eq!(coded(&v), &Exp::Var(0));
2133 assert_eq!(
2134 block,
2135 vec![Exp::Catch(rc_exp(Exp::Let(
2136 rc_exp(p2(Prim2::Plus, Exp::Lit(1), Exp::Lit(2))),
2137 rc_exp(Exp::Var(0)),
2138 )))]
2139 );
2140 }
2141
2142 #[test]
2143 fn a_staged_catch_ending_in_a_plain_value_lifts_its_tail() {
2144 let (v, block) = stage(Exp::Catch(rc_exp(Exp::Let(
2148 rc_exp(p2(Prim2::Plus, lift(Exp::Lit(1)), lift(Exp::Lit(2)))),
2149 rc_exp(Exp::Lit(7)),
2150 ))));
2151 assert_eq!(coded(&v), &Exp::Var(0));
2152 assert_eq!(
2153 block,
2154 vec![Exp::Catch(rc_exp(Exp::Let(
2155 rc_exp(p2(Prim2::Plus, Exp::Lit(1), Exp::Lit(2))),
2156 rc_exp(Exp::Lit(7)),
2157 )))]
2158 );
2159 }
2160
2161 #[test]
2162 fn run_now_executes_the_code_its_argument_produced() {
2163 let f = Exp::Run(
2165 rc_exp(Exp::Lit(0)),
2166 rc_exp(lift(lam(p2(Prim2::Plus, Exp::Var(1), lift(Exp::Lit(1)))))),
2167 );
2168 let mut h = Store::<NoMail>::default();
2169 let got = Machine::new(Env::default(), rc_exp(app(f, Exp::Lit(41)))).run(&mut h);
2170 assert_eq!(got, Ok(Val::Num(42)));
2171 assert_eq!(h.level, 0);
2173 assert!(h.block.is_empty());
2174 }
2175
2176 fn run_src(text: &str) -> Result<Val, Fault> {
2177 let forms = crate::floor::read::read(text).expect("reads");
2178 assert_eq!(forms.len(), 1);
2179 let exp = match crate::floor::read::trans(&forms[0], &Val::Nil).expect("lowers") {
2180 Val::Code(e) => e,
2181 other => panic!("expected code, got {other}"),
2182 };
2183 Machine::new(Env::default(), exp).run(&mut Store::<NoMail>::default())
2184 }
2185
2186 #[test]
2187 fn source_text_runs() {
2188 assert_eq!(
2189 run_src(
2190 "(let (fact (lambda (fact n)
2191 (if (< n 1) 1 (* n (fact (- n 1))))))
2192 (fact 5))"
2193 ),
2194 Ok(Val::Num(120))
2195 );
2196 }
2197
2198 #[test]
2199 fn source_text_stages_and_runs_what_it_staged() {
2200 assert_eq!(
2204 run_src(
2205 "((run 0 (let (pow (lambda (pow n)
2206 (lambda (f x)
2207 (if (< n 1) (lift 1) (* x ((pow (- n 1)) x))))))
2208 (lift (pow 3))))
2209 2)"
2210 ),
2211 Ok(Val::Num(8))
2212 );
2213 }
2214
2215 #[test]
2216 fn one_staged_operand_stages_the_call_and_the_rest_join_it() {
2217 let (v, block) = stage(p2(Prim2::Plus, lift(Exp::Lit(1)), Exp::Lit(2)));
2218 assert_eq!(coded(&v), &Exp::Var(0));
2219 assert_eq!(block, vec![p2(Prim2::Plus, Exp::Lit(1), Exp::Lit(2))]);
2220 assert!(matches!(
2221 eval(p2(
2222 Prim2::Plus,
2223 lift(Exp::Lit(1)),
2224 Exp::Prim2(Prim2::Cons, rc_exp(Exp::Lit(2)), rc_exp(Exp::Nil))
2225 )),
2226 Ok(Val::Raise(_))
2227 ));
2228 }
2229}