Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Ejit - a javascript compiler for EmacsLisp

Everyone's making compilers for Javascript these days, it's the new assembly language.

Elnode makes building webapps in Emacs relatively easy. But you still need to write a lot of Javascript. A lot of Javascript is boiler plate nonsense and can be mostly strung together with lots of little librarys. But it's still very tedious to do that. So I've started Ejit, to make it possible to build an entirely EmacsLisp webapp.

Ejit takes EmacsLisp and compiles it to Javascript.

Here's some example EmacsLisp:

(flet ((myfunc (a)
         (* 20 a)))
  (let ((a 1)
        (b '(10)))
    (* (+ a (car b)) 2)))

And here is the resulting Javascript:

(function (myfunc) { 
  (function (a,b) { 
     MULT(PLUS(a, car(b)), 2) })(1, [10]) 
   })(function (a) { 
        MULT(20, a) 

This is wrong, but it shows what ejit can do right now.

What we have

There's also the start of an EmacsLisp kernel, which has to be done in Javascript, and makes things like CAR and MULT and PLUS available.

No bridge exists to any other Javascript right now but neither is the compiler doing any checking that functions exist or do not exist, so it should be easy to make the Emacs-Lisp call a Javascript function.

I intend to build a testing framework for this using Elnode so that you can write your EmacsLisp for the browser and get feedback on whether it's working or not.

The approach?

Emacs has more than 1100 special forms implemented in C. Many of these are for buffers and it's operating system environment and such like but some are language. let is a C special form. So is let*.

The idea is to use a macro language to simplify most of EmacsLisp (not the library code, but the language code) to where we have just 1 form for doing one thing.

So let* can be simplified into let for example. Or the other way around. cond can be simplified into if.

This seems like a useful goal in and of itself. If you want to help that part is quite easy.

You have to avoid writing recursive macro expansions (making if -> if for example) but that's pretty easy.

Once we have a simplified language then we can code walk it easier. I have the beginnings of a code walker for the simple language.

Lisp 2

It wouldn't be elisp if we didn't have both lexical and dynamic scope. Exactly how to offer that is the current problem.

I've added the file lexical-test-1.el to describe some of the problems of lex-scope.

My first inclination though is to do what I think the default Emacs behaviour should be, namely the code is in lexical binding mode and special variables have to be defvared.

I think the easiest way to implement dynamic scope is to compile defvar (and maybe global setq) to something that records the var as special. Specials are just globals really, they could be collected in a great big function scope in js. For example:

(defvar a "my a")
(let ((b "my b"))
  (list a b))

Might come out as:

(function (a) {
  (function (b) { return [a, b]; })("my b");
})("my a");

Other problems

What would buffer locals mean??

What indeed? there are lots of Emacs semantics things like this that might be really wierd.

My aim is to make it possible to write elisp to run in the browser, not necessarily to make all elisp run in the browser.

Ok. Why the hell?

Because if we have this then maybe we could write a display engine in a browser. Maybe Emacs functions could be shimed to call back to Emacs. Maybe we could use browsers like multiple processes.

There are possibilities.


Javascript compiler for EmacsLisp






No releases published


No packages published