Fully-featured, blazingly-fast language that compiles to beautiful, hand-made-like JavaScript. Implemented in less than 100 lines.
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



LiScript replaces JavaScript's syntax by lisp's powerful S-Expressions and macro system.

Differently from other languages that compile to JavaScript, it does not try to make it a completely different language - which is the root of many common problems such as messy generated code, overheads, painful compilation and hard debugging - all of which compensate for the theoricall benefits. Instead, as very thin layer - the whole implementation being less than 100 lines - it's generated code is fast, readable, beautiful, zero-overheaded, workeable and easy to debug.

In summary, it's a programming language that combines JavaScript's high level features, ridiculous cross-platformness and blazing speed with lisp's awesome, powerful syntax loved by hackers all around the world. For more info on it, I recommend reading Paul Graham's "Beating the Averages": http://www.paulgraham.com/avg.html


There's no installation guide yet (this will be updated soon). For now, just download LiScript, require the file on node.s or include it in a HTML script tag and call LiScript.compile("(your source code)"). This will return the compiled JavaScript.

You can also try it online: http://evanhahn.github.com/Try-LiScript/

Tutorial / Using

Using LiScript is very easy. I'll expose the whole language with examples. If you find trouble understanding those, you could may on S-Expressions. Looking at the source could be a good idea. Also, feel free to contact me! Notice that this is the crude form of the language - to actually use it you'll certainly load with macros which will calibre the syntax to fill your needs. The language core is very easy. It has 4 basic forms, which map directly to their JavaScript counterparts:

  • String: "this is a string"
  • Array: ["this" "is" "an" "array"]
  • Object: {foo 5 bar 7}
  • Function/macro calling: (func 1 2 3)

It also comes with the following functions out-of-the-box:

  • Math operators: sum sub mul div mod
(sum 1 2 3 (mul 2 2)) 
Output: 10
  • Boolean comparisons: and or eq dif less greater lesseq greatereq
(eq 2 2)
Output: true
  • Assignment: def
(def foo 5)
This is the same as "foo = 5" in JavaScript.
  • Conditional: if
(def rnd (Math.random))
(if (less rnd 0.05)
	(console.log "You won :D")
	(console.log "Bad luck, try again."))
Output: ?
  • Function definition: fn
(fn (a b) (sum a b))
Output: function(a,b){ return a+b; };
  • Member access: get set
(def my_obj {a 1 b 2 c 3})
(set my_obj "b" 4)
(console.log (get my_obj "b"))
Output: 4
  • Loop: while
(def i 0)
(while (less i 4) 
	(console.log i)
	(def i (sum i 1)))
Output: 0 1 2 3
  • Iteration: iter
(iter {a 1 b 2 c 3} 
		(console.log [key val]))
Output: ["a",1] ["b",2] ["c",3]
  • Macro: defmacro Macros work by modifying the code before it's compiled to JavaScript. and it couldn't be easier: just return an array of strings representing the new form of your code! Let's make a macro that inverts an expression:
(defmacro swap (a b) [b a])
(swap "test" console.log)
This becomes `(console.log "test")` which outputs `"test"`!

Another example:

(defmacro unless (cond T F) ["if" cond F T]) 
(def yell (fn (a) (call a "toUpperCase"))) 
(def im_sad false)
(unless im_sad (yell "What a great day!"))

This is an interesting fact about Lisp: clever user of macros can make the language sound just like speech. There's no syntax: just a bunch of phrases that tell your program what to do. Sometimes it's too abstracted away you don't even notice you are programming: (make me a sandwitch in 2 hours), one could perfectly make this work. Lisp code from a great hacker is a piece of art. But maybe you're the type that likes terse syntax and symbols? No problems...

  • Readers: defreader Readers are similar to macros, except they work for special forms (not parenthesis). Readers on LiScript are a little different: you just define a name and enclosing symbols. You can, then, further process it with normal macros. For example, lets define the form < a > to return the square of a:
(defreader square < >) 
(defmacro square (a) (mul a a)) 
(console.log <3>)
The form above becomes (console.log (square 3)),
which becomes (console.log (mul 3 3)),
which becomes (console.log 9),
which outputs 9. 

That is much simpler than traditional reader macros! For more advanced cases you can just edit the parser itself: it's a 25-lines-long function on the source, so it shouldn't be hard. Given how no other lisp-to-js language implement reader macros at all, it's pure win.

Well, that's it! This is the whole language. Again, the out-of-the-box package must be temperated with macros. For example, you could certainly improve the loops - a "for" macro could work as CoffeeScript's array comprehension. A "let" macro might prove handy, and a facility to concatenate arrays would make defining new macros easier. The point is: LiScript allows you to do whatever you want; you control the language!

Next steps:

LiScript is just a first step towards a goal: increasing programmer productivity to new levels. There is still needs some work - for example, "var x=3" is not an expression in JavaScript. Because of this, all variables are defined on the global scope. I'm thinking in a solution for this. Anyway, the idea is reaching a point of stability where the language doesn't need to be ever changed anymore, making it future-proof. At this point, efforts must be done towards the concretization of:

  1. A centralized, cloud-based, taggeable, computer-analyzable, queriable database of functions and macros (NOT libraries!)

  2. A powerful, shortcut-optimized, VIM inspired, web-based IDE to access those.

  3. A huge community with a good communication system. (this is the hard part ;/)

If this all interests you, feel free to contact me!