This page features Lisp-to-Javascript translator and runtime library and contains various interactive "pads" to experiment with the system.
Use the code in the text area as-is, or modify it, or replace it. Press "read lisp" to see the result of reading the code in, "lisp -> JS" to see the result of conversion of it to JavaScript, "eval lisp" to execute it.
Adding the ingredients enabling macros - &rest in argument lists,
the backquote
and its comma and @ syntax, the
defmacro
facility, the macroexpand
function
- was not very difficult. The result is a smmall and fast yet capable
macro system. A few examples are on the following pad:
Considering the above, it is pretty clear that this project is not expected to run some existing Lisp or Scheme code "as is". Some porting is required; many primitives may be missing, some behave differently.
In a nutshell, this project implements a flavor of lisp featuring the following.
Scoping rules are implied by the workings of execution contexts from section 10 of ECMA-262. For instance, lisp closures are lexical (with the smallest lexical scope being a JS function definition), clean and are pretty efficient in comparison to the rest of the JS runtime.
Cons cells are represented as JavaScript objects with 2
properties, car
and cdr
. Nil
is
translated to JavaScript undefined
. Defun
is
translated to JavaScript function definition, and due to that, has
scope of the corresponding active context. Define
and
defvar
is translated to JavaScript var
statement and also
has scope of the corresponding active context. Left-hand side of
assignment may contain arbitrarily expressions as part of property
access expressions.
Atoms in lisp is everything between blanks and list
delimiters. and in this system atoms can be used
creatively. Specifically, it is possible to intentionally write
expressions having complex JavaScript expressions as atoms, One
example is a.b.c
. Another, contrived one is
a.b.c.d-x+y+z[?1:2][++p*q--/*r*/]
. Casing is preserved, so
(qUote x 1)
translates to qUote(x,1)
.
Symbols have historically played an important role in traditional Lisp systems, providing "objects" with identity and properties and an ability to reify as variables. We've reduced this to two aspects: symbols appearing in translated code can map to JavaScript identifiers or expressions; Symbols (or any atoms) appearing inside of quoted expressions map to JavaScript strings.
One is to experiment and have fun with S-expressions, JavaScript and their mix, as demonstrated by the interactive pads seen above on this page.
Take a look at the source of this HTML page. The lisp
system is initialized with a script include tag. After that, global
object Lisp contains the lisp functions and the translator as its
properties. The lisp functions are then exported to become available as
toplevel definitions with Lisp.use_package()
. One can
skip this step, using Lisp
as name qualifier, which
sometimes can be more appropriate.
The code that drive the interactive pads is not part of the lisp system. Yet the code shows some handy ways to invoke the translator and perhaps is reusable as well.
The second way of using the system is to code Web2.0, AJAX-ian apps in lisp using macros to capture various web code patterns, expanding it into production JavaScript code to be be consequently embedded/included into HTML pages.
The third one is to maintain code in lisp format, perhaps on the server, having that transparently expanded to JavaScript or perhaps into complex HTML content on demand. One example is given below.