SLip

A Lisp environment for the browser.

Open demo
Note, the demo requires you to enable popups for this website.

Versus Common Lisp

While I have no specific goal (nor resources, probably) to implement the full Common Lisp specification, SLip is closer to Common Lisp than to other dialects. This page lists some fundamental differences.

No “lambda lists” for functions

Functions defined with defun, lambda, labels and flet don't accept the fancy argument list that Common Lisp has. You can't use &optional, &key etc. there. One easy way to implement them would be to use the destructuring-bind macro; I tried that and all functions were something like 4 times slower.

A proper implementation would add support for those in the compiler itself, and would be slower only when the fancy args are used, without wasting any additional time on simple argument lists. But that's pretty tricky and I didn't get to work on it.

To take a variable number of arguments (like &rest), you can use the Scheme way:

(defun foo (foo bar . baz) ;; “baz” is &rest
  ...)
(defun foo args ;; “args” is a list with all arguments, like &whole
  ...)

To take optional and keyword arguments you can use the destructuring-bind macro, for which we have a fairly complete implementation, but it comes with an important speed penalty.

No multiple-value returns

I haven't found the right way to implement this without sacrificing a lot of speed.

No “real CLOS”

I ported TinyCLOS and it can actually be taken pretty far, but it's not nearly as good as CLOS yet. It's also pretty slow.

Strings are immutable

Since JS strings are immutable, so are SLip strings. We could emulate all the Common Lisp “features” by boxing strings in a custom object, but I think that would reduce performance for no practical benefit.

Eval-always

As mentioned in implementation notes, while compiling a piece of code all toplevel expressions are evaluated in sequence.

No exact arithmetic

Integer and floating point precision is as good as your browser can do. There are no rational and no complex numbers.

No type system, no declare

Most primitive functions do run-time type checking and signal an error if they receive data that they can't understand. However, there are no static (compile-time) type checks yet. I'd probably need to rewrite the whole thing to implement static typing.

No reader customization

For the time being you can't customize the reader. Even if that will be possible at some point, the API will probably be different from Common Lisp's.

Additionally, for now only decimal numbers are supported in the reader.

No symbol-macrolet or compiler macros

I'll probably add support for these at some point.

No “debugger”

Debugging, for now, is painful. There's no step-by-step debugger, or stack frame inspector.

Lots more...

I'm pretty sure there are a lot more things we're missing, but most of them could fall in the “library” section. For example we don't have a pretty printer, a loop macro, and the format function is incomplete (though still quite useful). But most of this missing functionality can be written in SLip itself, so it's less essential.

Fork me on Github