Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Javascript with a lisp
JavaScript Common Lisp
tag: v0.0.5

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
bin
examples
lib
public
test
.gitignore
README.textile
package.json
package.lisp

README.textile

Sibilant

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.

Installation

bash$ npm install sibilant

Repl

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.

Language

Literals

Strings

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

Multiline strings are okay:

"this is a
multiline string"

Numbers

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

Variables

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.

Quoting

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

Lists

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

Defining a variable

(defvar foo "foo now has this value")

Hashes

(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

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

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)
    (progn
     (call-your-mom)
     (say 'hi))
  (progn
    (complain "bad at examples")
    (42)))

; 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

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")
  (upload-to-youtube))

Examples

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 nodejs.org, 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 "127.0.0.1")
(console.log "Server running at http://127.0.0.1:8124/")

Contributing

Something went wrong with that request. Please try again.