| author | Alan Dipert
<alan@tailrecursion.com> 2026-01-02 03:20:04 UTC |
| committer | Alan Dipert
<alan@tailrecursion.com> 2026-01-02 03:20:04 UTC |
| parent | 0827200d067ec26ab7442808c58039f34a5bcc4e |
| md/Home.md | +1 | -0 |
| md/Lisp.md | +1 | -1 |
| md/Lisp/DestinationDrivenCompilation.md | +45 | -0 |
diff --git a/md/Home.md b/md/Home.md index 3768529..93e78d3 100644 --- a/md/Home.md +++ b/md/Home.md @@ -24,6 +24,7 @@ Updates | Date | Note | |:-----------|:-------------------------------------------------------------------------------------------------------------------------------------------| +| 2026-01-01 | Added [Lisp:DestinationDrivenCompilation](./Lisp/DestinationDrivenCompilation.md), comparing statement-context emitters with destination-driven code generation for bracketed hosts. | | 2025-12-27 | Added [AIAndRisk](./AIAndRisk.md), reflecting on why AI upside favors owners who can offload risk while salaried engineers must retain understanding. | | 2025-12-27 | Added [Coherence](./Coherence.md) on treating an AI coding agent like an employee by keeping intent, artifacts, and execution aligned. | | 2025-11-19 | Added [WhoIsGod](./WhoIsGod.md) as the hub linking to the names and covenants reference tables. | diff --git a/md/Lisp.md b/md/Lisp.md index 5fbde47..d007d62 100644 --- a/md/Lisp.md +++ b/md/Lisp.md @@ -5,5 +5,5 @@ I have been interested in all things Lisp since around 2009, when I learned Cloj * [Lisp:GherkinHistory](./Lisp/GherkinHistory.md) provides context around an interpreter I wrote in 2013 that was extremely gratifying. - +* [Lisp:DestinationDrivenCompilation](./Lisp/DestinationDrivenCompilation.md) compares statement-context emission to destination-driven code generation for bracketed host languages. diff --git a/md/Lisp/DestinationDrivenCompilation.md b/md/Lisp/DestinationDrivenCompilation.md new file mode 100644 index 0000000..15ba7d3 --- /dev/null +++ b/md/Lisp/DestinationDrivenCompilation.md @@ -0,0 +1,45 @@ +# DestinationDrivenCompilation + +Compilers that target hosts with a hard statement/expression split (JavaScript, C, and similar "bracket" languages) have to respect where values are allowed and where only effects make sense. ClojureScript's emitter handled this with context-sensitive emission: every node got an expression-or-statement flag and picked a matching output form. I patterned [JACL](https://tailrecursion.com/git-arr/r/jacl.git/) after that mode because it kept the emitter easy to read while the backend was taking shape. (See the [ClojureScript emitter](https://github.com/clojure/clojurescript/blob/515900f9762102987bda7d53b919dafc0b6c0580/src/clj/clojure/cljs.clj) `:context` handling.) + +Context-sensitive emission (expression/statement mode) + +- Feels natural: each emitter mirrors the host syntax it is asked to produce. +- Adds scaffolding: expression-only paths fabricate values even when only effects are needed. +- Adds wrappers: expression nodes in statement position often become immediately invoked function expressions (IIFEs) to "unwrap" a value back into a statement. +- Propagates mode: the flag is carried to every child, so subexpressions default to producing values even when the parent needs only effects. + +Destination-driven compilation (value/effect/tail) + +- Each node is compiled toward a destination: produce a value, perform an effect, or return from tail position. +- Eliminates wrappers: an effect destination emits straight-line statements; a tail destination emits direct `return`s. +- Reduces temps: only value destinations introduce locals, so fewer temps appear and less dead code needs removal. +- Propagates destinations: children inherit the current destination and can short-circuit—effect destinations can drop unused values, and tail destinations emit the final `return`. + +Example: compiling a value-binding `if` +Source (Lisp-ish): +``` +(let [x (if test (f) (g))] + (h x)) +``` +Context-sensitive emission (expression mode needing a value): +``` +var x = (function(){ + if (test) { return f(); } + else { return g(); } +})(); +h(x); +``` +Destination-driven emission (value destination): +``` +var x; +if (test) { x = f(); } +else { x = g(); } +h(x); +``` + +Destination-driven output already looks like the optimized version. If I rewrote JACL to target destinations instead of expression-versus-statement mode, I expect fewer IIFEs, fewer temps, and fewer cleanup passes to bridge the abstraction mismatch with bracketed hosts. + +Background reading +- Destination-driven code generation was popularized by Kent Dybvig (see "[Destination-Driven Code Generation](http://www.cs.indiana.edu/~dyb/pubs/dest.pdf)"). +- Context-sensitive emission in ClojureScript is visible in its compiler emitter path that threads a `:context` flag per node.