Skip to content
Javascript with a lisp
JavaScript Common Lisp
Find file
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



There’s a ridiculous amount of documentation I need to do, but I wanted to get this out.

You’ve seen coffeescript, the language that is parsed by javascript and “compiles” to javascript. Sibilant is like that, but inspired by lisp. Everything is a list. Macros that output javascript can be defined in sibilant and included at translation time.


bash$ npm install sibilant


bash$ sibilant
sibilant> (defvar sys (require 'sys))
sibilant> (sys.puts "hello world")
hello world
sibilant> (defun hello (&rest args)
...est args) > (sys.puts (sys.inspect args)))
result: [Function]
sibilant> (hello 'world)
[ 'world' ]
sibilant> (+ 5 3)
result: 8
sibilant> * ;this is the return value of the last statement
result: 8

Convert a file

bash$ sibilant package.lisp

This outputs to stdout. To print to a file, use unix.

bash$ sibilant package.lisp > package.json

This is actually how package.json is generated.




"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")


Check out the examples directory to get a sense of what’s possible. Also, check out macros.lisp to see how easy it is to write new compiler macros.

Didn’t feel like clicking? Here’s the example from, translated to sibilant:

(defvar http (require 'http))

(defvar server (http.create-server (lambda (request, response)
  (response.write-head 200 (hash "Content-Type" "text/plain"))
  (response.end "Hello World\n"))))

(server.listen 8124 "")
(console.log "Server running at")


Something went wrong with that request. Please try again.