1use smol_str::SmolStr;
2
3use crate::floor::host::{OpDef, Registry};
4use crate::floor::read::{self, form_arity};
5use crate::floor::{list, list_elements, rc_val, Shared, Val};
6
7pub fn extend(r: Registry) -> Registry {
8 r.op(OpDef {
9 name: "desugar",
10 arity: 1,
11 run: |a| desugar_top(&a[0]),
12 })
13 .op(OpDef {
14 name: "desugar-body",
15 arity: 1,
16 run: |a| match list_elements(&a[0]) {
17 Some(forms) => desugar_body(&forms),
18 None => Err(err("desugar", "a body is a list of forms")),
19 },
20 })
21}
22
23fn err(tag: &str, detail: impl Into<String>) -> Val {
24 Val::Pair(
25 rc_val(Val::Sym(SmolStr::new(tag))),
26 rc_val(crate::floor::host::Str::val(detail.into())),
27 )
28}
29
30fn sym(s: &str) -> Val {
31 Val::Sym(SmolStr::new(s))
32}
33
34fn is(v: &Val, name: &str) -> bool {
35 matches!(v, Val::Sym(s) if s == name)
36}
37
38struct Gen(usize);
39
40impl Gen {
41 fn next(&mut self) -> Val {
42 self.0 += 1;
43 Val::Sym(SmolStr::new(format!("%{}", self.0)))
44 }
45}
46
47pub fn desugar_top(v: &Val) -> Result<Val, Val> {
48 desugar(v, &mut Gen(0))
49}
50
51pub fn desugar_body(forms: &[Val]) -> Result<Val, Val> {
52 body(forms, &mut Gen(0))
53}
54
55fn let_(name: Val, init: Val, body: Val) -> Val {
56 list(&[sym("let"), list(&[name, init]), body])
57}
58
59fn desugar(v: &Val, g: &mut Gen) -> Result<Val, Val> {
60 let items = match v {
61 Val::Pair(_, _) => list_elements(v).ok_or_else(|| err("desugar", "improper form"))?,
62 other => return Ok(other.clone()),
63 };
64 let head = &items[0];
65 let args = &items[1..];
66
67 if let Val::Sym(name) = head {
68 match name.as_str() {
69 "quote" => {
72 return match args {
73 [_] => Ok(v.clone()),
74 _ => Err(err("desugar", "quote takes one argument")),
75 }
76 }
77 "quasiquote" => {
78 return match args {
79 [t] => quasiquote(t, g),
80 _ => Err(err("desugar", "quasiquote takes one argument")),
81 }
82 }
83 "unquote" | "unquote-splicing" => {
86 return Err(err("desugar", "unquote outside a template"));
87 }
88 "lambda" | "clambda" => return lambda(name, args, g),
89 "let" => return let_form(args, g),
90 "begin" => return body(args, g),
91 "cond" => return cond(args, g),
92 "case" => return case(args, g),
93 "and" => return and(args, g),
94 "or" => return or(args, g),
95 "list" => {
96 let mut acc = Val::Nil;
97 for a in args.iter().rev() {
98 acc = list(&[sym("cons"), desugar(a, g)?, acc]);
99 }
100 return Ok(acc);
101 }
102 "define" => {
105 return Err(err("desugar", "define outside a body"));
106 }
107 "import" => {
108 return Err(err("desugar", "import outside a body"));
109 }
110 _ if form_arity(name).is_some_and(|n| n == args.len()) => {
114 let mut out = vec![head.clone()];
115 for a in args {
116 out.push(desugar(a, g)?);
117 }
118 return Ok(list(&out));
119 }
120 _ => {}
121 }
122 }
123
124 let mut out = vec![desugar(head, g)?];
127 for a in args {
128 out.push(desugar(a, g)?);
129 }
130 Ok(list(&out))
131}
132
133fn cons(a: Val, b: Val) -> Val {
134 list(&[sym("cons"), a, b])
135}
136
137fn quoted(v: Val) -> Val {
138 list(&[sym("quote"), v])
139}
140
141fn marked(v: &Val) -> Option<(&str, &Val)> {
144 let Val::Pair(head, rest) = v else {
145 return None;
146 };
147 let Val::Sym(name) = &**head else {
148 return None;
149 };
150 match &**rest {
151 Val::Pair(e, tail) if matches!(**tail, Val::Nil) => Some((name.as_str(), e)),
152 _ => None,
153 }
154}
155
156fn quasiquote(t: &Val, g: &mut Gen) -> Result<Val, Val> {
161 let mut joiner = None;
162 let out = quasi(t, 1, g, &mut joiner)?;
163 Ok(match joiner {
164 None => out,
165 Some(j) => let_(j.clone(), join_fn(&j), out),
166 })
167}
168
169fn join_fn(j: &Val) -> Val {
171 let step = cons(
172 list(&[sym("car"), sym("xs")]),
173 list(&[j.clone(), list(&[sym("cdr"), sym("xs")]), sym("ys")]),
174 );
175 list(&[
176 sym("lambda"),
177 list(&[j.clone(), sym("xs"), sym("ys")]),
178 list(&[sym("if"), list(&[sym("nil?"), sym("xs")]), sym("ys"), step]),
179 ])
180}
181
182fn quasi(t: &Val, depth: usize, g: &mut Gen, joiner: &mut Option<Val>) -> Result<Val, Val> {
183 if let Some((tag, e)) = marked(t) {
184 match tag {
185 "unquote" if depth == 1 => return desugar(e, g),
186 "unquote" => {
187 let inner = quasi(e, depth - 1, g, joiner)?;
188 return Ok(cons(quoted(sym("unquote")), cons(inner, Val::Nil)));
189 }
190 "quasiquote" => {
191 let inner = quasi(e, depth + 1, g, joiner)?;
192 return Ok(cons(quoted(sym("quasiquote")), cons(inner, Val::Nil)));
193 }
194 "unquote-splicing" if depth > 1 => {
195 let inner = quasi(e, depth - 1, g, joiner)?;
196 return Ok(cons(quoted(sym("unquote-splicing")), cons(inner, Val::Nil)));
197 }
198 "unquote-splicing" => {
201 return Err(err("desugar", "unquote-splicing outside a list"));
202 }
203 _ => {}
204 }
205 }
206 if !matches!(t, Val::Pair(_, _)) {
207 return Ok(quoted(t.clone()));
208 }
209
210 let mut spine = Vec::new();
214 let mut cur = t;
215 while let Val::Pair(head, rest) = cur {
216 if marked(cur).is_some_and(|(tag, _)| is_hole(tag)) {
217 break;
218 }
219 spine.push(&**head);
220 cur = rest;
221 }
222 let mut acc = quasi(cur, depth, g, joiner)?;
225 for head in spine.into_iter().rev() {
226 acc = match marked(head) {
227 Some(("unquote-splicing", e)) if depth == 1 => {
228 let j = joiner.get_or_insert_with(|| g.next()).clone();
229 list(&[j, desugar(e, g)?, acc])
230 }
231 _ => cons(quasi(head, depth, g, joiner)?, acc),
232 };
233 }
234 Ok(acc)
235}
236
237fn is_hole(tag: &str) -> bool {
238 matches!(tag, "unquote" | "unquote-splicing" | "quasiquote")
239}
240
241fn lambda(kw: &str, args: &[Val], g: &mut Gen) -> Result<Val, Val> {
244 let (me, params, rest) = match args {
245 [Val::Sym(_), p, rest @ ..] if !rest.is_empty() => (args[0].clone(), p, rest),
246 [p, rest @ ..] if !rest.is_empty() && !matches!(p, Val::Sym(_)) => (sym("_"), p, rest),
247 _ => return Err(err("desugar", "lambda takes a parameter list and a body")),
248 };
249 if is(&me, "reflect") {
253 if kw != "lambda" {
254 return Err(err("desugar", "only lambda can be reflective"));
255 }
256 return Ok(list(&[sym("rlambda"), params.clone(), body(rest, g)?]));
257 }
258 let params =
259 list_elements(params).ok_or_else(|| err("desugar", "lambda's parameters are a list"))?;
260 let mut binders = vec![me];
263 let mut shapes = Vec::new();
264 for p in params {
265 match p {
266 Val::Sym(_) => binders.push(p),
267 _ => {
268 let t = g.next();
269 binders.push(t.clone());
270 shapes.push((p, t));
271 }
272 }
273 }
274 let mut b = body(rest, g)?;
275 for (pat, t) in shapes.iter().rev() {
276 b = bind(pat, t.clone(), b, g)?;
277 }
278 Ok(list(&[sym(kw), list(&binders), b]))
279}
280
281fn let_form(args: &[Val], g: &mut Gen) -> Result<Val, Val> {
288 let (head, rest) = args
289 .split_first()
290 .ok_or_else(|| err("desugar", "let takes bindings and a body"))?;
291 if rest.is_empty() {
292 return Err(err("desugar", "let takes bindings and a body"));
293 }
294 let items = list_elements(head).ok_or_else(|| err("desugar", "let's bindings are a list"))?;
295
296 let bindings = match items.first() {
297 Some(Val::Sym(_)) => vec![head.clone()],
298 _ => items,
299 };
300
301 let mut acc = body(rest, g)?;
302 for b in bindings.iter().rev() {
303 let parts = list_elements(b).ok_or_else(|| err("desugar", "a binding is (name init)"))?;
304 let [name, init] = parts.as_slice() else {
305 return Err(err("desugar", "a binding is (name init)"));
306 };
307 acc = bind(name, desugar(init, g)?, acc, g)?;
308 }
309 Ok(acc)
310}
311
312enum Wrap {
315 Bind(Val, Val),
316 Import(Val),
317}
318
319enum Step {
322 Fun(Val, Val),
323 Bind(Val, Val),
324 Import(Val),
325 Expr(Val),
326}
327
328fn body(forms: &[Val], g: &mut Gen) -> Result<Val, Val> {
335 let (last, init) = forms
336 .split_last()
337 .ok_or_else(|| err("desugar", "empty body"))?;
338 if definition(last).is_some() || import(last).is_some() {
339 return Err(err("desugar", "a body ends in an expression"));
340 }
341
342 let mut steps = Vec::with_capacity(init.len());
343 for f in init {
344 steps.push(match (definition(f), import(f)) {
345 (Some((name, expr)), _) => {
346 let e = desugar(&expr, g)?;
347 match (&name, arity(&e)) {
348 (Val::Sym(_), Some(_)) => Step::Fun(name, e),
349 _ => Step::Bind(name, e),
350 }
351 }
352 (_, Some(expr)) => Step::Import(desugar(&expr, g)?),
353 _ => Step::Expr(desugar(f, g)?),
354 });
355 }
356
357 let mut wraps = Vec::with_capacity(steps.len());
358 let mut i = 0;
359 while i < steps.len() {
360 let run = steps[i..]
361 .iter()
362 .take_while(|s| matches!(s, Step::Fun(_, _)))
363 .count();
364 if run > 0 {
365 let mut fns = Vec::with_capacity(run);
366 for s in &steps[i..i + run] {
367 if let Step::Fun(n, e) = s {
368 fns.push((n.clone(), e.clone()));
369 }
370 }
371 group(&fns, &mut wraps, g);
372 i += run;
373 continue;
374 }
375 match &steps[i] {
376 Step::Bind(n, e) => wraps.push(Wrap::Bind(n.clone(), e.clone())),
377 Step::Import(e) => wraps.push(Wrap::Import(e.clone())),
378 Step::Expr(e) => wraps.push(Wrap::Bind(sym("_"), e.clone())),
379 Step::Fun(_, _) => unreachable!("a run of them was just taken"),
380 }
381 i += 1;
382 }
383
384 let mut acc = desugar(last, g)?;
385 for w in wraps.into_iter().rev() {
386 acc = match w {
387 Wrap::Bind(n, e) => let_(n, e, acc),
388 Wrap::Import(e) => list(&[sym("import"), e, acc]),
389 };
390 }
391 Ok(acc)
392}
393
394fn group(fns: &[(Val, Val)], wraps: &mut Vec<Wrap>, g: &mut Gen) {
402 let plain = |wraps: &mut Vec<Wrap>| {
403 for (n, e) in fns {
404 wraps.push(Wrap::Bind(n.clone(), e.clone()));
405 }
406 };
407
408 let names: Vec<SmolStr> = fns
409 .iter()
410 .filter_map(|(n, _)| match n {
411 Val::Sym(s) => Some(s.clone()),
412 _ => None,
413 })
414 .collect();
415 let n = names.len();
416 if n != fns.len()
417 || names
418 .iter()
419 .enumerate()
420 .any(|(i, x)| names[..i].contains(x))
421 {
422 return plain(wraps);
423 }
424
425 let mut edges: Vec<Vec<usize>> = Vec::with_capacity(n);
426 for (_, e) in fns {
427 let mut hit = Vec::new();
428 reads(e, &names, &mut hit);
429 edges.push(
430 hit.iter()
431 .filter_map(|x| names.iter().position(|y| y == x))
432 .collect(),
433 );
434 }
435 if edges.iter().all(Vec::is_empty) {
436 return plain(wraps);
437 }
438
439 let w = n.div_ceil(64);
443 let mut to = vec![0u64; n * w];
444 for (i, es) in edges.iter().enumerate() {
445 for &j in es {
446 to[i * w + j / 64] |= 1 << (j % 64);
447 }
448 }
449 for k in 0..n {
450 for i in 0..n {
451 if to[i * w + k / 64] >> (k % 64) & 1 == 1 {
452 for c in 0..w {
453 to[i * w + c] |= to[k * w + c];
454 }
455 }
456 }
457 }
458 let reaches = |i: usize, j: usize| to[i * w + j / 64] >> (j % 64) & 1 == 1;
459
460 let mut cycle: Vec<usize> = (0..n).collect();
462 for i in 0..n {
463 if let Some(j) = (0..i).find(|&j| reaches(i, j) && reaches(j, i)) {
464 cycle[i] = cycle[j];
465 }
466 }
467
468 let mut done = vec![false; n];
469 let mut left = n;
470 while left > 0 {
471 let ready = (0..n).find(|&rep| {
472 cycle[rep] == rep
473 && !done[rep]
474 && (0..n)
475 .filter(|&i| cycle[i] == rep)
476 .all(|i| edges[i].iter().all(|&j| cycle[j] == rep || done[j]))
477 });
478 let Some(rep) = ready else {
482 for i in 0..n {
483 if !done[i] {
484 wraps.push(Wrap::Bind(fns[i].0.clone(), fns[i].1.clone()));
485 }
486 }
487 return;
488 };
489 let members: Vec<usize> = (0..n).filter(|&i| cycle[i] == rep).collect();
490 for &i in &members {
491 done[i] = true;
492 }
493 left -= members.len();
494 match members.as_slice() {
495 [i] => wraps.push(Wrap::Bind(fns[*i].0.clone(), fns[*i].1.clone())),
496 _ => knot(fns, &members, wraps, g),
497 }
498 }
499}
500
501fn knot(fns: &[(Val, Val)], members: &[usize], wraps: &mut Vec<Wrap>, g: &mut Gen) {
512 let grp = match g.next() {
515 Val::Sym(n) => {
516 let mut s = n.to_string();
517 for &i in members {
518 if let Val::Sym(m) = &fns[i].0 {
519 s.push('/');
520 s.push_str(m);
521 }
522 }
523 Val::Sym(SmolStr::new(s))
524 }
525 other => other,
526 };
527 let idx = g.next();
528
529 let mut b = Val::Num(0);
530 for (at, &i) in members.iter().enumerate().rev() {
531 b = list(&[
532 sym("if"),
533 list(&[sym("eq?"), idx.clone(), Val::Num(at as i64)]),
534 fns[i].1.clone(),
535 b,
536 ]);
537 }
538 for (at, &i) in members.iter().enumerate().rev() {
539 let k = arity(&fns[i].1).expect("a run's definitions are lambdas");
540 let args: Vec<Val> = (0..k).map(|_| g.next()).collect();
541 let mut binders = vec![fns[i].0.clone()];
545 binders.extend(args.iter().cloned());
546 let mut call = vec![list(&[grp.clone(), Val::Num(at as i64)])];
547 call.extend(args);
548 b = let_(
549 fns[i].0.clone(),
550 list(&[sym("lambda"), list(&binders), list(&call)]),
551 b,
552 );
553 }
554
555 wraps.push(Wrap::Bind(
556 grp.clone(),
557 list(&[sym("lambda"), list(&[grp.clone(), idx]), b]),
558 ));
559 for (at, &i) in members.iter().enumerate() {
560 wraps.push(Wrap::Bind(
561 fns[i].0.clone(),
562 list(&[grp.clone(), Val::Num(at as i64)]),
563 ));
564 }
565}
566
567fn arity(e: &Val) -> Option<usize> {
570 let items = spine(e);
571 match items.as_slice() {
572 [head, binders, _] if is(head, "lambda") || is(head, "clambda") => {
573 Some(spine(binders).len().checked_sub(1)?)
574 }
575 _ => None,
576 }
577}
578
579fn spine(v: &Val) -> Vec<&Val> {
582 let mut out = Vec::new();
583 let mut cur = v;
584 while let Val::Pair(head, rest) = cur {
585 out.push(&**head);
586 cur = rest;
587 }
588 out
589}
590
591struct Scope {
594 name: SmolStr,
595 rest: Option<Shared<Scope>>,
596}
597
598fn shadowed(mut s: Option<&Shared<Scope>>, name: &SmolStr) -> bool {
599 while let Some(l) = s {
600 if &l.name == name {
601 return true;
602 }
603 s = l.rest.as_ref();
604 }
605 false
606}
607
608fn under(s: &Option<Shared<Scope>>, binders: &[&Val]) -> Option<Shared<Scope>> {
609 let mut out = s.clone();
610 for b in binders {
611 if let Val::Sym(name) = b {
612 out = Some(Shared::new(Scope {
613 name: name.clone(),
614 rest: out,
615 }));
616 }
617 }
618 out
619}
620
621fn reads(e: &Val, names: &[SmolStr], out: &mut Vec<SmolStr>) {
627 let mut work = vec![(e, None::<Shared<Scope>>)];
628 while let Some((v, sc)) = work.pop() {
629 let Val::Sym(s) = v else {
630 if !matches!(v, Val::Pair(_, _)) {
631 continue;
632 }
633 let items = spine(v);
634 if let Val::Sym(head) = items[0] {
635 match (head.as_str(), items.len()) {
636 ("quote", 2) => continue,
637 ("lambda" | "clambda" | "rlambda", 3) => {
638 work.push((items[2], under(&sc, &spine(items[1]))));
639 continue;
640 }
641 ("let", 3) => {
642 let b = spine(items[1]);
643 if let [name, init] = b.as_slice() {
644 work.push((init, sc.clone()));
645 work.push((items[2], under(&sc, &[name])));
646 continue;
647 }
648 }
649 ("import", 3) => {
650 work.push((items[1], sc.clone()));
651 work.push((items[2], sc));
652 continue;
653 }
654 _ => {}
655 }
656 }
657 work.extend(items.into_iter().map(|x| (x, sc.clone())));
658 continue;
659 };
660 if names.contains(s) && !shadowed(sc.as_ref(), s) && !out.contains(s) {
661 out.push(s.clone());
662 }
663 }
664}
665
666fn import(v: &Val) -> Option<Val> {
667 let items = list_elements(v)?;
668 if !is(items.first()?, "import") {
669 return None;
670 }
671 match &items[1..] {
672 [expr] => Some(expr.clone()),
673 _ => None,
674 }
675}
676
677fn definition(v: &Val) -> Option<(Val, Val)> {
678 let items = list_elements(v)?;
679 if !is(items.first()?, "define") {
680 return None;
681 }
682 match &items[1..] {
683 [name @ Val::Sym(_), expr] => Some((name.clone(), expr.clone())),
684 [head, rest @ ..] if !rest.is_empty() => {
685 let sig = list_elements(head)?;
686 let (name, params) = sig.split_first()?;
687 let mut lam = vec![sym("lambda"), name.clone(), list(params)];
688 lam.extend_from_slice(rest);
689 Some((name.clone(), list(&lam)))
690 }
691 _ => None,
692 }
693}
694
695fn cond(clauses: &[Val], g: &mut Gen) -> Result<Val, Val> {
696 let mut acc = Val::Nil;
697 for c in clauses.iter().rev() {
698 let parts = list_elements(c).ok_or_else(|| err("desugar", "a cond clause is a list"))?;
699 let (test, rest) = parts
700 .split_first()
701 .ok_or_else(|| err("desugar", "an empty cond clause"))?;
702 if rest.is_empty() {
703 return Err(err("desugar", "a cond clause needs a body"));
704 }
705 let then = body(rest, g)?;
706 acc = if is(test, "else") {
707 then
708 } else {
709 list(&[sym("if"), desugar(test, g)?, then, acc])
710 };
711 }
712 Ok(acc)
713}
714
715fn case(args: &[Val], g: &mut Gen) -> Result<Val, Val> {
719 let (subject, clauses) = args
720 .split_first()
721 .ok_or_else(|| err("desugar", "case takes a key and clauses"))?;
722 let key = g.next();
723
724 let mut acc = Val::Nil;
725 for c in clauses.iter().rev() {
726 let parts = list_elements(c).ok_or_else(|| err("desugar", "a case clause is a list"))?;
727 let (keys, rest) = parts
728 .split_first()
729 .ok_or_else(|| err("desugar", "an empty case clause"))?;
730 if rest.is_empty() {
731 return Err(err("desugar", "a case clause needs a body"));
732 }
733 let then = body(rest, g)?;
734 if is(keys, "else") {
735 acc = then;
736 continue;
737 }
738 let ks =
739 list_elements(keys).ok_or_else(|| err("desugar", "a case clause's keys are a list"))?;
740 let mut test = Val::Num(0);
741 for k in ks.iter().rev() {
742 test = list(&[
743 sym("if"),
744 list(&[sym("eq?"), key.clone(), quoted(k.clone())]),
745 Val::Num(1),
746 test,
747 ]);
748 }
749 acc = list(&[sym("if"), test, then, acc]);
750 }
751 Ok(let_(key, desugar(subject, g)?, acc))
752}
753
754fn bind(pat: &Val, init: Val, inner: Val, g: &mut Gen) -> Result<Val, Val> {
764 match pat {
765 Val::Sym(_) => Ok(let_(pat.clone(), init, inner)),
766 Val::Nil => Ok(let_(sym("_"), init, inner)),
769 Val::Pair(head, rest) => {
770 let t = g.next();
771 let acc = bind(rest, list(&[sym("cdr"), t.clone()]), inner, g)?;
772 let acc = bind(head, list(&[sym("car"), t.clone()]), acc, g)?;
773 Ok(let_(t, init, acc))
774 }
775 _ => Err(err("desugar", "a binder is a name or a list of them")),
776 }
777}
778
779fn and(args: &[Val], g: &mut Gen) -> Result<Val, Val> {
780 let Some((last, init)) = args.split_last() else {
781 return Ok(Val::Num(1));
782 };
783 let mut acc = desugar(last, g)?;
784 for a in init.iter().rev() {
785 acc = list(&[sym("if"), desugar(a, g)?, acc, Val::Num(0)]);
786 }
787 Ok(acc)
788}
789
790fn or(args: &[Val], g: &mut Gen) -> Result<Val, Val> {
793 let Some((last, init)) = args.split_last() else {
794 return Ok(Val::Num(0));
795 };
796 let mut acc = desugar(last, g)?;
797 for a in init.iter().rev() {
798 let t = g.next();
799 acc = let_(
800 t.clone(),
801 desugar(a, g)?,
802 list(&[sym("if"), t.clone(), t, acc]),
803 );
804 }
805 Ok(acc)
806}
807
808pub fn compile(src: &str) -> Result<Val, Val> {
809 let forms = read::read(src)?;
810 let lowered = body(&forms, &mut Gen(0))?;
811 read::trans(&lowered, &Val::Nil)
812}
813
814pub fn registry() -> Registry {
816 extend(crate::floor::host::builtins())
817}
818
819#[cfg(test)]
820mod tests {
821 use super::*;
822 use crate::floor::machine::{Machine, NoMail, Store};
823 use crate::floor::Env;
824
825 fn one(src: &str) -> Val {
826 let forms = read::read(src).expect("reads");
827 assert_eq!(forms.len(), 1);
828 forms[0].clone()
829 }
830
831 fn d(src: &str) -> Val {
832 desugar_top(&one(src)).expect("rewrites")
833 }
834
835 fn db(src: &str) -> Val {
836 desugar_body(&read::read(src).expect("reads")).expect("rewrites")
837 }
838
839 fn run(src: &str) -> Val {
840 let exp = match compile(src).expect("compiles") {
841 Val::Code(e) => e,
842 other => panic!("expected code, got {other}"),
843 };
844 Machine::new(Env::default(), exp)
845 .run(&mut Store::<NoMail>::default())
846 .expect("no fault")
847 }
848
849 #[test]
850 fn an_n_ary_lambda_keeps_its_arity_and_its_name() {
851 assert_eq!(
852 d("(lambda f (a b) (f a b))"),
853 one("(lambda (f a b) (f a b))")
854 );
855 }
856
857 #[test]
858 fn a_reflective_lambda_does_not_curry() {
859 assert_eq!(
860 d("(lambda reflect (m l e r k) e)"),
861 one("(rlambda (m l e r k) e)")
862 );
863 }
864
865 #[test]
866 fn a_nullary_function_takes_no_argument() {
867 assert_eq!(d("(lambda () 1)"), one("(lambda (_) 1)"));
868 assert_eq!(d("(f)"), one("(f)"));
869 }
870
871 #[test]
872 fn a_definition_binds_the_rest_of_its_body() {
873 assert_eq!(
874 d("(begin (define x 1) (define (f a) a) (f x))"),
875 one("(let (x 1) (let (f (lambda (f a) a)) (f x)))")
876 );
877 }
878
879 #[test]
880 fn a_form_and_a_call_both_get_their_operands_rewritten() {
881 assert_eq!(
882 d("(cons (or a b) c)"),
883 one("(cons (let (%1 a) (if %1 %1 b)) c)")
884 );
885 assert_eq!(d("(f (or a b) c)"), one("(f (let (%1 a) (if %1 %1 b)) c)"));
886 }
887
888 #[test]
889 fn rewriting_does_not_reach_inside_quoted_data() {
890 assert_eq!(d("'(lambda (a b c) x)"), one("'(lambda (a b c) x)"));
891 }
892
893 #[test]
894 fn or_names_each_test_so_it_is_evaluated_once() {
895 assert_eq!(d("(or a b)"), one("(let (%1 a) (if %1 %1 b))"));
896 }
897
898 #[test]
899 fn the_rewritten_surface_runs() {
900 assert_eq!(
901 run("(define (fact n) (if (< n 1) 1 (* n (fact (- n 1)))))
902 (fact 5)"),
903 Val::Num(120)
904 );
905 assert_eq!(
906 run("(define (sum3 a b c) (+ a (+ b c)))
907 (sum3 1 2 3)"),
908 Val::Num(6)
909 );
910 assert_eq!(
911 run("(cond ((< 2 1) 'lt) (else 'ge))"),
912 Val::Sym("ge".into())
913 );
914 assert_eq!(run("(and 1 2)"), Val::Num(2));
915 assert_eq!(run("(or 0 7)"), Val::Num(7));
916 assert_eq!(run("(car (cdr (list 1 2 3)))"), Val::Num(2));
917 }
918
919 #[test]
920 fn a_thousand_definitions_do_not_recurse() {
921 let mut src = String::new();
922 for i in 0..1000 {
923 src.push_str(&format!("(define x{i} {i})\n"));
924 }
925 src.push_str("x999");
926 assert_eq!(run(&src), Val::Num(999));
927 }
928
929 #[test]
930 fn the_surface_stages_the_same_way_the_floor_does() {
931 assert_eq!(
933 run("(define (pow n)
934 (lambda (x) (if (< n 1) (lift 1) (* x ((pow (- n 1)) x)))))
935 ((run 0 (lift (pow 3))) 2)"),
936 Val::Num(8)
937 );
938 }
939
940 #[test]
941 fn the_template_prefixes_read_as_the_forms_they_stand_for() {
942 assert_eq!(one("`x"), one("(quasiquote x)"));
943 assert_eq!(one(",x"), one("(unquote x)"));
944 assert_eq!(one(",@x"), one("(unquote-splicing x)"));
945 assert_eq!(one("`,x"), one("(quasiquote (unquote x))"));
946 assert_eq!(one("'`x"), one("(quote (quasiquote x))"));
947 }
948
949 #[test]
950 fn a_template_with_no_holes_is_a_quotation() {
951 assert_eq!(d("`(a b)"), one("(cons 'a (cons 'b '()))"));
952 }
953
954 #[test]
955 fn a_template_rebuilds_the_shape_around_its_holes() {
956 assert_eq!(d("`(a ,b)"), one("(cons 'a (cons b '()))"));
957 assert_eq!(d("`(a . ,b)"), one("(cons 'a b)"));
958 assert_eq!(run("(let ((b 2)) `(1 ,b 3))"), run("'(1 2 3)"));
959 assert_eq!(run("(let ((b 2)) `(1 . ,b))"), run("'(1 . 2)"));
960 }
961
962 #[test]
963 fn a_splice_brings_its_own_joiner() {
964 assert_eq!(run("(let ((xs '(2 3))) `(1 ,@xs 4))"), run("'(1 2 3 4)"));
965 assert_eq!(run("(let ((xs '())) `(1 ,@xs))"), run("'(1)"));
966 assert_eq!(
967 run("(let ((xs '(1)) (ys '(2))) `(,@xs ,@ys))"),
968 run("'(1 2)")
969 );
970 }
971
972 #[test]
973 fn a_nested_template_holds_its_inner_holes_as_data() {
974 assert_eq!(
975 run("(let ((b 2)) `(a `(c ,b)))"),
976 run("'(a (quasiquote (c (unquote b))))")
977 );
978 assert_eq!(
979 run("(let ((b 2)) `(a `(c ,,b)))"),
980 run("'(a (quasiquote (c (unquote 2))))")
981 );
982 }
983
984 #[test]
985 fn a_hole_outside_a_template_is_refused() {
986 assert!(desugar_top(&one(",x")).is_err());
987 assert!(desugar_top(&one("`,@x")).is_err());
988 }
989
990 #[test]
991 fn case_compares_one_key_against_each_clause() {
992 assert_eq!(run("(case 'b ((a) 1) ((b c) 2) (else 3))"), Val::Num(2));
993 assert_eq!(run("(case 'c ((a) 1) ((b c) 2) (else 3))"), Val::Num(2));
994 assert_eq!(run("(case 'z ((a) 1) ((b c) 2) (else 3))"), Val::Num(3));
995 assert_eq!(run("(case 'z ((a) 1))"), Val::Nil);
996 }
997
998 #[test]
999 fn a_case_key_is_named_and_its_clause_heads_are_not() {
1000 assert_eq!(
1001 d("(case k ((a) 1) (else 2))"),
1002 one("(let (%1 k) (if (if (eq? %1 'a) 1 0) 1 2))")
1003 );
1004 }
1005
1006 #[test]
1007 fn a_binder_may_be_a_shape_rather_than_a_name() {
1008 assert_eq!(run("(let (((a b) '(1 2))) (- a b))"), Val::Num(-1));
1009 assert_eq!(run("(let (((a . r) '(1 2 3))) (car r))"), Val::Num(2));
1010 assert_eq!(
1011 run("(let ((((a b) c) '((1 2) 3))) (+ a (+ b c)))"),
1012 Val::Num(6)
1013 );
1014 }
1015
1016 #[test]
1017 fn a_parameter_may_be_a_shape_too() {
1018 assert_eq!(run("((lambda ((a b)) (- a b)) '(1 2))"), Val::Num(-1));
1019 assert_eq!(
1020 run("(define (f x (a . r)) (+ x (+ a (car r)))) (f 1 '(2 3))"),
1021 Val::Num(6)
1022 );
1023 }
1024
1025 #[test]
1026 fn a_shape_may_rebind_a_name_its_init_reads() {
1027 assert_eq!(
1028 run("(let ((a '(1 2))) (let (((a b) a)) (- a b)))"),
1029 Val::Num(-1)
1030 );
1031 }
1032
1033 #[test]
1034 fn bindings_are_sequential_and_a_later_one_sees_an_earlier() {
1035 assert_eq!(d("(let ((x 1) (y x)) y)"), one("(let (x 1) (let (y x) y))"));
1036 assert_eq!(run("(let ((x 1) (y (+ x 1))) (* x y))"), Val::Num(2));
1037 }
1038
1039 #[test]
1040 fn a_definition_may_call_one_written_below_it() {
1041 assert_eq!(
1042 run("(define (a n) (b (+ n 1)))
1043 (define (b n) (* n 2))
1044 (a 3)"),
1045 Val::Num(8)
1046 );
1047 assert_eq!(
1048 db("(define (a) (b)) (define (b) 1) (a)"),
1049 db("(define (b) 1) (define (a) (b)) (a)")
1050 );
1051 }
1052
1053 #[test]
1054 fn a_run_that_reads_nothing_is_left_in_order() {
1055 assert_eq!(
1056 db("(define (a) 1) (define (b) 2) (+ (a) (b))"),
1057 one("(let (a (lambda (a) 1)) (let (b (lambda (b) 2)) (+ (a) (b))))")
1058 );
1059 }
1060
1061 #[test]
1062 fn definitions_that_read_each_other_are_tied() {
1063 assert_eq!(
1064 run("(define (ev? n) (if (eq? n 0) 1 (od? (- n 1))))
1065 (define (od? n) (if (eq? n 0) 0 (ev? (- n 1))))
1066 (+ (* 10 (ev? 8)) (od? 7))"),
1067 Val::Num(11)
1068 );
1069 }
1070
1071 #[test]
1072 fn a_cycle_may_be_longer_than_two() {
1073 assert_eq!(
1074 run("(define (up n) (if (eq? n 0) 0 (+ 1 (down (- n 1)))))
1075 (define (down n) (if (eq? n 0) 0 (+ 1 (side (- n 1)))))
1076 (define (side n) (if (eq? n 0) 0 (+ 1 (up (- n 1)))))
1077 (up 9)"),
1078 Val::Num(9)
1079 );
1080 }
1081
1082 #[test]
1083 fn a_cycle_ties_only_its_own_members() {
1084 let out = format!(
1087 "{}",
1088 db("(define (p) 1)
1089 (define (ev? n) (od? n))
1090 (define (od? n) (ev? n))
1091 (define (q) 2)
1092 (+ (p) (q))")
1093 );
1094 assert!(out.contains("('let ('p ('lambda ('p) 1))"), "{out}");
1095 assert!(out.contains("('let ('q ('lambda ('q) 2))"), "{out}");
1096 assert_eq!(
1097 run("(define (p) 1)
1098 (define (ev? n) (if (eq? n 0) 1 (od? (- n 1))))
1099 (define (od? n) (if (eq? n 0) 0 (ev? (- n 1))))
1100 (define (q) 2)
1101 (+ (p) (+ (q) (ev? 4)))"),
1102 Val::Num(4)
1103 );
1104 }
1105
1106 #[test]
1107 fn a_value_definition_ends_a_run() {
1108 assert_eq!(
1109 db("(define (a) 1) (define x (a)) (define (b) x) (b)"),
1110 one("(let (a (lambda (a) 1))
1111 (let (x (a))
1112 (let (b (lambda (b) x)) (b))))")
1113 );
1114 }
1115
1116 #[test]
1117 fn a_shadowed_name_is_not_a_read() {
1118 assert_eq!(
1119 db("(define (a) (let ((b 1)) b)) (define (b) 2) (a)"),
1120 one("(let (a (lambda (a) (let (b 1) b)))
1121 (let (b (lambda (b) 2)) (a)))")
1122 );
1123 assert_eq!(
1124 run("(define (a) (let ((b 1)) b)) (define (b) 2) (a)"),
1125 Val::Num(1)
1126 );
1127 }
1128
1129 #[test]
1130 fn a_quoted_name_is_not_a_read() {
1131 assert_eq!(
1132 db("(define (a) 'b) (define (b) 1) (a)"),
1133 one("(let (a (lambda (a) 'b)) (let (b (lambda (b) 1)) (a)))")
1134 );
1135 }
1136
1137 #[test]
1138 fn a_name_defined_twice_leaves_the_run_a_chain() {
1139 assert_eq!(
1140 db("(define (a) (b)) (define (b) 1) (define (b) 2) (a)"),
1141 one("(let (a (lambda (a) (b)))
1142 (let (b (lambda (b) 1))
1143 (let (b (lambda (b) 2)) (a))))")
1144 );
1145 }
1146
1147 #[test]
1148 fn the_surface_extends_the_floor_rather_than_replacing_it() {
1149 let r = registry();
1150 assert!(r.lookup("str-append").is_some());
1151 assert!(r.lookup("desugar").is_some());
1152 }
1153}