Javascript with a lisp
JavaScript Common Lisp
Switch branches/tags
Pull request Compare This branch is 2 commits ahead, 404 commits behind jbr:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Sibilant is a language that is parsed by javascript and compiles to javascript.
Sibilant is inspired by lisp and follows many lisp conventions, although it is still relatively close to the underlying javascript.
Macros can be defined in sibilant and included at compile time.
Sibilant is entirely written in sibilant and can recompile itself.

Try it before you install includes an in-browser as-you-type sibilant compiler and tutorial, so you can get a sense of the language without leaving your browser.


First, install node.js [ github ] and npm [ github ].

$ npm install sibilant


-v / --version         Print out a version string and exit

-h / --help            This message

--repl / [no args]     Sibilant interactive command prompt

--execute / -x         This is a flag. Execute input files in order supplied.

--eval [optional STRING] / -e [optional STRING]
                       Evaluate STR if provided, otherwise evaluate standard in.

--output DIR / -o DIR  Output input files to this dir, replacing .lisp with .js.

--input FILE / -i FILE / FILE
                       Add this file to the input files. If the execute flag is
                       set, input files will be executed.  If an output dir is
                       specified, each file will be written to that dir.
                       Otherwise, each file will be written to STDOUT.

CLI Examples

To compile sibilant

$ git clone git://
$ cd sibilant
$ npm link .
$ sibilant src/*.lisp -o lib
$ sibilant -x test/test.lisp # you're now running a sibilant you just compiled.

To compile one file to stdout

$ sibilant test/test.lisp

To compile a file to a directory

$ sibilant test/test.lisp -o . # put test.js here or $ sibilant --input test/test.lisp --output .

To run a file

$ sibilant -x test/test.lisp

To enter the repl

$ sibilant or $ sibilant --repl




"to the world, he said \"hello\""

Multiline strings are okay:

"this is a
multiline string"


Numbers are directly translated to javascript. Valid numbers include 10, 98.6, -100, et cetera.


Variables only include lower-case letters. Hyphens are legal, and are translated into camelcase in javascript. For example, j-query is jQuery. Asterisks become underscores. For example *global-variable* would become _globalVariable_ in javascript. Variables can end with question marks and exclamation marks. These are translated to javascript as “Q” and “B” (for bang). For example, ready? becomes readyQ and finish! becomes finishB.


'(a b c d e f g) ;=> ['a', 'b', 'c', 'd', 'e', 'f', 'g']
'hello ;=> "hello"


(list 1 2 3 4 5) ;=> [1,2,3,4,5]

Defining a variable

(defvar foo "foo now has this value")


(hash key1 'value1
      key2 'value2) ;=> {key1: "value1", key2: "value2"}

Calling functions

Let’s say we’re in node and want to use the built-in function require.

(defvar sys (require 'sys)) ;=> var sys = require("sys")

Defining functions

(defun square (arg1) (* arg1 arg1))
    ;=> var square = function(arg1) { return arg1 * arg1 }

(square 5)

The last statement is always returned.

Optional arguments

Sibilant supports optional arguments. If an argument is preceded by &optional, it will be skipped if there are fewer than the total number of arguments. Optional arguments are filled in from left to right.

(defun example (a &optional b c &optional d e)
 (... do something with a b c d e ...))

(example 1 2 3)     ; these will be a c and e
(example 1 2)       ; this will raise an exception
(example 1 2 3 4)   ; these will be a b c e
(example 1 2 3 4 5) ; these will be a b c d e

Variable arguments (varargs)

Sibilant supports arbitrary-length arguments by way of the &rest label. If an argument is preceded by &rest, any arguments beyond the named arguments will be put into the &rest argument. The &rest argument must be the last argument currently.

(defun another-example (a b &rest everything-else)
  (... do something with a, b and the something-else array ...))

(another-example 1)         ; this will raise an exception
(another-example 1 2)       ; a will be 1, b will be 2, and everythingElse will be []
(another-example 1 2 3 4 5) ; a will be 1, b will be 2, and everythingElse will be [3,4,5]

The interaction of &optional and &rest

If both &optional and &rest arguments are used, the &optionals are filled in before arguments spill over into &rest


Lambdas are defined just like functions (with &rest and &optional args, if you so desire), but with the lambda keyword.

In fact, (defun name (args) body) is functionally equivalent to (defvar name (lambda (args) body)).

Control flow


if takes three arguments — the condition that is checked, the true body, and the false body. if always has a return value, which is achieved by wrapping every if statement in an anonymous self-calling function (in js).

(if (= 2 (+ 1 1)) 'yes 'no) ;=> the return value of this will be "yes"

; for multi-statement blocks, use progn:
(if (defined? foo)
     (say 'hi))
    (complain "bad at examples")

; in this horrible example, if foo is defined, the first block will be
; called and the return value of say("hi") will be returned. If foo is
; undefined, the second block will be called and 42 will be returned.


when is like the true branch of if, but doesn’t require progn for multi-statement blocks.

(when (<= 2 rainbow-count)
  (puts "oh my god, double rainbow")


The most up to date documentation will always be which includes an as-you-type in-browser sibilant compiler.
Check out sibilant itself, which is written 100% in sibilant to get a sense of what’s possible.
Also, check out macros.lisp to see how easy it is to write new compiler macros.