Saturday, February 23, 2008

ErlyJS - translating Javascript to Erlang

I have lately invested many hours of coding in ErlyJS, my open source attempt of writing a Javascript compiler for the Erlang virtual machine and crossed today the barrier of 100, for the number of commits and also for the number of test cases. There is still a long way to go, because nobody (including myself) will actually use the compiler in a real project, unless it is 100% Javascript compliant. But at least, most of the basic stuff is now halfway implemented:
  • Literals
  • Global / local variable handling
  • Operators (except of dot operator, for objects)
  • Functions
  • Built-in global functions
The next big task will be object handling (and implementing the built-in objects and their functions)

I am not targeting the Erlang VM directly (beside of the Erlang compiler source code, there doesen't exist any formal specification or at least documentation about the Erlang VM internals in general and specifically the VM opcodes). What I do is transforming the Javascript source code AST to an Erlang AST. This involves a lot of trickery, because Erlang doesn't allow variable re-assignments (this is good and also necessary in the context of Erlang concurrency), but most Javascript code is just a bunch of variable re-assignments, so I have to model it somehow and I have choosen to model it differently for global Javascript variables (Erlang process dictionary) and local variables (normal Erlang variables). One interesting thing about having an Erlang AST of Javascript source code is the possibility of pretty-printing Erlang source code. Let's take a look at a Javascript example from the test cases:
function test() {
var a=0, b="Bananas";

switch (b) {
case "Oranges":
a = 1;
break;
case "Apples":
a = 2;
break;
case "Papayas":
case "Bananas":
a = 2.5;
a = 3;
break;
default:
a = 4;
}

return a;
}

If I pretty print the AST (just before compiling it, and this is even done automatically at verbose ErlyJS compiling settings) I get the following Erlang source code:
js_test() ->
V78 = 0,
V80 = "Bananas",
{V152} = case V80 of
"Oranges" -> V170 = 1, {V170};
"Apples" -> V88 = 2, {V88};
X when X == "Papayas"; X == "Bananas" ->
V270 = 2.5, V288 = 3, {V288};
_ -> V32 = 4, {V32}
end,
V152.
This kind of source code translation is extremely useful while developing and debugging the ErlyJS compiler and analyzing test cases.

7 comments:

Matthew Kanwisher said...

How can you transfer code from a imperative language to a functional one, aren't you going to lose a lot of the benefits of erlang if you have to have all this state?

Roberto Saccon said...

Matthew, you are loosing the benefits of Erlang the language, if the alternative would be to code directly in Erlang. But ErlyJS is for scenarios where Erlang the language is not a viable option for client applications, but the server is written in Erlang.

Matthew Kanwisher said...

I have to say you have some rather interesting Erlang projects. I'm curious of why you chose to compile to erlang instead of using an external js interpreter via like a C bridge?

Roberto Saccon said...

A C bridge is a portability and maintenance nightmare (ask CouchDB guys), and worst, it is drastically limiting scalability. Let's take a Comet Server for example. Every process represents a client connection and owns the socket, and I want to run the client app within that process.

Btw., I had a C-bridge to spidermonkey, just for parsing the Javascript sourcecode, but it was more trouble than benefit and I didn't like the way the AST was represented and I spent just too much time maintaining that C code, so I wrote my own parser in Erlang.

Benjamin Nortier said...

Awesome. It would make testing generated javascript much easier if one were to develop an Erlang-based web framework which does JS code generation...

Anonymous said...

How do you map mutable data structure (like array, hash table) to Erlang? Using ETS or process dictionary? But both of them are not garbage collected.

Anonymous said...

Hello,

What about this project ? I am currently working on a Javascript obfuscator written ir Erlang, and your Javascript parser should be interesting to understand.

Thank you