narju/
tower.rs

1use crate::floor::machine::{drain, Fault, Machine, Store};
2use crate::floor::{list, rc_exp, rc_val, Env, Exp, RcExp, Val};
3
4fn sym(s: &str) -> Val {
5    Val::Sym(s.into())
6}
7
8/// A `clambda` evaluated outside a staged region answers `('cfun . f)`, the tag
9/// telling a call site that `f` is compiled rather than primitive. From out here
10/// there is nothing to decide, so the wrapper only gets in the way.
11fn unwrap_cfun(v: &Val) -> &Val {
12    match v {
13        Val::Pair(h, t) if matches!(&**h, Val::Sym(s) if s == "cfun") => t,
14        _ => v,
15    }
16}
17
18pub const SOURCE: &str = include_str!("../naj/tower.naj");
19
20/// The library, evaluated by the evaluator rather than compiled beside it.
21pub const PRELUDE: &str = include_str!("../naj/prelude.naj");
22
23/// The prompt. An object program and a task like any other: nothing about a
24/// REPL needs to be built into the host.
25pub const REPL: &str = include_str!("../naj/repl.naj");
26
27/// Resolves `naj.deps` into `naj.lock`. An object program for the same reason
28/// the prompt is one: everything it needed was already a capability.
29pub const LOCK: &str = include_str!("../naj/lock.naj");
30
31/// A loaded evaluator and the heap it runs in; two towers do not share cells.
32/// The interpreter and environment are held here rather than in the evaluator
33/// because both accumulate: the prelude pushes a frame onto `env`, and an
34/// alteration replaces `m`.
35pub struct Tower {
36    heap: Store,
37    api: Val,
38    m: Val,
39    env: Val,
40}
41
42impl Tower {
43    pub fn load() -> Result<Tower, Fault> {
44        let exp = match crate::surface::compile(SOURCE).map_err(Fault::Throw)? {
45            Val::Code(e) => e,
46            other => return Err(Fault::Bug(format!("tower source is not code: {other}"))),
47        };
48        let mut heap = Store::default();
49        let api = Machine::new(Env::default(), exp).run(&mut heap)?;
50        let mut t = Tower {
51            heap,
52            api,
53            m: Val::Nil,
54            env: Val::Nil,
55        };
56        t.m = t.get("m")?;
57        t.env = t.get("env")?;
58
59        // The prelude is an object program, evaluated by the evaluator just
60        // loaded. Its value is a frame, which goes in front of the base one.
61        let forms = crate::floor::read::read(PRELUDE).map_err(Fault::Throw)?;
62        let src = crate::surface::desugar_body(&forms).map_err(Fault::Throw)?;
63        let frame = t.eval(&src)?;
64        t.env = Val::Pair(rc_val(frame), rc_val(t.env.clone()));
65        Ok(t)
66    }
67
68    /// Apply a value from this tower to arguments built outside it. A live value
69    /// with no source form rides in as [`Exp::Proc`], the carrier cross-stage
70    /// persistence uses.
71    pub fn call(&mut self, f: &Val, args: &[Val]) -> Result<Val, Fault> {
72        let proc = |v: &Val| rc_exp(Exp::Proc(rc_val(v.clone())));
73        let exp = Exp::App(proc(unwrap_cfun(f)), args.iter().map(proc).collect());
74        Machine::new(Env::default(), rc_exp(exp)).run(&mut self.heap)
75    }
76
77    /// What a module load amounts to, and how a value written outside the
78    /// evaluator - an interpreter mutation, say - gets inside it.
79    pub fn run_source(&mut self, src: &str) -> Result<Val, Fault> {
80        match crate::surface::compile(src).map_err(Fault::Throw)? {
81            Val::Code(e) => Machine::new(Env::default(), e).run(&mut self.heap),
82            other => Err(Fault::Bug(format!("source is not code: {other}"))),
83        }
84    }
85
86    /// One entry of the evaluator's export selector.
87    pub fn get(&mut self, name: &str) -> Result<Val, Fault> {
88        let api = self.api.clone();
89        self.call(&api, &[Val::Sym(name.into())])
90    }
91
92    pub fn eval(&mut self, prog: &Val) -> Result<Val, Fault> {
93        let m = self.m.clone();
94        self.eval_under(&m, prog)
95    }
96
97    /// The environment is this tower's either way: an alteration changes what
98    /// the forms mean, not what is in scope.
99    pub fn eval_under(&mut self, m: &Val, prog: &Val) -> Result<Val, Fault> {
100        let f = self.get("eval")?;
101        let env = self.env.clone();
102        self.call(&f, &[m.clone(), env, prog.clone()])
103    }
104
105    /// The residual of a program, without running it. Staging leaves its
106    /// bindings in the heap's open block and hands back only the variable naming
107    /// the result, so closing the block is this caller's job.
108    pub fn compile(&mut self, prog: &Val) -> Result<Val, Fault> {
109        let m = self.m.clone();
110        self.compile_under(&m, prog)
111    }
112
113    /// As [`Tower::compile`], but under a given interpreter.
114    pub fn compile_under(&mut self, m: &Val, prog: &Val) -> Result<Val, Fault> {
115        let f = self.get("compile")?;
116        let env = self.env.clone();
117        let r = self.call(&f, &[m.clone(), env, prog.clone()])?;
118        Ok(self.close(r))
119    }
120
121    /// The floor closure a scheduler starts, evaluating `prog` with the task's
122    /// own address bound to `self`. Nothing of this tower's heap goes with it,
123    /// so the task runs in the heap that spawned it.
124    pub fn task(&mut self, prog: &Val) -> Result<Val, Fault> {
125        let f = self.get("task")?;
126        let m = self.m.clone();
127        let env = self.env.clone();
128        self.call(&f, &[m, env, prog.clone()])
129    }
130
131    /// A file, as the entry point of a task. The forms become the body of a
132    /// thunk the prelude's `script` runs once, so a sequence of definitions
133    /// ending in an expression still gets the loop an RPC needs. Nothing starts
134    /// until a message arrives: the invocation is a message like any other.
135    pub fn script(&mut self, forms: &[Val]) -> Result<Val, Fault> {
136        let mut thunk = vec![sym("lambda"), sym("run"), Val::Nil];
137        thunk.extend_from_slice(forms);
138        let whole = list(&[sym("script"), sym("self"), list(&thunk)]);
139        let prog = crate::surface::desugar_body(&[whole]).map_err(Fault::Throw)?;
140        self.task(&prog)
141    }
142
143    /// It reads its lines by calling `('host stdin)`, so what it needs from a
144    /// caller is a console to register and one message to start it.
145    pub fn repl(&mut self) -> Result<Val, Fault> {
146        let forms = crate::floor::read::read(REPL).map_err(Fault::Throw)?;
147        let prog = crate::surface::desugar_body(&forms).map_err(Fault::Throw)?;
148        self.task(&prog)
149    }
150
151    /// A `script` rather than a `task` because it runs once and ends, which is
152    /// the shape a file gets and the same message starts it.
153    pub fn locker(&mut self) -> Result<Val, Fault> {
154        let forms = crate::floor::read::read(LOCK).map_err(Fault::Throw)?;
155        self.script(&forms)
156    }
157
158    fn close(&mut self, v: Val) -> Val {
159        let Val::Code(e) = v else { return v };
160        let stmts = std::mem::take(&mut self.heap.block);
161        Val::Code(rc_exp(drain(stmts, RcExp::unwrap_or_clone(e))))
162    }
163}
164
165#[cfg(test)]
166mod tests {
167    use super::*;
168    use crate::floor::host::Str;
169    use crate::floor::{list, pair};
170    use crate::sched::{addr, Heap};
171    use crate::world::host;
172
173    fn prog(text: &str) -> Val {
174        let forms = crate::floor::read::read(text).expect("reads");
175        crate::surface::desugar_body(&forms).expect("desugars")
176    }
177
178    fn run(text: &str) -> Val {
179        Tower::load()
180            .expect("loads")
181            .eval(&prog(text))
182            .expect("no fault")
183    }
184
185    #[test]
186    fn the_evaluator_loads() {
187        Tower::load().expect("loads");
188    }
189
190    #[test]
191    fn an_interpreted_program_computes() {
192        assert_eq!(run("(let ((x 3)) (* x (+ x 1)))"), Val::Num(12));
193    }
194
195    #[test]
196    fn an_object_closure_is_applied_by_recursion() {
197        assert_eq!(
198            run(
199                "(let ((f (lambda fact (n) (if (< n 1) 1 (* n (fact (- n 1)))))))
200                   (f 5))"
201            ),
202            Val::Num(120)
203        );
204    }
205
206    #[test]
207    fn quoted_data_survives_evaluation() {
208        assert_eq!(run("(car (cdr '(1 2 3)))"), Val::Num(2));
209    }
210
211    #[test]
212    fn an_imported_frame_brings_its_names_into_scope() {
213        assert_eq!(
214            run("(define (arith base)
215                   (list (cons 'up (lambda u (n) (+ n base)))
216                         (cons 'down (lambda d (n) (- n base)))))
217                 (import (arith 10))
218                 (down (up 5))"),
219            Val::Num(5)
220        );
221    }
222
223    #[test]
224    fn an_import_nests_like_every_other_binding() {
225        assert_eq!(
226            run("(define x 1)
227                 (import (list (cons 'x 2)))
228                 (define x 3)
229                 x"),
230            Val::Num(3)
231        );
232        assert_eq!(
233            run("(define x 1)
234                 (import (list (cons 'x 2)))
235                 x"),
236            Val::Num(2)
237        );
238    }
239
240    #[test]
241    fn an_imported_semantics_is_a_value_and_not_an_installation() {
242        assert_eq!(
243            run(&format!(
244                "(define shifting (list (cons 'M {SHIFT})))
245                 (import shifting)
246                 (let ((f (lambda f (n) (+ n 1))))
247                   (cons (f 0) ((with-interp f (M (interp-of f))) 0)))"
248            )),
249            pair(Val::Num(1), Val::Num(11))
250        );
251    }
252
253    #[test]
254    fn an_import_needs_something_to_import_into() {
255        let forms = crate::floor::read::read("(import (list))").expect("reads");
256        assert!(crate::surface::desugar_body(&forms).is_err());
257    }
258
259    #[test]
260    fn a_compiled_function_agrees_with_the_interpreted_one() {
261        let src = |kw: &str| {
262            format!(
263                "(let ((fib ({kw} fib (n)
264                              (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))))
265                   (fib 10))"
266            )
267        };
268        assert_eq!(run(&src("lambda")), Val::Num(55));
269        assert_eq!(run(&src("clambda")), Val::Num(55));
270    }
271
272    #[test]
273    fn an_interpreter_is_a_value_a_function_can_alter() {
274        let mut t = Tower::load().expect("loads");
275        let shift = t
276            .run_source(
277                // Floor source, so the handler reaches into the
278                // continuation's representation rather than calling
279                // `apply-cont`: `('cont f . h)`, and this one never
280                // raises.
281                "(lambda M (m)
282                   (cons (cons 'eval-lit
283                               (lambda h (m l e r k)
284                                 ((car (cdr k)) (+ e 1))))
285                         m))",
286            )
287            .expect("no fault");
288        let base = t.get("m").expect("no fault");
289        let altered = t.call(&shift, &[base]).expect("no fault");
290
291        let p = prog("(+ 1 1)");
292        assert_eq!(t.eval_under(&altered, &p), Ok(Val::Num(4)));
293        assert_eq!(t.eval(&p), Ok(Val::Num(2)));
294    }
295
296    fn shift(n: i64) -> Val {
297        prog(&format!("(lambda h (m l e r k) (apply-cont k (+ e {n})))"))
298    }
299
300    fn with_lit(t: &mut Tower, h: Val) -> Val {
301        assert!(matches!(&h, Val::Pair(a, _) if **a == Val::Sym("clo".into())));
302        let entry = Val::Pair(rc_val(Val::Sym("eval-lit".into())), rc_val(h));
303        Val::Pair(rc_val(entry), rc_val(t.get("m").expect("no fault")))
304    }
305
306    fn shifted(t: &mut Tower) -> Val {
307        let h = t.eval(&shift(1)).expect("no fault");
308        with_lit(t, h)
309    }
310
311    #[test]
312    fn an_object_level_handler_materializes_the_level_above_it() {
313        let mut t = Tower::load().expect("loads");
314        let altered = shifted(&mut t);
315
316        let p = prog("(+ 1 1)");
317        assert_eq!(t.eval_under(&altered, &p), Ok(Val::Num(4)));
318        assert_eq!(t.eval(&p), Ok(Val::Num(2)));
319    }
320
321    #[test]
322    fn a_materialized_level_leaves_no_trace_in_the_residual() {
323        let mut t = Tower::load().expect("loads");
324        let altered = shifted(&mut t);
325        let p = prog("(clambda f (n) (+ n 1))");
326        let out = t.compile_under(&altered, &p).expect("no fault");
327        match out {
328            Val::Code(e) => assert_eq!(format!("{e}"), "(let (lambda (let (+ x1 2) x2)) x0)"),
329            other => panic!("expected code, got {other}"),
330        }
331    }
332
333    #[test]
334    fn a_level_is_interpreted_by_the_one_that_wrote_it() {
335        let mut t = Tower::load().expect("loads");
336
337        let h2 = t.eval(&shift(1)).expect("no fault");
338        let m2 = with_lit(&mut t, h2);
339        let h1 = t.eval_under(&m2, &shift(10)).expect("no fault");
340        let m1 = with_lit(&mut t, h1);
341
342        assert_eq!(t.eval_under(&m1, &prog("(+ 1 1)")), Ok(Val::Num(24)));
343    }
344
345    #[test]
346    fn call_cc_is_an_ordinary_definition_in_the_object_language() {
347        assert_eq!(run("(+ 1 (call/cc (lambda (k) (k 5))))"), Val::Num(6));
348        assert_eq!(
349            run("(+ 1 (call/cc (lambda (k) (+ 100 (k 5)))))"),
350            Val::Num(6)
351        );
352        // Not escaping: the continuation is ignored and the body's value
353        // is returned the ordinary way.
354        assert_eq!(run("(+ 1 (call/cc (lambda (k) 5)))"), Val::Num(6));
355    }
356
357    #[test]
358    fn a_prompt_bounds_the_continuation_reified_under_it() {
359        assert_eq!(
360            run("(* 10 (prompt (lambda () (+ 1 (call/cc (lambda (k) (+ 100 (k 5))))))))"),
361            Val::Num(60)
362        );
363        // `abort` needs no continuation to have been reified: it hands
364        // its value to the prompt and abandons everything between.
365        assert_eq!(
366            run("(* 10 (prompt (lambda () (+ 1 (abort 5)))))"),
367            Val::Num(50)
368        );
369    }
370
371    #[test]
372    fn a_reflective_call_site_stages_away() {
373        let mut t = Tower::load().expect("loads");
374        let p = prog("(clambda f (n) (+ 1 (call/cc (lambda (k) (+ 100 (k n))))))");
375        match t.compile(&p).expect("no fault") {
376            Val::Code(e) => assert_eq!(format!("{e}"), "(let (lambda (let (+ 1 x1) x2)) x0)"),
377            other => panic!("expected code, got {other}"),
378        }
379    }
380
381    fn residual(text: &str) -> String {
382        let mut t = Tower::load().expect("loads");
383        match t.compile(&prog(text)).expect("no fault") {
384            Val::Code(e) => format!("{e}"),
385            other => panic!("expected code, got {other}"),
386        }
387    }
388
389    #[test]
390    fn a_residual_is_floor_code_in_anf() {
391        assert_eq!(
392            residual("(clambda f (n) (+ n 1))"),
393            "(let (lambda (let (+ x1 1) x2)) x0)"
394        );
395    }
396
397    #[test]
398    fn a_compiled_function_keeps_the_arity_it_was_written_at() {
399        assert_eq!(
400            residual("(clambda g (a b) (+ (* a b) 1))"),
401            "(let (lambda/2 (let (* x1 x2) (let (+ x3 1) x4))) x0)"
402        );
403    }
404
405    #[test]
406    fn recursion_and_a_staged_conditional_survive_compilation() {
407        assert_eq!(
408            residual("(clambda fib (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))"),
409            "(let (lambda (let (< x1 2) (let (if x2 x1 \
410             (let (- x1 1) (let (x0 x3) (let (- x1 2) \
411             (let (x0 x5) (let (+ x4 x6) x7)))))) x3))) x0)"
412        );
413    }
414
415    #[test]
416    fn a_residual_carries_the_semantics_it_was_compiled_under() {
417        let mut t = Tower::load().expect("loads");
418        let base = t.get("m").expect("base interpreter");
419        // Every literal comes out a hundred larger, and the addition that
420        // does it happens while compiling: both its operands are
421        // constants, so nothing about the site is staged and there is
422        // nothing to emit.
423        let marked = {
424            let h = t
425                .eval(&prog("(lambda h (m l e r k) (apply-cont k (+ e 100)))"))
426                .expect("handler evaluates");
427            pair(pair(sym("eval-lit"), h), base.clone())
428        };
429
430        let src = prog("(clambda f (n) (+ n 1))");
431        let show = |v: Val| match v {
432            Val::Code(e) => format!("{e}"),
433            other => panic!("expected code, got {other}"),
434        };
435        assert_eq!(
436            show(t.compile_under(&base, &src).expect("no fault")),
437            "(let (lambda (let (+ x1 1) x2)) x0)"
438        );
439        assert_eq!(
440            show(t.compile_under(&marked, &src).expect("no fault")),
441            "(let (lambda (let (+ x2 101) x3)) x1)"
442        );
443
444        // And the same through `run`, where what comes back is applicable.
445        let get = "(let ((f (clambda f (n) (+ n 1)))) f)";
446        let f = t.eval_under(&base, &prog(get)).expect("no fault");
447        let g = t.eval_under(&marked, &prog(get)).expect("no fault");
448        assert_eq!(t.call(&f, &[Val::Num(1)]).expect("no fault"), Val::Num(2));
449        assert_eq!(t.call(&g, &[Val::Num(1)]).expect("no fault"), Val::Num(102));
450    }
451
452    #[test]
453    fn a_clambda_that_ran_is_tagged_as_compiled() {
454        let mut t = Tower::load().expect("loads");
455        // Staged it stays code, so the tag distinguishes only the run case -
456        // where the value is a floor closure and would otherwise be taken for
457        // a primitive by the call site.
458        let f = t
459            .eval(&prog("(let ((f (clambda f (n) (+ n 1)))) f)"))
460            .expect("no fault");
461        assert!(matches!(&f, Val::Pair(h, t)
462            if **h == sym("cfun") && matches!(&**t, Val::Clo(_, _))));
463        assert_eq!(t.call(&f, &[Val::Num(1)]).expect("no fault"), Val::Num(2));
464    }
465
466    #[test]
467    fn a_call_to_an_operator_the_site_does_not_know_dispatches_at_run_time() {
468        // The emitted decision, in full: the operand list is built, and
469        // the four things `static-apply` needs ride in as persisted
470        // values rather than as syntax.
471        assert_eq!(
472            residual("(clambda f (g n) (g n))"),
473            "(let (lambda/2 (let (cons x2 ()) \
474             (let (#<closure> #<closure> x1 x3 #<('cont #<closure> . #<closure>)>) x4))) x0)"
475        );
476
477        for op in ["lambda", "clambda"] {
478            let src = format!("(let ((f ({op} f (g n) (g n)))) (f {{}} 5))");
479            // An interpreted callee and a compiled one: one call site, two
480            // representations, and the answer does not depend on which
481            // arrives.
482            for arg in ["(lambda h (x) (+ x 1))", "(clambda h (x) (+ x 1))"] {
483                assert_eq!(run(&src.replace("{}", arg)), Val::Num(6), "{op} {arg}");
484            }
485            // A primitive is a floor closure, so it goes through the same
486            // arm a compiled function does.
487            assert_eq!(
488                run(&format!("(let ((f ({op} f (g n) (g n 1)))) (f + 5))")),
489                Val::Num(6)
490            );
491            // And a value that is not applicable at all fails the same
492            // way it does interpreted, rather than failing to compile.
493            let Val::Raise(v) = run(&src.replace("{}", "7")) else {
494                panic!("expected a raise from {op}");
495            };
496            assert_eq!(v.to_string(), "('cannot-apply . 7)");
497        }
498    }
499
500    #[test]
501    fn a_compiled_combinator_runs_its_callee_under_the_callees_own_semantics() {
502        let map = "(let ((map (clambda map (f xs) \
503                    (if (nil? xs) '() (cons (f (car xs)) (map f (cdr xs)))))))";
504        assert_eq!(
505            run(&format!("{map} (map (lambda h (x) (* x 2)) '(1 2 3)))")),
506            run("'(2 4 6)")
507        );
508
509        // The same callee under an interpreter where a literal is worth a
510        // hundred more than it says. Nothing about the compiled `map`
511        // changed, and it was compiled before the alteration existed.
512        let hundred = "(let ((louder (lambda a (m) \
513                       (cons (cons 'eval-lit \
514                             (lambda h (m l e r k) (apply-cont k (+ e 100)))) m))))";
515        let dbl = "(lambda h (x) (* x 2))";
516        assert_eq!(
517            run(&format!(
518                "{map} {hundred} (let ((d {dbl})) \
519                 (map (with-interp d (louder (interp-of d))) '(1 2 3)))))"
520            )),
521            run("'(102 204 306)")
522        );
523    }
524
525    #[test]
526    fn a_closure_made_while_staging_is_not_a_value_to_persist() {
527        let mk = |body: &str| {
528            format!("(let ((f (clambda f (g n) (g (lambda h (x) {body}))))) ((f (lambda i (c) c) 1) 10))")
529        };
530        for body in ["(+ x n)", "(+ x 1)"] {
531            let Val::Raise(v) = run(&mk(body)) else {
532                panic!("expected a raise from {body}");
533            };
534            assert_eq!(v.to_string(), "('unpersistable . 'pair)", "{body}");
535        }
536        // The operand that is *not* built here still crosses: it arrives
537        // as code and stays code.
538        assert_eq!(
539            run("(let ((f (clambda f (g n) (g n)))) (f (lambda h (x) (+ x 1)) 5))"),
540            Val::Num(6)
541        );
542    }
543
544    #[test]
545    fn a_closure_is_not_a_result_a_compiled_region_can_give_back() {
546        // Alone; as a leaf of a structure the region does build; and in
547        // one arm of a staged conditional, which is the same boundary
548        // reached a third way.
549        for body in [
550            "(lambda h (x) (+ x n))",
551            "(cons 1 (lambda h (x) x))",
552            "(if (< n 2) (lambda h (x) x) 0)",
553        ] {
554            let p = format!("(let ((f (clambda f (n) {body}))) (f 1))");
555            let Val::Raise(v) = run(&p) else {
556                panic!("expected a raise from {body}");
557            };
558            assert_eq!(v.to_string(), "('unreturnable . 'closure)", "{body}");
559        }
560    }
561
562    #[test]
563    fn a_reflective_operator_cannot_arrive_at_a_compiled_call_site() {
564        let bind = "(let ((r (lambda reflect (m l e r k) (apply-cont k (car e)))))";
565        let tag = |src: String| {
566            let Val::Raise(v) = run(&src) else {
567                panic!("expected a raise from {src}");
568            };
569            let Val::Pair(t, _) = &*v else {
570                panic!("expected a tagged raise, got {v}");
571            };
572            Val::clone(t)
573        };
574        // Interpreted, the operand arrives as syntax and is never
575        // evaluated. Compiled, it was evaluated before anything looked at
576        // the operator — which is why the site is gone by the dispatch.
577        assert_eq!(
578            run(&format!("{bind} (let ((f (lambda f (g) (g zzz)))) (f r)))")),
579            sym("zzz")
580        );
581        assert_eq!(
582            tag(format!("{bind} (let ((f (clambda f (g) (g zzz)))) (f r)))")),
583            sym("unbound")
584        );
585        // With an operand that does evaluate, the dispatch is reached and
586        // names what it cannot do.
587        assert_eq!(
588            run(&format!("{bind} (let ((f (lambda f (g) (g 1)))) (f r)))")),
589            Val::Num(1)
590        );
591        assert_eq!(
592            tag(format!("{bind} (let ((f (clambda f (g) (g 1)))) (f r)))")),
593            sym("no-call-site")
594        );
595    }
596
597    #[test]
598    fn a_compiled_region_can_answer_with_a_pair() {
599        assert_eq!(
600            residual("(clambda f (n) (cons n 1))"),
601            "(let (lambda (let (cons x1 1) x2)) x0)"
602        );
603        assert_eq!(
604            residual("(clambda f (n) (cons n '(1 2)))"),
605            "(let (lambda (let (cons 2 ()) (let (cons 1 x2) \
606             (let (cons x1 x3) x4)))) x0)"
607        );
608        assert_eq!(
609            run("(let ((f (clambda f (n) (cons n '(1 2))))) (f 7))"),
610            run("(let ((f (lambda f (n) (cons n '(1 2))))) (f 7))")
611        );
612    }
613
614    #[test]
615    fn each_arm_of_a_staged_conditional_builds_its_own_structure() {
616        assert_eq!(
617            run("(let ((f (clambda f (n) (if (< n 2) '(a) '(b c))))) (f 7))"),
618            run("(let ((f (lambda f (n) (if (< n 2) '(a) '(b c))))) (f 7))")
619        );
620    }
621
622    #[test]
623    fn a_handler_can_put_a_value_into_the_residual_that_nothing_else_would() {
624        let mut t = Tower::load().expect("loads");
625        let base = t.get("m").expect("base interpreter");
626        let marked = {
627            let h = t
628                .eval(&prog(
629                    "(lambda h (m l e r k) (apply-cont k (+ e ((l 'lift) 100))))",
630                ))
631                .expect("handler evaluates");
632            pair(pair(sym("eval-lit"), h), base)
633        };
634        let src = prog("(clambda f (n) (+ n 1))");
635        let Val::Code(e) = t.compile_under(&marked, &src).expect("no fault") else {
636            panic!("expected code");
637        };
638        assert_eq!(
639            format!("{e}"),
640            "(let (lambda (let (+ 1 100) (let (+ x1 x2) x3))) x0)"
641        );
642    }
643
644    #[test]
645    fn a_compiled_region_inlines_interpreted_code_and_calls_compiled_code() {
646        assert_eq!(
647            residual("(let ((g (lambda g (x) (+ x 1)))) (clambda f (n) (g (g n))))"),
648            "(let (lambda (let (+ x1 1) (let (+ x2 1) x3))) x0)"
649        );
650        assert_eq!(
651            residual("(let ((g (clambda g (x) (+ x 1)))) (clambda f (n) (g (g n))))"),
652            "(let (lambda (let (+ x1 1) x2)) \
653             (let (lambda (let (x0 x2) (let (x0 x3) x4))) x1))"
654        );
655    }
656
657    #[test]
658    fn a_host_value_compiles_to_the_answer_it_interprets() {
659        let body = "(s) (if (eq? s \"x\") 1 0)";
660        assert_eq!(
661            run(&format!("(let ((f (lambda f {body}))) (f \"x\"))")),
662            Val::Num(1)
663        );
664        assert_eq!(
665            run(&format!("(let ((f (clambda f {body}))) (f \"x\"))")),
666            Val::Num(1)
667        );
668        assert_eq!(
669            residual(&format!("(clambda f {body})")),
670            "(let (lambda (let (eq? x1 \"x\") (let (if x2 1 0) x3))) x0)"
671        );
672    }
673
674    #[test]
675    fn an_interpreted_recursive_callee_is_refused_rather_than_unfolded() {
676        let mut t = Tower::load().expect("loads");
677        let out = t.compile(&prog(
678            "(let ((g (lambda g (x) (if (< x 1) 0 (g (- x 1))))))
679               (clambda f (n) (g n)))",
680        ));
681        assert_eq!(
682            out,
683            Ok(crate::floor::raise(list(&[
684                sym("inlines-forever"),
685                sym("g")
686            ])))
687        );
688    }
689
690    #[test]
691    fn a_refused_cycle_names_every_function_on_it() {
692        let mut t = Tower::load().expect("loads");
693        let out = t.compile(&prog(
694            "(let ((h (lambda h (y g) (g y h))))
695               (let ((g (lambda g (x h) (h x g))))
696                 (clambda f (n) (g n h))))",
697        ));
698        assert_eq!(
699            out,
700            Ok(crate::floor::raise(list(&[
701                sym("inlines-forever"),
702                sym("g"),
703                sym("h")
704            ])))
705        );
706    }
707
708    #[test]
709    fn a_recursion_over_static_data_still_unfolds() {
710        assert_eq!(
711            residual(
712                "(let ((walk (lambda walk (xs n)
713                               (if (nil? xs) n (walk (cdr xs) (+ n 1))))))
714                   (clambda f (n) (walk '(1 2 3) n)))"
715            ),
716            "(let (lambda (let (+ x1 1) (let (+ x2 1) (let (+ x3 1) x4)))) x0)"
717        );
718    }
719
720    #[test]
721    fn a_constant_joins_a_residual_wherever_it_came_from() {
722        assert_eq!(
723            residual("(clambda f (n) (+ n (car '(7 8))))"),
724            "(let (lambda (let (+ x1 7) x2)) x0)"
725        );
726    }
727
728    #[test]
729    fn a_task_is_an_object_program_and_the_address_it_was_given() {
730        let mut t = Tower::load().expect("loads");
731        let entry = t.task(&prog("self")).expect("no fault");
732
733        let mut h = Heap::new(1000);
734        let id = h.spawn(entry);
735        h.run().expect("no bug");
736        assert_eq!(h.take_exits(), vec![(id, ok(addr(id)))]);
737    }
738
739    const SHIFT: &str = "(lambda M (i)
740                           (with-handler i 'eval-lit
741                             (lambda h (m l e r k) (apply-cont k (+ e 10)))))";
742
743    #[test]
744    fn a_procedures_interpreter_is_a_value_that_can_be_replaced() {
745        assert_eq!(
746            run(&format!(
747                "(let ((f (lambda f (n) (+ n 1))))
748                   (cons (f 0)
749                         ((with-interp f ({SHIFT} (interp-of f))) 0)))"
750            )),
751            Val::Pair(rc_val(Val::Num(1)), rc_val(Val::Num(11)))
752        );
753    }
754
755    #[test]
756    fn the_interpreter_in_force_is_readable_as_a_value() {
757        assert_eq!(
758            run(&format!(
759                "(let ((i ({SHIFT} (interpreter))))
760                   ((with-interp (lambda f (n) (+ n 1)) i) 0))"
761            )),
762            Val::Num(11)
763        );
764    }
765
766    #[test]
767    fn a_program_can_be_evaluated_in_an_environment_it_is_handed() {
768        assert_eq!(
769            run("(let ((r (env-extend (environment) 'x 20)))
770                   (eval-in r (desugar-body (read \"(+ x 2)\"))))"),
771            Val::Num(22)
772        );
773    }
774
775    #[test]
776    fn a_protected_region_reports_which_way_it_ended() {
777        assert_eq!(
778            run("(cons (attempt (lambda () (+ 1 2)))
779                       (attempt (lambda () (throw 'boom))))"),
780            pair(
781                pair(sym("ok"), Val::Num(3)),
782                pair(sym("throw"), sym("boom"))
783            )
784        );
785    }
786
787    #[test]
788    fn a_raise_stops_at_the_nearest_protected_region() {
789        assert_eq!(
790            run("(attempt (lambda ()
791                   (+ 1 (cdr (attempt (lambda () (throw 7)))))))"),
792            pair(sym("ok"), Val::Num(8))
793        );
794    }
795
796    #[test]
797    fn a_call_to_a_task_that_dies_raises_at_the_call_site() {
798        let mut t = Tower::load().expect("loads");
799        let entry = t
800            .task(&prog(
801                "(task-loop self
802                            (lambda h (st msg)
803                              (let ((child (spawn (lambda c (me)
804                                                    (begin (receive)
805                                                           (throw 'boom))))))
806                                (cons 'stop
807                                      (attempt (lambda () (call child 'ping))))))
808                            0)",
809            ))
810            .expect("no fault");
811
812        let mut h = Heap::new(100_000);
813        let id = h.spawn(entry);
814        h.post(&addr(id), sym("go"));
815        h.run().expect("no bug");
816        assert_eq!(
817            h.take_exits(),
818            vec![
819                (1, pair(sym("throw"), sym("boom"))),
820                (
821                    id,
822                    ok(pair(
823                        sym("throw"),
824                        pair(
825                            sym("callee-down"),
826                            pair(addr(1), pair(sym("throw"), sym("boom")))
827                        )
828                    ))
829                ),
830            ]
831        );
832    }
833
834    #[test]
835    fn a_death_the_handler_asked_about_reaches_the_handler() {
836        let mut t = Tower::load().expect("loads");
837        let entry = t
838            .task(&prog(
839                "(task-loop self
840                            (lambda h (st msg)
841                              (if (tagged? msg 'task-down)
842                                  (cons 'stop msg)
843                                  (let ((child (spawn (lambda c (me)
844                                                        (begin (receive) 7)))))
845                                    (begin (monitor child)
846                                           (begin (send child 'go) st)))))
847                            0)",
848            ))
849            .expect("no fault");
850
851        let mut h = Heap::new(100_000);
852        let id = h.spawn(entry);
853        h.post(&addr(id), sym("go"));
854        h.run().expect("no bug");
855        assert_eq!(
856            h.take_exits(),
857            vec![
858                (1, ok(Val::Num(7))),
859                (
860                    id,
861                    ok(pair(sym("task-down"), pair(addr(1), ok(Val::Num(7)))))
862                ),
863            ]
864        );
865    }
866
867    #[test]
868    fn a_supervisor_restarts_a_child_and_then_gives_up() {
869        let mut t = Tower::load().expect("loads");
870        let entry = t
871            .task(&prog(
872                "(supervise self (list (cons 'kid (cons 1 (lambda c (me) (throw 'boom))))))",
873            ))
874            .expect("no fault");
875
876        let mut h = Heap::new(100_000);
877        let id = h.spawn(entry);
878        h.post(&addr(id), sym("go"));
879        h.run().expect("no bug");
880        assert_eq!(
881            h.take_exits(),
882            vec![
883                (1, pair(sym("throw"), sym("boom"))),
884                (2, pair(sym("throw"), sym("boom"))),
885                (
886                    id,
887                    ok(pair(
888                        sym("give-up"),
889                        pair(sym("kid"), pair(sym("throw"), sym("boom")))
890                    ))
891                ),
892            ]
893        );
894    }
895
896    #[test]
897    fn a_child_that_returns_is_not_restarted() {
898        let mut t = Tower::load().expect("loads");
899        let entry = t
900            .task(&prog(
901                "(supervise self (list (cons 'kid (cons 3 (lambda c (me) 7)))))",
902            ))
903            .expect("no fault");
904
905        let mut h = Heap::new(100_000);
906        let id = h.spawn(entry);
907        h.post(&addr(id), sym("go"));
908        h.run().expect("no bug");
909        assert_eq!(
910            h.take_exits(),
911            vec![(1, ok(Val::Num(7))), (id, ok(sym("all-done")))]
912        );
913    }
914
915    #[test]
916    fn a_task_that_never_reaches_receive_is_ended() {
917        let mut t = Tower::load().expect("loads");
918        let entry = t
919            .task(&prog(
920                "(task-loop self
921                            (lambda h (st msg)
922                              (if (tagged? msg 'task-down)
923                                  (cons 'stop msg)
924                                  (let ((child (spawn-monitor
925                                                (lambda c (me)
926                                                  ((lambda f (x) (f x)) 0)))))
927                                    (begin (limit-turns child 2) st))))
928                            0)",
929            ))
930            .expect("no fault");
931
932        let mut h = Heap::new(10_000);
933        let id = h.spawn(entry);
934        h.post(&addr(id), sym("go"));
935        h.run().expect("no bug");
936        assert_eq!(
937            h.take_exits(),
938            vec![
939                (1, pair(sym("throw"), sym("unresponsive"))),
940                (
941                    id,
942                    ok(pair(
943                        sym("task-down"),
944                        pair(addr(1), pair(sym("throw"), sym("unresponsive")))
945                    ))
946                ),
947            ]
948        );
949    }
950
951    #[test]
952    fn spawn_with_forks_the_semantics_rather_than_sharing_it() {
953        let mut t = Tower::load().expect("loads");
954        let entry = t
955            .task(&prog(&format!(
956                "(begin (spawn-with {SHIFT} (lambda c (me) (send '(host child) (+ 0 1))))
957                        (send '(host parent) (+ 0 1)))"
958            )))
959            .expect("no fault");
960
961        let mut h = Heap::new(200_000);
962        h.spawn(entry);
963        h.run().expect("no bug");
964        assert_eq!(
965            h.take_away(),
966            vec![(host("parent"), Val::Num(1)), (host("child"), Val::Num(21)),]
967        );
968    }
969
970    #[test]
971    fn become_changes_what_the_next_message_means() {
972        let mut t = Tower::load().expect("loads");
973        let src = prog(&format!(
974            "(task-loop self
975                        (lambda h (st msg)
976                          (cond ((tagged? msg 'shift) (become {SHIFT} st))
977                                ((tagged? msg 'ask) (cons 'stop (+ 0 1)))
978                                (else st)))
979                        0)"
980        ));
981        let ending_with = |t: &mut Tower, msgs: &[&str]| {
982            let mut h = Heap::new(100_000);
983            let id = h.spawn(t.task(&src).expect("no fault"));
984            for m in msgs {
985                h.post(&addr(id), list(&[Val::Sym((*m).into())]));
986            }
987            h.run().expect("no bug");
988            h.take_exits()
989        };
990
991        assert_eq!(ending_with(&mut t, &["ask"]), vec![(0, ok(Val::Num(1)))]);
992        assert_eq!(
993            ending_with(&mut t, &["shift", "ask"]),
994            vec![(0, ok(Val::Num(21)))]
995        );
996    }
997
998    #[test]
999    fn an_object_procedure_can_be_spawned() {
1000        let mut t = Tower::load().expect("loads");
1001        let entry = t
1002            .task(&prog("(spawn (lambda c (me) (send '(host child) me)))"))
1003            .expect("no fault");
1004
1005        let mut h = Heap::new(10_000);
1006        let parent = h.spawn(entry);
1007        h.run().expect("no bug");
1008
1009        let child = addr(1);
1010        assert_eq!(
1011            h.take_away(),
1012            vec![(
1013                list(&[Val::Sym("host".into()), Val::Sym("child".into())]),
1014                child.clone()
1015            )]
1016        );
1017        assert_eq!(h.take_exits(), vec![(parent, ok(child)), (1, ok(Val::Nil))]);
1018    }
1019
1020    #[test]
1021    fn a_call_suspends_a_task_rather_than_blocking_it() {
1022        let mut t = Tower::load().expect("loads");
1023        let server = t
1024            .task(&prog(
1025                "(task-loop self
1026                            (lambda h (st msg) (begin (reply msg (* 2 (cadddr msg))) st))
1027                            0)",
1028            ))
1029            .expect("no fault");
1030        let client = t
1031            .task(&prog(
1032                "(task-loop self
1033                            (lambda h (st msg) (cons 'stop (+ 1 (call (cadr msg) 20))))
1034                            0)",
1035            ))
1036            .expect("no fault");
1037
1038        let mut h = Heap::new(10_000);
1039        let s = h.spawn(server);
1040        let c = h.spawn(client);
1041        h.post(&addr(c), list(&[Val::Sym("go".into()), addr(s)]));
1042        h.run().expect("no bug");
1043
1044        // The server is still looping, so the only task that ended is the
1045        // caller - with the value its suspended call site computed.
1046        assert_eq!(h.take_exits(), vec![(c, ok(Val::Num(41)))]);
1047    }
1048
1049    #[test]
1050    fn a_message_arriving_mid_turn_waits_for_it() {
1051        let mut t = Tower::load().expect("loads");
1052        let server = t
1053            .task(&prog(
1054                "(task-loop self
1055                            (lambda h (st msg) (begin (reply msg (* 2 (cadddr msg))) st))
1056                            0)",
1057            ))
1058            .expect("no fault");
1059        let client = t
1060            .task(&prog(
1061                "(task-loop self
1062                            (lambda h (st msg)
1063                              (cond ((tagged? msg 'note)
1064                                     (begin (send '(host seen) st) (cons 'stop st)))
1065                                    ((tagged? msg 'go) (+ st (call (cadr msg) 20)))
1066                                    (else st)))
1067                            0)",
1068            ))
1069            .expect("no fault");
1070
1071        let mut h = Heap::new(10_000);
1072        let s = h.spawn(server);
1073        let c = h.spawn(client);
1074        h.post(&addr(c), list(&[Val::Sym("go".into()), addr(s)]));
1075        h.post(&addr(c), list(&[Val::Sym("note".into())]));
1076        h.run().expect("no bug");
1077
1078        assert_eq!(
1079            h.take_away(),
1080            vec![(
1081                list(&[Val::Sym("host".into()), Val::Sym("seen".into())]),
1082                Val::Num(40)
1083            )]
1084        );
1085        assert_eq!(h.take_exits(), vec![(c, ok(Val::Num(40)))]);
1086    }
1087
1088    #[test]
1089    fn a_turn_may_hand_the_task_over_and_the_backlog_goes_with_it() {
1090        let mut t = Tower::load().expect("loads");
1091        let node = t
1092            .task(&prog(
1093                "(task-loop self
1094                            (lambda h (st msg)
1095                              (let ((kid (spawn (lambda (me)
1096                                                  (begin (send self (list 'register 'kid me))
1097                                                         (task-loop me
1098                                                                    (lambda k (s2 m2) s2)
1099                                                                    0))))))
1100                                (let ((_ (call '(host tick) 'wait)))
1101                                  (hand greeter '()))))
1102                            0)",
1103            ))
1104            .expect("no fault");
1105        let asker = t
1106            .task(&prog(
1107                "(task-loop self
1108                            (lambda h (st msg) (cons 'stop (call (cadr msg) '(names))))
1109                            0)",
1110            ))
1111            .expect("no fault");
1112
1113        let mut h = Heap::new(100_000);
1114        let n = h.spawn(node);
1115        let a = h.spawn(asker);
1116        // The child's registration has to be in flight while the node is
1117        // still setting up, which is what the `tick` call and the reply
1118        // below arrange: nothing answers `tick`, so the first run ends
1119        // with the node suspended and the registration waiting.
1120        h.post(&addr(n), Val::Sym("go".into()));
1121        h.run().expect("no bug");
1122        h.post(
1123            &addr(n),
1124            list(&[Val::Sym("reply".into()), Val::Num(1), Val::Nil]),
1125        );
1126        h.post(&addr(a), list(&[Val::Sym("go".into()), addr(n)]));
1127        h.run().expect("no bug");
1128
1129        assert_eq!(
1130            h.take_exits(),
1131            vec![(a, ok(list(&[Val::Sym("kid".into())])))]
1132        );
1133    }
1134
1135    #[test]
1136    fn a_task_calling_itself_is_refused_rather_than_left_to_park() {
1137        let mut t = Tower::load().expect("loads");
1138        let entry = t
1139            .task(&prog(
1140                "(task-loop self
1141                            (lambda h (st msg) (cons 'stop (call self '(anything))))
1142                            0)",
1143            ))
1144            .expect("no fault");
1145
1146        let mut h = Heap::new(10_000);
1147        let id = h.spawn(entry);
1148        h.post(&addr(id), Val::Sym("go".into()));
1149        h.run().expect("no bug");
1150
1151        let sym = |s: &str| Val::Sym(s.into());
1152        assert_eq!(
1153            h.take_exits(),
1154            vec![(
1155                id,
1156                Val::Pair(
1157                    rc_val(sym("throw")),
1158                    rc_val(pair(sym("self-call"), list(&[sym("anything")])))
1159                )
1160            )]
1161        );
1162    }
1163
1164    #[test]
1165    fn a_reference_holds_a_value_and_survives_a_request_it_does_not_know() {
1166        let mut t = Tower::load().expect("loads");
1167        let driver = t
1168            .task(&prog(
1169                "(task-loop self
1170                            (lambda h (st msg)
1171                              (let ((c (spawn (lambda (me) (ref me 0)))))
1172                                (let ((first (call c '(read))))
1173                                  (let ((_ (call c '(write 42))))
1174                                    (let ((bad (attempt (lambda () (call c '(oops))))))
1175                                      (cons 'stop
1176                                            (list first bad (call c '(read)))))))))
1177                            0)",
1178            ))
1179            .expect("no fault");
1180
1181        let mut h = Heap::new(100_000);
1182        let d = h.spawn(driver);
1183        h.post(&addr(d), Val::Sym("go".into()));
1184        h.run().expect("no bug");
1185
1186        let sym = |s: &str| Val::Sym(s.into());
1187        // The reference is still looping, so the driver is the only exit.
1188        assert_eq!(
1189            h.take_exits(),
1190            vec![(
1191                d,
1192                ok(list(&[
1193                    Val::Num(0),
1194                    list(&[sym("throw"), sym("bad-request"), sym("oops")]),
1195                    Val::Num(42),
1196                ]))
1197            )]
1198        );
1199    }
1200
1201    #[test]
1202    fn the_list_library_computes() {
1203        assert_eq!(run("(length (append '(1 2) '(3 4)))"), Val::Num(4));
1204        assert_eq!(run("(nth 0 (reverse '(1 2 3)))"), Val::Num(3));
1205        assert_eq!(
1206            run("(fold (lambda (a x) (+ a x)) 0 (filter (lambda (x) (> x 2)) '(1 2 3 4)))"),
1207            Val::Num(7)
1208        );
1209        assert_eq!(
1210            run("(last (map (lambda (x) (* x x)) '(1 2 3)))"),
1211            Val::Num(9)
1212        );
1213        assert_eq!(
1214            run("(foldr (lambda (x a) (cons x a)) '() '(1 2))"),
1215            list(&[Val::Num(1), Val::Num(2)])
1216        );
1217    }
1218
1219    #[test]
1220    fn an_index_past_the_end_raises() {
1221        let sym = |s: &str| Val::Sym(s.into());
1222        assert_eq!(
1223            run("(attempt (lambda () (nth 9 '(1))))"),
1224            pair(sym("throw"), pair(sym("no-such-index"), Val::Num(9)))
1225        );
1226        assert_eq!(
1227            run("(attempt (lambda () (last '())))"),
1228            pair(sym("throw"), sym("empty-list"))
1229        );
1230    }
1231
1232    #[test]
1233    fn a_mapped_effect_runs_front_to_back() {
1234        let mut t = Tower::load().expect("loads");
1235        let entry = t
1236            .task(&prog("(map (lambda (x) (send '(host trace) x)) '(1 2 3))"))
1237            .expect("no fault");
1238
1239        let mut h = Heap::new(100_000);
1240        h.spawn(entry);
1241        h.run().expect("no bug");
1242        assert_eq!(
1243            h.take_away(),
1244            vec![
1245                (host("trace"), Val::Num(1)),
1246                (host("trace"), Val::Num(2)),
1247                (host("trace"), Val::Num(3)),
1248            ]
1249        );
1250    }
1251
1252    #[test]
1253    fn the_comparisons_derive_from_the_one_the_floor_has() {
1254        assert_eq!(
1255            run("(list (> 2 1) (< 2 1) (<= 2 2) (>= 1 2) (= 3 3) (not 0))"),
1256            list(&[
1257                Val::Num(1),
1258                Val::Num(0),
1259                Val::Num(1),
1260                Val::Num(0),
1261                Val::Num(1),
1262                Val::Num(1)
1263            ])
1264        );
1265    }
1266
1267    #[test]
1268    fn text_is_taken_apart_and_put_back_together() {
1269        assert_eq!(run(r#"(join "-" (split "a.b.c" "."))"#), Str::val("a-b-c"));
1270        assert_eq!(run(r#"(str-at "abc" 1)"#), Str::val("b"));
1271        assert_eq!(run(r#"(substr "abc" 1 99)"#), Str::val("bc"));
1272        assert_eq!(run(r#"(length (split "" "."))"#), Val::Num(1));
1273        assert_eq!(run(r#"(eq? (str->sym "kid") 'kid)"#), Val::Num(1));
1274    }
1275
1276    #[test]
1277    fn a_search_that_finds_nothing_answers_past_the_end() {
1278        assert_eq!(run(r#"(str-find "hello" "ll")"#), Val::Num(2));
1279        assert_eq!(run(r#"(str-find "hello" "z")"#), Val::Num(5));
1280        assert_eq!(run(r#"(str-find "hello" "h")"#), Val::Num(0));
1281        assert_eq!(run(r#"(str-has? "hello" "ell")"#), Val::Num(1));
1282        assert_eq!(run(r#"(str-has? "hello" "elk")"#), Val::Num(0));
1283        assert_eq!(run(r#"(starts-with? "hello" "he")"#), Val::Num(1));
1284        assert_eq!(run(r#"(ends-with? "hello" "lo")"#), Val::Num(1));
1285        // A prefix longer than the string compares unequal rather than
1286        // raising on the negative index `substr` clamps away.
1287        assert_eq!(run(r#"(ends-with? "no" "ohno")"#), Val::Num(0));
1288        assert_eq!(run(r#"(str-trim "  hi \n")"#), Str::val("hi"));
1289        assert_eq!(run(r#"(str-trim "   ")"#), Str::val(""));
1290    }
1291
1292    #[test]
1293    fn text_reaches_the_alphabet_and_the_number_it_spells() {
1294        assert_eq!(run(r#"(str->num "42")"#), Val::Num(42));
1295        assert_eq!(run(r#"(str->num " -1.5 ")"#), Val::Flo(-1.5));
1296        assert_eq!(
1297            run(r#"(attempt (lambda () (str->num "twelve")))"#),
1298            pair(sym("throw"), pair(sym("not-a-number"), Str::val("twelve")))
1299        );
1300        assert_eq!(run(r#"(str-upper "aß")"#), Str::val("ASS"));
1301        assert_eq!(run(r#"(str-lower "ABC")"#), Str::val("abc"));
1302        assert_eq!(run(r#"(ord "A")"#), Val::Num(65));
1303        assert_eq!(run(r#"(chr 65)"#), Str::val("A"));
1304        assert_eq!(run(r#"(chr (+ (ord "a") 1))"#), Str::val("b"));
1305    }
1306
1307    #[test]
1308    fn the_arithmetic_reaches_past_the_polynomials() {
1309        assert_eq!(run("(sqrt 4)"), Val::Flo(2.0));
1310        assert_eq!(run("(pow 2 10)"), Val::Flo(1024.0));
1311        assert_eq!(run("(round (* 100 (log (exp 1))))"), Val::Num(100));
1312        assert_eq!(run("(round (* 1000 (sin 0)))"), Val::Num(0));
1313        assert_eq!(run("(round (* 1000 (atan2 0 1)))"), Val::Num(0));
1314        assert_eq!(run("(floor -1.5)"), Val::Num(-2));
1315        assert_eq!(run("(ceil -1.5)"), Val::Num(-1));
1316        assert_eq!(run("(trunc -1.5)"), Val::Num(-1));
1317        assert_eq!(run("(round -1.5)"), Val::Num(-2));
1318        // An integer is already one, and is not widened and narrowed to
1319        // prove it.
1320        assert_eq!(run("(ceil 3)"), Val::Num(3));
1321        assert_eq!(run("(abs -3)"), Val::Num(3));
1322        assert_eq!(run("(max 2 (min 5 9))"), Val::Num(5));
1323        assert_eq!(run("(list (even? 4) (odd? -3))"), run("(list 1 1)"));
1324    }
1325
1326    #[test]
1327    fn the_surface_forms_reach_the_object_language() {
1328        assert_eq!(run("(let ((b 2)) `(a ,b ,@'(c d)))"), run("'(a 2 c d)"));
1329        assert_eq!(run("(case 'b ((a) 1) ((b c) 2) (else 3))"), Val::Num(2));
1330        assert_eq!(run("(let (((a . r) '(1 2 3))) (+ a (car r)))"), Val::Num(3));
1331        assert_eq!(run("((lambda ((a b)) (- a b)) '(1 2))"), Val::Num(-1));
1332    }
1333
1334    #[test]
1335    fn definitions_reach_each_other_in_the_object_language() {
1336        assert_eq!(
1337            run("(define (ev? n) (if (eq? n 0) 1 (od? (- n 1))))
1338                 (define (od? n) (if (eq? n 0) 0 (ev? (- n 1))))
1339                 (+ (* 10 (ev? 8)) (od? 7))"),
1340            Val::Num(11)
1341        );
1342        assert_eq!(
1343            run("(define (a n) (b (+ n 1)))
1344                 (define (b n) (* n 2))
1345                 (a 3)"),
1346            Val::Num(8)
1347        );
1348    }
1349
1350    #[test]
1351    fn a_cycle_refuses_to_compile_and_says_which() {
1352        let mut t = Tower::load().expect("loads");
1353        let out = t
1354            .compile(&prog(
1355                "(define (ev? n) (if (eq? n 0) 1 (od? (- n 1))))
1356                 (define (od? n) (if (eq? n 0) 0 (ev? (- n 1))))
1357                 (clambda f (n) (ev? n))",
1358            ))
1359            .expect("no fault");
1360        let text = format!("{out}");
1361        assert!(text.contains("inlines-forever"), "{text}");
1362        assert!(text.contains("ev?") && text.contains("od?"), "{text}");
1363
1364        assert_eq!(
1365            residual(
1366                "(define (a n) (b (+ n 1)))
1367                 (define (b n) (* n 2))
1368                 (clambda f (n) (a n))"
1369            ),
1370            "(let (lambda (let (+ x1 1) (let (* x2 2) x3))) x0)"
1371        );
1372    }
1373
1374    #[test]
1375    fn compiling_the_members_does_not_rescue_a_cycle() {
1376        let mut t = Tower::load().expect("loads");
1377        let out = t
1378            .eval(&prog(
1379                "(define ev? (clambda ev? (n) (if (eq? n 0) 1 (od? (- n 1)))))
1380                 (define od? (clambda od? (n) (if (eq? n 0) 0 (ev? (- n 1)))))
1381                 (ev? 8)",
1382            ))
1383            .expect("no fault");
1384        let text = format!("{out}");
1385        assert!(text.contains("inlines-forever"), "{text}");
1386        assert!(text.contains("ev?") && text.contains("od?"), "{text}");
1387    }
1388
1389    #[test]
1390    fn a_table_answers_by_key_and_refuses_a_verb_it_does_not_know() {
1391        let mut t = Tower::load().expect("loads");
1392        let driver = t
1393            .task(&prog(
1394                "(task-loop self
1395                            (lambda h (st msg)
1396                              (let ((tb (spawn (lambda (me) (table-at me '())))))
1397                                (let ((_ (call tb '(put a 1))))
1398                                  (let ((_ (call tb '(put b 2))))
1399                                    (let ((got (call tb '(get a))))
1400                                      (let ((miss (attempt (lambda () (call tb '(get z))))))
1401                                        (let ((bad (attempt (lambda () (call tb '(nonsense))))))
1402                                          (let ((_ (call tb '(drop b))))
1403                                            (cons 'stop
1404                                                  (list got miss bad
1405                                                        (call tb '(keys))))))))))))
1406                            0)",
1407            ))
1408            .expect("no fault");
1409
1410        let mut h = Heap::new(200_000);
1411        let d = h.spawn(driver);
1412        h.post(&addr(d), sym("go"));
1413        h.run().expect("no bug");
1414        assert_eq!(
1415            h.take_exits(),
1416            vec![(
1417                d,
1418                ok(list(&[
1419                    Val::Num(1),
1420                    pair(sym("throw"), pair(sym("no-such-key"), sym("z"))),
1421                    list(&[sym("throw"), sym("bad-request"), sym("nonsense")]),
1422                    list(&[sym("a")]),
1423                ]))
1424            )]
1425        );
1426    }
1427
1428    #[test]
1429    fn a_future_answers_every_reader_with_the_one_result() {
1430        let mut t = Tower::load().expect("loads");
1431        let driver = t
1432            .task(&prog(
1433                "(task-loop self
1434                            (lambda h (st msg)
1435                              (let ((src (spawn (lambda (me) (ref me 7)))))
1436                                (let ((f (future src '(read))))
1437                                  (cons 'stop (list (call f '(read)) (call f '(read)))))))
1438                            0)",
1439            ))
1440            .expect("no fault");
1441
1442        let mut h = Heap::new(200_000);
1443        let d = h.spawn(driver);
1444        h.post(&addr(d), sym("go"));
1445        h.run().expect("no bug");
1446        assert_eq!(
1447            h.take_exits(),
1448            vec![(d, ok(list(&[Val::Num(7), Val::Num(7)])))]
1449        );
1450    }
1451
1452    #[test]
1453    fn a_supervisor_names_the_children_it_holds_up() {
1454        let mut t = Tower::load().expect("loads");
1455        let driver = t
1456            .task(&prog(
1457                "(task-loop self
1458                            (lambda h (st msg)
1459                              (let ((sup (spawn (lambda (me)
1460                                                  (supervise me (list (cons 'a (cons 3 (lambda c (me) (receive))))))))))
1461                                (let ((which (call sup '(which-children))))
1462                                  (let ((one (call sup '(child a))))
1463                                    (let ((none (attempt (lambda () (call sup '(child z))))))
1464                                      (cons 'stop
1465                                            (list (map (lambda (e) (car e)) which)
1466                                                  (eq? one (cdr (car which)))
1467                                                  none)))))))
1468                            0)",
1469            ))
1470            .expect("no fault");
1471
1472        let mut h = Heap::new(200_000);
1473        let d = h.spawn(driver);
1474        h.post(&addr(d), sym("go"));
1475        h.run().expect("no bug");
1476        let exits = h.take_exits();
1477        assert_eq!(
1478            exits,
1479            vec![(
1480                d,
1481                ok(list(&[
1482                    list(&[sym("a")]),
1483                    Val::Num(1),
1484                    pair(sym("throw"), pair(sym("no-such-child"), sym("z"))),
1485                ]))
1486            )]
1487        );
1488    }
1489
1490    #[test]
1491    fn a_deadline_arms_a_timer_that_answers_the_call_it_bounds() {
1492        let mut t = Tower::load().expect("loads");
1493        let entry = t
1494            .task(&prog(
1495                "(task-loop self
1496                            (lambda h (st msg) (cons 'stop (call-within 50 '(host nowhere) '(hi))))
1497                            0)",
1498            ))
1499            .expect("no fault");
1500
1501        let mut h = Heap::new(100_000);
1502        let id = h.spawn(entry);
1503        h.post(&addr(id), sym("go"));
1504        h.run().expect("no bug");
1505
1506        // No clock is registered, so the timer never fires and the task
1507        // parks: a world without the capability simply never times out.
1508        assert_eq!(h.take_exits(), vec![]);
1509        assert_eq!(
1510            h.take_away(),
1511            vec![
1512                (
1513                    host("nowhere"),
1514                    list(&[sym("req"), addr(id), Val::Num(1), list(&[sym("hi")])])
1515                ),
1516                (
1517                    host("clock"),
1518                    list(&[
1519                        sym("after"),
1520                        Val::Num(50),
1521                        addr(id),
1522                        list(&[
1523                            sym("reply"),
1524                            Val::Num(1),
1525                            pair(sym("throw"), sym("timeout"))
1526                        ])
1527                    ])
1528                ),
1529            ]
1530        );
1531    }
1532
1533    fn ok(v: Val) -> Val {
1534        Val::Pair(rc_val(Val::Sym("ok".into())), rc_val(v))
1535    }
1536}