# Hacking the CoffeeScript Redux Compiler

Published: 2012-08-16
Tags: code, coffeescript, javascript
URL: https://codebrief.com/2012/08/hacking-the-coffeescript-compiler/

CoffeeScript is great. I'm not going to spend any time backing that statement up in this article, but you are free to stop reading if it's not your cup of tea.

My main gripe with CoffeeScript, however, is a small impedance mismatch with the [Ember.js](http://emberjs.com) object model. Creating classes using the `new` operator in coffeescript does not translate well to the Ember convention of creating object's via the `create` method.<sup>[1](#footnote-1)</sup>


Specifically, consider the following CoffeeScript:

```coffeescript
class Developer
class Brogrammer extends Developer
b = new Brogrammer
```

Running this through the CoffeeScript compiler generates something along the lines of:

```javascript
var b, Brogrammer, Developer;
Developer = function () {
  function Developer() {
  }
  return Developer;
}();
Brogrammer = function (super$) {
  extends$(Brogrammer, super$);
  function Brogrammer() {
  }
  return Brogrammer;
}(Developer);
b = new Brogrammer;
function isOwn$(o, p) {
  return {}.hasOwnProperty.call(o, p);
}
function extends$(child, parent) {
  var key;
  for (key in parent)
    if (isOwn$(parent, key))
      child[key] = parent[key];
  function ctor() {
    this.constructor = child;
  }
  ctor.prototype = parent.prototype;
  child.prototype = new ctor;
  child.__super__ = parent.prototype;
  return child;
}
```

When dealing with Ember.js, however, it would be desirable to output the following:

```javascript
var b, Brogrammer, Developer;
Developer = Ember.Object.extend();
Brogrammer = Developer.extend();
b = Brogrammer.create();
```

Fortunately, I have been following the [CoffeeScript Redux Project](https://github.com/michaelficarra/CoffeeScriptRedux) by [Michael Ficarra](https://github.com/michaelficarra) closely and am excited by its potential. From its own description, it aims to be a "rewrite of the CoffeeScript compiler with proper compiler design principles and a focus on robustness and extensibility." Although not complete, extensibility is exactly what we need here and it is far enough along for a proof of concept.

In this post I am going to detail exactly that: how one would go about creating a modified, Ember-specific version of the CS compiler which conforms to the Ember object model.

## Compiler Overview

In order to make this modification, it is important to grok the structure of the CSR compiler. Below are the steps the `coffee` binary goes through during compilation:

1. **Preprocessing** - Perform lexical analysis and convert the input into tokens.
2. **Parsing** - Construct the CoffeeScript abstract syntax tree (AST). This is written using [PEG.js](http://pegjs.majda.cz/).
3. **Optimising** - Perform optimizations and simplify the AST.
4. **Compiling** - Compile the CS AST into a JavaScript AST.
5. **Code generation** - Output JS, this uses [escodegen](https://github.com/Constellation/escodegen/).

Since we are not adding any new syntax to CoffeeScript itself, our primitive proof of concept only has to worry about the compilation phase: we need only modify the generated JavaScript AST to use Ember's conventions. 

## Modifying the Code

After checking out the code from the GitHub [repo](https://github.com/michaelficarra/CoffeeScriptRedux), let's try and test out the existing behavior. Create a file called `test.coffee` in the root of the repository and populate it with the example at the top of this post. Then run:

```
make && ./bin/coffee --debug --js < test.coffee
```

This will output a lot of information, including the AST trees and the final javascript. The outputted javascript should be close to the output I gave at the beginning of this post.

For the purposes of this blog post, there are three main changes that need to be made:

1. Base class definitions should use `Ember.Object.extend();`
2. Subclasses should call `extend` on the base class.
3. Class instantiation should use `create` instead of `new`.

The code for the compilation phase is predictably located in `src/compiler.coffee`. This file contains a set of rules for translating CoffeeScript AST nodes to Javascript AST nodes. For reference, the potential JS nodes are defined in `src/js-nodes.coffee`. For the first two changes above, the pertinent code is located in `compiler.coffee` near the code:

```coffeescript
    [CS.Class, ({nameAssignee, parent, name, ctor, block, compile}) ->
      args = []
      params = []
      parentRef = genSym 'super'
      block = forceBlock block
      ...
```

As CoffeeScript supports executable class bodies, bound methods, etc., the logic inside here is non-trivial. However, looking towards the bottom of the method, we see that it returns an expression consisting of:

```coffeescript
new JS.CallExpression (new JS.FunctionExpression null, params, block), args
```

This represents the outer function of a CoffeeScript class definition. For ember, we want to change this to a call to `Ember.Object.extend`. The following code does exactly that:

```coffeescript
new JS.CallExpression memberAccess(memberAccess(new JS.Identifier('Ember'), 'Object'), 'extend'), []
```

We also need to comment out the existing inheritance logic and change the target of the create expression when the class definition is extending another class. I am not going to include the code here, but feel free to check out the [repo](https://github.com/ghempton/CoffeeScriptRedux/tree/ember) which contains these changes.

To modify `new` to use `create`, the change is rather trivial. Simply change:

```coffeescript
[CS.NewOp, ({ctor, arguments: args}) -> new JS.NewExpression ctor, args]
```

to:

```coffeescript
[CS.NewOp, ({ctor, arguments: args}) -> new JS.CallExpression memberAccess(ctor, 'create'), []]
```

This changes the CoffeeScript new expression from outputting a JS new expression to outputting a JS call expression. If you now re-run the command you should see the following output:

```
➜  CoffeeScriptRedux git:(ember) ✗ ./bin/coffee --js < test.coffee 
// Generated by CoffeeScript 2.0.0
void function () {
  var b, Brogrammer, Developer;
  Developer = Ember.Object.extend();
  Brogrammer = Developer.extend();
  b = Brogrammer.create();
}.call(this);
```

That is all their is to it! The compiler now outputs class definitions using the Ember object-model. You can view the working code on [github](https://github.com/ghempton/CoffeeScriptRedux/tree/ember).

As a disclaimer, this simple prototype is an experiment and will not provide much real-world value. It is only the beginning of an Ember-infused CoffeeScript fork. A more sophisticated version would take into account class bodies, mixins, bindings, getters/setters and other Ember goodness, far beyond the scope of this post. But [stay tuned](https://github.com/ghempton/ember-script) :).

<div class="footnotes">
<p id="footnote-1">1. Technically, Ember classes actually are compatible with the new operator, but there is no way to pass in a hash parameter as the class body for initialization.</p>
</div>