Javathcript allows you to script your web pages in a simple lisp variant. Once you include Javathcript.js,
any script tags in your document with
type="text/lisp" will be evaluated. It will also download lisp files (only from the original server),
if you have a script tag that has a
While it is not an exact implementation of any pre-existing variant of lisp, if you know lisp most of it should be familiar. If you don't you might find it useful to follow a tutorial, e.g. this one. There will be differences between this implementation and others, but there is also much that is common.
Since the browser doesn't natively understand script tags with
type="text/lisp", the Javathcript.js file
is included in the header to provide parsing and evaluation for lisp code. I have also included the prelude.lsp lisp
source file in the header since it defines a number of functions that this code uses (e.g.
To include these files, the following script tags are in the head of this page. Note that the
prelude.lsp file has to be served from the same
server as any page that uses it, as it is fetched by an XHR.
The block of code below attaches a javathcript handler to the
onclick attribute of the button.
Click the button to see the code execute.
<type="text/lisp"> (let* ( (button (getElement "btn")) (nameField (getElement "name")) (clickHandler (lambda () (alert (concat "Hello " (get nameField "value"))))) ) (set button "onclick" (export clickHandler)) ) < >
quote car cdr cons equal atom cond lambda label
According to A Micro-Manual for Lisp - Not the whole truth , these functions provide the core of Lisp, and are enough to create a self-hosting LISP interpreter. Here are some examples (click to evaluate them):
The Micro-manual also suggests
t Nil or and not null defun list which I have included, and
cadr with arbitrary combinations
of 'a' and 'd', some of which are in the prelude. I've modified the following example slightly from that given in the paper as the empty list is not regarded as an
atom in javathcript.
def defun let let*
As well as
defun to set a name for a function in the global scope, there is also
def, to allow you to set names for
other kinds of values in the global scope. Functions provide their own scope, but you can also use
let* to create
temporary scopes. The code example at the top of this page used
let* to assign names for the button, the nameField and the clickHandler.
if ' ;
You can quote something by simply putting the single quote in front of it. This is a bit more terse than having to wrap it in
Comments are lines that start with the
if provides a slighly more intuitive alternative to
A number of aliases are provided in the prelude.lsp file, eg.
eq eq? head tail first rest, as well as
a number of useful functions, e.g.
length concat substring
As well as atoms and lists, Javathcript also provides some support for strings Strings literals can be entered by surrounding them in double quotes.
Most functions that work on lists will also work on strings, although unlike in some lisps, Javathcript strings are not lists.
Also note that
concat if started with a string will concatenate numbers into the string too.
plus minus divide times rem < > <= >= = /=
Javathcript supports numeric literals, and the normal arithmetic functions (which are aliased by prelude.lsp to be accessible by the symbols too).
sin cos tan asin acos atan floor max min log abs ceil pow exp atan2 random sqrt round
set sets properties on them, and
returns previously set properties.
js method export
js function evaluates its string argument, and returns the result. If the result is a function, a small adjustment is made to it
so that it will evaluate its arguments in the current Javathcript scope before executing. If the result is a function that belongs to an
object, executing separately will unbind the function from the object it was connected to (the
this reference will be wrong). In that
case, you should use
(method object "methodname") to get a reference to the function that will execute against the provided object.
Check out the Graphics and the Canvas tag section to see an example of some of this in action.
disconnected from that scope. If you want to call them from, e.g. event handlers, then you can use the
export function to create
a function with the scope boiled in.
document body window getElement alert message confirm
These functions are defined in the prelude.lsp file, and provide you references to the document and the window.
getElementById, and message is a synonym for
The Y combinator is "one of the most strange and wonderful artifacts of Computer Science" according to Douglas Crockford. It allows you to write an anoymous function that can use recursion (not that this is something that comes up a lot...). There's a good explanation of it here.
The Micro-manual included a complete Lisp interpreter written in Lisp. Here is a slight modification of it that I took from here.
The following image was rendered into a canvas by some Javathcript code in an embedded script tag. In order to have this demo work in internet explorer too, I've included excanvas on this page. If your browser doesn't support canvas, you would have seen an alert message when you loaded this page, and this demo won't work.
The project is hosted on github here. Depending on your setup, the following command should get you a local copy of the code.
git clone firstname.lastname@example.org:kybernetikos/Javathcript.git
Parsing is done with parsing code that I ported from Java. The original java is the code that accompanies the book Building Parsers With Java and is copyright Steven J. Metsker.
The lisp engine was created by me, based on A Micro-Manual for Lisp - Not the whole truth by John McCarthy.
Although Javathcript doesn't take code from other projects, running lisp variants in the browser is not a new thing. It's been done before by at least:
You can contact me by email at, or check out my blog.
Leave a comment.comments powered by Disqus