Skip to content
This repository

Whalesong: Racket to JavaScript compiler

Whalesong: a compiler from Racket to JavaScript.

Danny Yoo (


See: for documentation.

The rest of the content in this document will migrate there shortly.


Prerequisite: Racket 5.1.1.  The majority of the project is written
Typed Racket, and I highly recommend you use a version of Racket
that's at least 5.1.1; otherwise, compilation may take an unusual
amount of time.


Example usage

Create a simple, standalong executable of your program.  At the
moment, the program must be written in the base language of whalesong.
(This restriction currently prevents arbitrary racket/base programs
from compiling, and we'll be working to remove this restriction.)

    $ cat hello.rkt 
    #lang planet dyoo/whalesong
    (display "hello world")

    $ ./whalesong.rkt build hello.rkt

    $ ls -l hello.xhtml
    -rw-rw-r-- 1 dyoo nogroup 692213 Jun  7 18:00 hello.xhtml

[FIXME: add more examples]



The basic idea is to reuse most of the Racket compiler infrastructure.
We use the underlying Racket compiler to produce bytecode from Racket
source; it also performs macro expansion and module-level
optimizations for us.  We parse that bytecode using the
compiler/zo-parse collection to get an AST, compile that to an
intermediate language, and finally assemble JavaScript.

                        AST          IL                     JS
 parse-bytecode.rkt ----------> compiler.rkt --------> assembler.rkt ------->

The IL is intended to be translated straightforwardly.  We currently
have an assembler to JavaScript, as well as a simulator
(simulator.rkt).  The simulator allows us to test the compiler in a
controlled environment.



This is intended to reuse the Racket compiler to produce the AST
structures defined in compiler/zo-parse.



translates the AST to the intermediate language.  The compiler has its
origins in the register compiler in Structure and Interpretation of
Computer Programs:

with some significant modifications.  Since this is a stack machine,
we don't need any of the register-saving infrastructure in the
original compiler.  We also need to support slightly different linkage
structures, since we want to support multiple value contexts.  We're
trying to generate code that works effectively on a machine like the
one described in:

The intermediate language is defined in il-structs.rkt, and a
simulator for the IL in simulator/simulator.rkt.  See
test-simulator.rkt to see the simulator in action, and
test-compiler.rkt to see how the output of the compiler can be fed
into the simulator.

The assumed machine is a stack machine with the following atomic

    val: value
    proc: procedure
    argcount: number of arguments

and two stack registers:

    env: environment stack
    control: control stack



The JavaScript assembler plays a few tricks to make things like tail
calls work:

   * Each basic block is translated to a function taking a MACHINE

   * Every GOTO becomes a function call.

   * The head of each basic-blocked function checks to see if we
     should trampoline

   * We support a limited form of computed jump by assigning an
     attribute to the function corresponding to a return point.  See
     the code related to the LinkedLabel structure for details.

Otherwise, the assembler is fairly straightforward.  It depends on
library functions defined in mini-runtime.js.  As soon as the compiler
stabilizes, we will be pulling in the runtime library in Moby Scheme
into this project.

The assembled output distinguishes between Primitives and Closures.
Primitives are only allowed to return single values back, and are not
allowed to do any higher-order procedure calls.  Closures, on the
other hand, have full access to the machine, but they are responsible
for calling the continuation and popping off their arguments when
they're finished.



The test suite in test-all.rkt runs the test suite.  You'll need to
run this on a system with a web browser, as the suite will evaluate
JavaScript and make sure it is producing values.  A bridge module
(planet dyoo/browser-evaluate) brings up a temporary web server that allows us
to pass values between Racket and the JavaScript evaluator on the


Acknowledgements and Thanks

This uses code from the following projects:

   jshashtable (
   js-numbers (
   JSON (
   jquery (

   [FIXME: add more]
Something went wrong with that request. Please try again.