narju/
surface.rs

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            // Rewriting inside quoted data would change what the program
70            // means, not how it is written.
71            "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            // `quasiquote` consumes the ones it owns, so arriving here means
84            // there was no template to belong to.
85            "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            // Both extend what the rest of a body sees, so neither means
103            // anything where there is no rest.
104            "define" => {
105                return Err(err("desugar", "define outside a body"));
106            }
107            "import" => {
108                return Err(err("desugar", "import outside a body"));
109            }
110            // A floor form at the arity the floor knows it at. Anything else
111            // with this name - a shadowed `car`, a wrong-arity call - falls
112            // through to application, and `trans` decides.
113            _ 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    // The floor takes an application at the arity it is written at, so there
125    // is nothing to curry and no argument to invent for a nullary call.
126    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
141/// What `(unquote e)` and its relatives look like once the reader has turned
142/// the prefix into a form.
143fn 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
156/// `` `t ``, as the `cons` calls that rebuild the shape around its holes.
157/// Nesting is counted rather than refused, which is the only reason `depth`
158/// exists. The floor has no `append`, so a splice gets one emitted per
159/// template rather than a free reference to a library that may not be loaded.
160fn 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
169/// Self-bound, so it can recur without a name from anywhere else.
170fn 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            // Tail position, where the spine walk below hands one over: there
199            // is no list here to join onto.
200            "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    // Stops at a hole rather than walking through one: `(a . ,b)` and
211    // `(a unquote b)` are the same three pairs, so a walk that did not look
212    // would take the dotted tail apart into two more elements.
213    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    // Never `t` itself: every marked form was answered above, so the walk has
223    // taken at least one step before it can stop at one.
224    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
241/// A named lambda is bound to its own name inside the body, which is what the
242/// floor's self-binding argument is for. `clambda` takes the same shape.
243fn 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    // 3-Lisp's spelling. A reflective procedure takes its whole reified call
250    // site, so it has no name to recur through and the name position is the
251    // marker instead.
252    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    // The floor binds only names, so a parameter that is a shape is named here
261    // and taken apart at the top of the body, as `let` does with one.
262    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
281/// `(let ((x a) (y b)) body...)`, and the floor's single-binding
282/// `(let (x a) body)`, told apart by whether the first element of the binding
283/// list is a symbol - which a binder must be and a binding never is. That test
284/// is why the single-binding form takes a name and not a shape. Bindings are
285/// sequential because nesting them is what the floor's one-at-a-time binding
286/// gives; two that read each other are two `define`s, not a `letrec`.
287fn 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
312/// The fold at the end of [`body`] turns each of these into the construct that
313/// binds what follows it.
314enum Wrap {
315    Bind(Val, Val),
316    Import(Val),
317}
318
319/// `Fun` is a definition whose value is a lambda and so has no effect to
320/// reorder, which is the only thing that makes a recursive group possible.
321enum Step {
322    Fun(Val, Val),
323    Bind(Val, Val),
324    Import(Val),
325    Expr(Val),
326}
327
328/// A `define` binds the rest of the sequence, so definition and sequencing are
329/// the same construct and neither needs a mutable frame. An `import` extends
330/// what follows by a whole frame whose contents are not known here, so the
331/// rewrite has the same shape and the work is left to the evaluator. A run of
332/// consecutive function definitions goes to [`group`] instead; it ends at
333/// anything with an effect or a value that cannot be forward-referenced.
334fn 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
394/// A run of consecutive function definitions, as the bindings that make them
395/// mutually visible. Sorting so each comes after the ones it reads is free -
396/// every value is a lambda, so moving one reorders no effect - and is stable
397/// where the reads allow. Definitions that read *each other* cannot be sorted
398/// and go to [`knot`], in the largest sets that must be tied together so one
399/// cycle does not make a long run pay. A name defined twice leaves the run a
400/// plain chain: which one a forward reference meant has no answer here.
401fn 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    // A bitmap row rather than a row of bools: a file is one run of
440    // definitions and may have a thousand, so the transitive closure is a
441    // million word-ors and not a billion byte-ors.
442    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    // Each name's cycle, named by its earliest member.
461    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        // The cycles of a graph form one without cycles, so some cycle always
479        // has its reads satisfied. Falling back rather than asserting, since
480        // being wrong should cost a program its recursion, not its build.
481        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
501/// A set of definitions that read each other, as bindings: one self-named
502/// lambda taking the index of the member wanted, with each member bound inside
503/// to a forwarder that asks the lambda for it. Nothing is assigned, because the
504/// floor's cell is not a form the tower's evaluator knows - so the cycle is
505/// rebuilt on the way round instead, at one allocation per sibling reach.
506///
507/// A knot cannot be compiled: every index is a literal, so the specializer
508/// resolves siblings statically and goes round until the occurs-check stops it
509/// (`a_cycle_refuses_to_compile_and_says_which`, `src/tower.rs`). Sorting is
510/// the half that survives compilation, which is why the two are kept separate.
511fn knot(fns: &[(Val, Val)], members: &[usize], wraps: &mut Vec<Wrap>, g: &mut Gen) {
512    // Named for the cycle it stands for, since the specializer reports this
513    // one alongside the members when it refuses to unfold them.
514    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        // Named for the member it stands in for, though its body does not
542        // recur: the specializer reports the names on a refused cycle, and
543        // those must be the program's rather than the ones invented here.
544        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
567/// A reflective lambda answers `None`: it is applied to its call site rather
568/// than to arguments, so a forwarder standing in for it would not be one.
569fn 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
579/// An improper tail is dropped, which only reaches quoted data - and [`reads`]
580/// does not look inside that.
581fn 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
591/// Shared between the pending items of [`reads`] rather than copied into each,
592/// so a deep expression costs one link per binder and not one set per node.
593struct 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
621/// Which of `names` an already-rewritten expression reads without binding them
622/// itself. It runs after the rewrite so the binding forms are the floor's three
623/// plus `import`, rather than everything the surface has. A name an `import`
624/// supplies is still reported, which is the safe direction: the caller may sort
625/// a definition it did not have to, never fail to sort one it did.
626fn 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
715/// The key is named once and each clause tests it with `eq?`, so a clause
716/// listing several keys costs a comparison apiece and still writes its body
717/// once. Clause heads are data, not expressions, and are not evaluated.
718fn 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
754/// A binder: a symbol names the whole value, a list names its parts by
755/// position, a dotted tail names the rest.
756///
757/// The temporary is not an optimisation and cannot be dropped when the init is
758/// already a variable - a pattern may bind a name the init also mentions,
759/// `(let (((a b) a)) …)`, and since the emitted bindings nest, the second
760/// accessor would read the name the first just rebound. Nothing checks the
761/// shape: `car` of a non-pair already raises, naming the accessor rather than
762/// the pattern.
763fn 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        // A pattern with no names left still runs its init: a binder position
767        // is not a place to decide an expression is dead.
768        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
790/// `or` returns the value of the test that succeeded, so each test needs
791/// a name: evaluating it twice would duplicate its effects.
792fn 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
814/// An embedder that wants more host types or ops extends this further.
815pub 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        // The power specializer again, written the way anyone would.
932        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        // `p` and `q` have nothing to do with the cycle beside them and
1085        // come out as the `let`s they would have been on their own.
1086        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}