Making a Mini-Lisp: Introduction to Transpilers in JavaScript

  • Is the ad hoc distinction between compilation and "transpilation" really worth it? Can't we just call them compilers? I get that the difference between compilation and transpilation is that the target language of the latter is not a lower lever language, which would be in the case of C and Assembler, but that it targets a language that's more or less of a similar level. Is this really worthy of another term? I'm not sure.

  • The language being defined here is not a Lisp, it's a (trivial) language that just happens to use (something like) S expressions as the surface syntax. (The reason it's only "something like" S expressions is that it has ad-hoc commas to delimit argument lists.)

    The characteristic that defines a Lisp is that code is not a sequence of characters, it's a data structure -- typically a tree of cons cells -- which can be manipulated within the language itself. The language being defined here doesn't have that property.

    It is this property that allows you to write macros, which is what makes Lisp cool. Without it you don't have Lisp, you just have a run-of-the-mill programming language with weird syntax.

  • Shameless Plug here.

    Inspired by Peter Norvig's 'How to write a Lisp Interpreter in Python', I created three variants of it along the same lines as the OP. The first is a Simple Lisp Interpreter in Javascript [1]. The second separates Syntactic Analysis from Execution [2]. And the third supports non deterministic computing [3].

    [1] https://bitbucket.org/sainamdar/lisp2js

    [2] https://bitbucket.org/sainamdar/lisp2js2

    [3] https://bitbucket.org/sainamdar/lisp2js2nd

  • As someone who's been working on figuring out a way to transpile or interpret a powerful dynamic language to Lua, JavaScript, Python and Go, the really tough thing to do is non-local exits. If you can solve that, I think that everything else is easy (well, a Simple Matter of Programming anyway).

    It's okay if your target language already supports non-local exits, particularly parameterised ones (although even that can be faked with a well-designed global), but if it doesn't then it's a pain (imagine how you'd do it in Go: every single function call will return an additional value, indicating if a non-local exit is intended).

    Alternatively, imagine trying to transpile call/cc to JavaScript…

  • Great article! Really accessible for a newbie. I'd love to see a comparison between using a manual lexer/parser like the one seen here and using OMeta/JS, which seems like a real time saver for people playing around with languages. https://github.com/alexwarth/ometa-js

  • formatting on code sample was wonky, just fixed them , refresh and enjoy!