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 after that mode because it kept the emitter easy to read while the backend was taking shape. (See the ClojureScript emitter :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 returns.
  • 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").
  • Context-sensitive emission in ClojureScript is visible in its compiler emitter path that threads a :context flag per node.