Compiling Factor to Javascript

I've written a compiler for a subset of the Factor programing language targeting Javascript as the compiled language. The blogposts describing the compiler and its implementation are here:

The actual working example is at: http://factor.bluishcoder.co.nz/responder/fjsc/

The compiler itself is written in Factor and runs on the server. In the example I take the users input, send it to the server via Ajax and eval the result when it comes back. The compiled javascript returned is displayed in a textarea for testing.

I basically started it as a test project for my post on Compilers and Interpreters in Factor but it was a bit big for that. I shelved it for a while and decided to finish it while I'm not in paid employment.

The main difference from 'real' Factor is that I don't support parsing words and I've not implemented much of the standard library. What parsing word functionality I wanted to support I built into the parser itself. The parser is written using Parser Combinators and produces an abstract syntax tree. I then compile this into Javascript.

There is a parser to convert from a string of Factor code to the AST as well as from already parsed Factor quotations from the server Factor instance. This allows writing code on the server in Factor, and converting it to Javascript without having to do any string generation of Factor or Javascript code manually.

I wanted to support continuations so I ended up generating the Javascript in continuation passing style. It results in ugly code but makes it easy to do callcc. An example of generated code (from '1 2 + alert'):

factor.push_data(1,
       function() {
         factor.push_data(2,
           function() {
             factor.find_word("+").execute(
               function() {
                 factor.find_word("alert").execute(factor.cont.next)
             })
           })
         })

The main problem with this approach is it will blow the browsers call stack pretty quickly. I use a workaround for this by counting the number of times I call the next continuation. When it reaches a certain threshold I pass it to setTimeout instead of calling it. This effectively jumps out of the call stack and starts it again. It also has the side benefit of releasing processor cycles to the browser and avoiding 'time consuming script' messages. I came across this approach in this LtU article. Apart from this I don't do any other optimisations yet.

The continuations are multi-shot and can be attached to event handlers. For example, the following attaches a normal quotation to the onclick event handler of a button with id 'test':

"click" "#test" elements [ "clicked" alert ] bind-event ;

Or a continuation:

[
    [
      >r "click" "#test" elements r> [ continue ] curry bind-event
      "Waiting for click on button" alert
      continue
    ] callcc0
    drop "Click done!" alert 
  ] callcc0

Factor has Erlang style concurrency (processes as lightweight threads and message passing) and I plan to port that library to the javascript version. I have a comet library that allows sending messages to and from the browser to Factor processes - I think it'd be pretty neat to be able to write processes on the browser in Factor that communicate to processes on the server in Factor.

I hope this is interesting enough to post here - I usually don't write about stuff I wrote myself but I thought it would be interesting as other compiler->javascript projects have been discussed. At the very least it might prove useful as a playground for those who want to try out a concatenative language like Factor or Joy.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

setTimeout

This is something that has been bugging me about JavaScript recently. The setTimeout trick is now commonly used to avoid nested or long running function calls (been meaning to do it for flapjax, our frp web language), but as a browser is a highly reactive environment, that means we quickly become susceptible to event ordering. To add insult to injury, browsers implement event handling differently!

Ordering was always an issue swept under the rug with JavaScript development, though the recent emphasis on using js as an application language or a compiler target has highlighted it. Anyone know any good reads on event based systems with limited resources or a real-time focus? The Esterel guys seemed to have really gone at it...

Exceptions/trampolines

Throwing an exception is another way to clear the stack: set up a try/catch block when starting a "process", then throw an exception (containing the continuation) to that point when the stack gets too big. That should allow deep recursion without introducing additional nondeterminism (it's what we do in Links when we require synchronicity), but might need additional care to avoid the 'time consuming script' problem.

Using trampolines is

Using trampolines is something I was considering but it's the ease of dealing with the long running script issue that made me go with the existing approach. Is there any other way of avoiding that other than setTimeout or not having long running scripts?

exceptions

Yeah I was wondering about that. I was running a Links demo a couple weeks back and had a script time out error - except the program then recovered from it. The CSP'd code was confusing enough to decompile for my other purposes that I didn't try to figure that one out.

What ever happened to the flapjax/links tangent? sk went silent on that front after my initial email and I had to deal with some other things (such as thinking about more quickly evaluating FRPs!). 2 more days and it's break over here so I can start working again :)