Skip to content
This repository

Javascript with a lisp

This branch is 2 commits ahead and 178 commits behind master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 bin
Octocat-spinner-32 lib
Octocat-spinner-32 public
Octocat-spinner-32 src
Octocat-spinner-32 test
Octocat-spinner-32 .gitignore
Octocat-spinner-32 README.textile
Octocat-spinner-32 package.json
Octocat-spinner-32 package.lisp
README.textile

Sibilant

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

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

Installation

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

$ npm install sibilant

CLI


-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.

To pass arguments to an executed file, append them after a "--", as follows:
$ sibilant -x myfile.lisp -- --arg-for-my-program=stuff

myfile.lisp will see process.argv as
[ 'sibilant', 'myfile.lisp', '--arg-for-my-program=stuff' ]

CLI Examples

To compile sibilant


$ git clone git://github.com/jbr/sibilant.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

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. Variables can contain numbers, but cannot begin with them. Asterisks become underscores. For example *global-variable* would become _globalVariable_ in javascript. Variables can end with a question mark or with an exclamation mark. These are translated to javascript as “__QUERY” and “__BANG” (for bang). For example, ready? becomes ready__QUERY and finish! becomes finish__BANG. I’m open to suggestions on better ways to translate ! and ? to javascript.

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

The most up to date documentation will always be sibilantjs.info 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.

How to get involved or learn more

Send a blank email to sibilant@librelist.com to join the mailing list.
Add any bugs or feature requests to the issues page or email the list.

Something went wrong with that request. Please try again.