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
8fn 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
20pub const PRELUDE: &str = include_str!("../naj/prelude.naj");
22
23pub const REPL: &str = include_str!("../naj/repl.naj");
26
27pub const LOCK: &str = include_str!("../naj/lock.naj");
30
31pub 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 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 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 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 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 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 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 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 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 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 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 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 "(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 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 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 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 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 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 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 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 assert_eq!(
488 run(&format!("(let ((f ({op} f (g n) (g n 1)))) (f + 5))")),
489 Val::Num(6)
490 );
491 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 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 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 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 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 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 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 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 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 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 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 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}