Wednesday, May 29, 2013

Wat: now in Perl, Python, and Ruby, too

I'm delighted somebody by the name of "shadowcat-mst" has taken my Wat interpreter and reimplemented it in Perl. That really seems fitting. Wat now covers JavaScript and Perl - think of the possibilities!

Update: Piotr Kuchta ported Wat to Python.
Update: Victor Hugo Borja ported Wat to Ruby.

Thursday, May 9, 2013

Green threads in the browser in 20 lines of Wat

This page shows 5 independent, cooperatively scheduled Wat green threads (view source for full Wat code).

Each thread has an ID and is defined as a function that loops forever, repeatedly printing its ID, and then sleeping for a (randomly long) while.
(define (run-thread (id String))
  (loop
    (@appendChild (.body $document)
                  (@createTextNode $document (+ "Active thread: " id " ")))
    (sleep (* 1000 (@random $Math)))))
So, how can a Wat thread sleep inside a loop when JavaScript forbids sleeping? Why, with good ole delimited continuations:

To spawn a thread, I just wrap the call to RUN-THREAD in a prompt (which is just a unique object used as an identifier):
(define default-prompt 'default-prompt)

(define (spawn-thread (id String))
  (push-prompt default-prompt
    (run-thread id)))
Where it gets interesting is the SLEEP function which captures the continuation up to the prompt, and sets up a callback with JavaScript's setTimeout that will reinstall the continuation later:
(define (sleep (ms Number))
  (take-subcont default-prompt k
    (define (callback . #ignore)
      (push-prompt-subcont default-prompt k))
    ($setTimeout (js-callback callback) ms)))
So, first, SLEEP aborts up to and including the default prompt using TAKE-SUBCONT. It receives the continuation in the variable K. Once it has K, it defines a CALLBACK function, that will reinstall the default prompt with PUSH-PROMPT, and then continue with K again with PUSH-SUBCONT. All that's left is to give this callback to setTimeout.

Then I can spawn independent threads:
(spawn-thread "thread-1")
(spawn-thread "thread-2")
(spawn-thread "thread-3")
(spawn-thread "thread-4")
(spawn-thread "thread-5")
Wat is very new, but it's already practical for adding concurrency and metaprogramming to JavaScript. Deployment is very easy. Include the single wat.js file, put some Lisp code in a <script> tag, and run it.

Wednesday, May 8, 2013

A new low in programming language design and implementation

The new Wat is the best, most lightweight way to implement a JavaScript-based programming language I have found so far.

Basically, I get away from JS as quickly and painlessly as possible, and start writing the language in itself.

So I define a very small set of primitives on the joint foundation of Kernel-like first-class lexical environments and fexprs and delimited continuations. Fexprs are a great tool for language-oriented programming, and delimited continuations allow me to escape from the browser's (and Node's) async hell and implement any concurrency and effect system I like.

To fexprs I also add macros. When a macro is used as the operator of a form, the form's code gets  changed to the macro's output when the macro is first called, a technique I learned from here. I like macros because they make syntactic abstraction cost-free - with fexprs alone there is always an interpretative overhead. Still, Wat macros, like fexprs, do not work with quoted identifiers, but with first-class values, so many hygiene problems are avoided.

To delimited control I also add classic first-order control (sequential, conditional, loop, throw, catch, finally). This runs on the ordinary JS stack. Only when a continuation is captured does the stack get reified on the heap.

And last but not least, I use a JSON-based syntax for writing the language in itself. At first this was just intended as a quick way to not have to specify a parser for Wat, but I'm starting to like it. It allows Wat to truly be embedded in JavaScript.

Wat does not have a type tagging or object system. It uses the raw JavaScript values.

The whole implementation is roughly 350 lines of JavaScript. After these 350 lines, I can already write Wat in Wat, which is just great.

Sunday, May 5, 2013

Some progress on the Wat VM

Wat is back! If you'll recall, Wat is my ultra-minimal (~500 lines of JS) interpreter for a Kernel-based language with delimited continuations as well as first-order control, and hygienic macros as well as fexprs.

I'm pretty excited by some recent and ongoing changes, which make Wat even smaller and turn it into more of a VM than a full language. Wat will provide (just) the following features:
  • delimited continuations and delimited dynamic binding (higher-order control); these will be used to build cooperative multithreading with thread-local bindings
  • try/catch/finally (first-order control) integrated with the JS stack, but suspendable by continuation capture
  • fexprs as well as in-source self-modifying-code memoizing macros (which are hygienic, as they're built on Kernel)
  • a native JS interface
And that's about it. This should give an extremely minimal yet powerful infrastructure for building JavaScript-based languages.

And I gave up on quasiquotation and Scheme-style hygienic macros again. I just cannot get them to work in a satisfying manner.

Exempli gratia, here's some initial Wat VM "microcode" for bootstrapping a vaporlanguage.