0.0.36 • Published 10 years ago
lisp2js v0.0.36
lisp2js beta (clojure like syntax)
By Yiyi Wang (shd101wyy)
Simple Lisp that compiles to JavaScript (targeting ECMAScript 6)
So ECMAScript 5 might not work.
As es6 is not fully supported, the language will compile to es5.
npm / github
Installation
npm -g install lisp2js
How to run
lisp2js # repl
lisp2js [file1.lisp] # run file1.lisp
lisp2js [file1.lisp] [file2.js] # compile [file1.lisp] to js file [file2.js]
Use lisp2js in Browser
<script src="lisp2js.js"></script>
<script>
var output = lisp.compile("(def x 12)"); // compile/eval expression, then return compiled result.
</script>
Click Me to Try it Online
Online REPL
all comma, tab, space will be ignored.
Examples
Basics
comment
; semicolon is used as comment
;; this is comment
define variable value
(def x 12)
(def ->this*name$invalid@in*js 13) ;; a invalid js variable name, which will be replaced with another name.
(def ** Math.pow)
var x = 12;
var _$45__$62_this_$42_name$invalid_$64_in_$42_js = 13; // all invalid characters are replaced with its own charcode.
var _$42__$42_ = Math.pow;
- change variable value
(set! x 15)
x = 15;
- define function
(defn add [a b]
(+ a b))
function add(a, b){
return a + b;
}
- call function
(add 3 4)
add(3, 4);
- define function with default parameters
(defn add [:a 12 :b 3]
(+ a b))
function add(a, b) {
a = (a === void 0 ? 12 : a);
b = (b === void 0 ? 3 : b);
return (a + b);
};
- define function with keyword parameters
(defn add [x {:y 1 :z 2}]
(+ x y z))
(add 0) ;; 3
(add 1 :y 3) ;; 6
function add(x, __lisp_args__) {
var __lisp_args_v__;
__lisp_args__ = (__lisp_args__ === void 0 ? {} : __lisp_args__);
var y = ((__lisp_args_v__ = __lisp_args__.y) === void 0 ? 1 : __lisp_args_v__);
var z = ((__lisp_args_v__ = __lisp_args__.z) === void 0 ? 2 : __lisp_args_v__);
return (x + y + z);
};
add(0);
add(1, {
y: 3
});
- call function with named(keyword) parameters
(defn add [{:a 1 :b 2}] (+ a b))
(add) ;; => 3
(add :a 3 :b 4) ;; => 7
(add :b 3) ;; => 4
function add(__lisp_args__) {
var __lisp_args_v__;
__lisp_args__ = (__lisp_args__ === void 0 ? {} : __lisp_args__);
var a = ((__lisp_args_v__ = __lisp_args__.a) === void 0 ? 1 : __lisp_args_v__);
var b = ((__lisp_args_v__ = __lisp_args__.b) === void 0 ? 2 : __lisp_args_v__);
return (a + b);
};
add();
add({
a: 3,
b: 4
});
add({
b: 3
});
- define function with rest parameters
(defn add [a & b] ;; b here is Array
(+ a b[0]))
(defn add [a . b] ;; b here is List
(+ a (car b)))
function add(a) {
for (var b = [], $__0 = 1; $__0 < arguments.length; $__0++) b[$__0 - 1] = arguments[$__0];
return (a + b[0]);
};
function add(a) {
for (var b = [], $__0 = 1; $__0 < arguments.length; $__0++) b[$__0 - 1] = arguments[$__0];
b = list.apply(null, b);
return (a + car(b));
};
- anonymous function
(fn [a :b 13 & c]
(+ a b c[0]))
function (a, b){
for (var c = [], $__0 = 2; $__0 < arguments.length; $__0++) c[$__0 - 2] = arguments[$__0];
b = (b === void 0 ? 13 : b);
return (a + b + c[0]);
};
- do. run a series of exps.
(do (+ 1 2)
(- 3 4)
(* 5 6))
(fn []
(do (+ 1 2)
(- 3 4)
(* 5 6)))
(if 1
(do (def x 1) (def y 2))
(do (def x 2) (def y 1)))
(1 + 2);
(3 - 4);
(5 * 6);;
function() {
(1 + 2);
(3 - 4);
return (5 * 6);;
};
if (1) {
var x = 1;
var y = 2;
} else {
var x = 2;
var y = 1;
};
- if
(if 1 2 3)
(def x (if 1 2 3))
if (1) {
2
} else {
3
};
var x = (1 ? 2 : 3);
- cond
(cond test1 (do stm1 stm2)
test2 (do stm3 stm4)
test3 stm5
else stm6)
if (test1) {
stm1;
stm2;
} else if (test2) {
stm3;
stm4;
} else if (test3) {
stm5;
} else {
stm6;
};
- case
(defn test [x]
(case x
"apple" "This is apple"
"orange" "This is orange"
else "This is nothing"))
function test(x) {
switch (x) {
case "apple":
return "This is apple";
case "orange":
return "This is orange";
default:
return "This is nothing";
};
};
- let (es5) // I might change this to es6 let in the future
(let [x 1
y 2
x (+ x y)
z 4]
(+ x y z))
(+ (let [x 1 y 2] (- x y))
3)
(defn test []
(let x 1 y 2 (+ x y)))
((function() {
var x = 1;
var y = 2;
x = (x + y);
var z = 4;
return (x + y + z)
})());
(((function() {
var x = 1;
var y = 2;
return (x - y)
})()) + 3);
function test() {
return ((function() {
var x = 1;
var y = 2;
return (x + y)
})());
};
- throw
(throw "Too Big")
throw "Too Big";
- yield
(defn test []
(yield 1)
(yield 2))
(def x (test))
(x.next) ;; 1
(x.next) ;; 2
(x.next) ;; stop
function test() {
yield 1;
yield 2;
return;
};
var x = test();
x.next();
x.next();
x.next();
- try/catch/finally
(try (console.log "This is try")
catch e (console.log "This is catch")
finally (console.log "This is finally"))
try {
console.log("This is try");
} catch (e) {
console.log("This is catch");
} finally {
console.log("This is finally");
};
- some operators
(= 1 1)
(+ 1 2 3)
(- 1 2 3)
(* 1 2 3)
(/ 1 2 3)
(* (+ 1 2) (- 3 4))
(> 1 2 3 4)
(<= 1 2 3 4)
(&& true false)
(|| 1 2)
(| 1 0x12)
(and true false)
(or true false)
(not true)
(1 === 1);
(1 + 2 + 3);
(1 - 2 - 3);
(1 * 2 * 3);
(1 / 2 / 3);
((1 + 2) * (3 - 4));
(1 > 2 && 2 > 3 && 3 > 4);
(1 <= 2 && 2 <= 3 && 3 <= 4);
(true && false);
(1 || 2);
(1 | 0x12);
(true && false);
(true || false);
(!true);
- get
(get "abcd" 'length)
(get console .log)
"abcd"["length"];
console.log;
- ->
(-> console (.log "Hello World"))
(-> $ (.post "test.php")
(.done (fn () "done"))
(.fail (fn () "fail")))
(-> "i am cool"
.length)
console.log("Hello World");
$.post("test.php").done(function() {
return "done";
}).fail(function() {
return "fail";
});
"i am cool".length;
- class (this might be buggy, I will implement class in es6 in the future)
(class Animal
:constructor (fn [age] ;; define constructor
(set! this.age age))
:showAge (fn [] ;; define method
(console.log "Called from Animal")
(console.log this.age)))
(class Dog extends Animal
:constructor (fn [age] ;; define constructor
(super age)) ;; call superclass constructor
:showAge (fn [] ;; define method
(console.log "Called from Dog")
(super.showAge)) ;; call superclass method
:bark (fn [] ;; define method
(console.log "Bark!")))
(def dog (new Dog 5))
(dog.showAge) ;; Called from Dog
;; Called from Animal
;; 5
(dog.bark) ;; Bark!
- loop
;; calculate factorial 10
(loop [i 10
acc 1]
(if (= i 0)
acc
(recur (- i 1)
(* i acc))))
(function __lisp__recur__$0(i, acc) {
if ((i === 0)) {
return acc
} else {
return __lisp__recur__$0((i - 1), (i * acc))
};
})(10, 1);
- new
(def x (new Array 1 2 3 4))
var x = (new Array(1, 2, 3, 4));
- in
(in 'a {'a 12})
("a" in {"a": 12});
- instanceof
(instanceof [1 2 3] Array)
([1, 2, 3] instanceof Array)
- List functions
- To enable List datatype, include lisp.js from https://github.com/shd101wyy/List_for_FP
- after you compile your .lisp file to javascript file.
- This file will give you 4 functions: car, cdr, cons, list.
and 1 datatype: $List
- See the link above for more information.
- define a list.
(def x '(1 2 3))
var x = cons(1, cons(2, cons(3, null)));
- quasiquote
(def x 12)
`(~x x) ;; => (12 x)
var x = 12;
cons(x, cons("x", null));
- car, cdr, cons, list
(def a 1)
(def b 2)
(def c (cons a (cons b '()))) ;; => (1 2)
(car c) ;; => 1
(cdr c) ;; => (2)
(def l (list a b)) ;; => (1 2)
var a = 1;
var b = 2;
var c = cons(a, cons(b, null));
car(c);
cdr(c);
var l = list(a, b);
Use JavaScript Object/Array
define Array
(def x [1 2 3])
var x = [1, 2, 3];
- define Object
(def x {:a 12 b 13 "c" 14})
// es6
var x = {a: 12, [b]: 13, "c": 14};
- es6 define value
(def [x y z] [1 2 3])
(def {:m :n} {:m 12 :n 20})
// es6
var [x, y, z] = [1, 2, 3];
var {
m, n
} = {
m: 12,
n: 20
};
- change value
(def x [1 2 3])
(set! x[0] 12)
(def y {:a 12 :b 13 :c (fn (a b) (+ a b))})
(set! y.a 13)
(set! y["a"] 13)
var x = [1, 2, 3];
x[0] = 12;
var y = {
a: 12,
b: 13,
c: function(a, b) {
return (a + b);
}
};
y.a = 13;
y["a"] = 13;
- get value
(def y {:a 12 :b 13 :c (fn (a b) (+ a b))})
(y.add y.a y.b)
var y = {
a: 12,
b: 13,
c: function(a, b) {
return (a + b);
}
};
y.add(y.a, y.b);
recur
similar to recur in clojure
- recur
(defn test [n]
(cond (= n 0) 0
1 (recur (- n 2)) ;; recur here means test
else (recur (- n 1))))
;; anonymous function recur
((fn [n acc]
(if (= n 0)
acc
(recur (- n 1) (* n acc)))) 10 1) ;; recur <=> that anonymous function
var test = function(n) {
if ((n === 0)) {
return 0;
} else if (1) {
return test((n - 2));
} else {
return test((n - 1));
};
};
(function __lisp__recur__$0(n, acc) {
if ((n === 0)) {
return acc;
} else {
return __lisp__recur__$0((n - 1), (n * acc));
};
})(10, 1)
Macro
- define a macro (unhygienic right now)
(defmacro square [x] `(* ~x ~x))
(square 12)
(defmacro square-with-different-params
[x] `(* ~x ~x)
[x y] `(+ (* ~x ~x) (* ~y ~y)))
(square-with-different-params 12)
(square-with-different-params 15 16)
(12 * 12);
(12 * 12);
((15 * 15) + (16 * 16));
- macro-expand: expand a macro form
(defmacro square [x] `(* ~x ~x))
;; the macro-expand function will expand the macro until it no longer represents a macro form.
(macro-expand '(square 12)) ; => '(* 12 12)
(defmacro test [x] `(test (+ 1 ~x)))
;; macro-expand can also expand macro forms for n times.
(macro-expand '(test 1) 2) ; => '(test (+ 1 (+ 1 1))) this will expand macro twice.
(macro-expand '(test 1) 3) ; => '(test (+ 1 (+ 1 (+ 1 1)))) this will expand macro for 3 times.
However, the macro implementation still has errors.
Change Log
- Version 0.0.36
- 2015/6/14
- begin to use clojure like syntax.
- 2015/3/15
- Version 0.0.33
- fix one macro bug
- add =>
- eg:
(=> (x y) (+ x y)) ;; es6 (x, y) => {return x + y};
- Version 0.0.31 ~ 0.0.32
2015/3/8
- change code generation for class statement.
- add macro-expand function.
eg:
(defmacro square (x) `(* ~x ~x)) ;; the macro-expand function will expand the macro until it no longer represents a macro form. (macro-expand '(square 12)) ; => '(* 12 12) (defmacro test (x) `(test (+ 1 ~x))) ;; macro-expand can also expand macro forms for n times. (macro-expand '(test 1) 2) ; => '(test (+ 1 (+ 1 1))) this will expand macro twice. (macro-expand '(test 1) 3) ; => '(test (+ 1 (+ 1 (+ 1 1)))) this will expand macro for 3 times.
2015/3/4
- fix one macro bug.
Version 0.0.30
- add class support (this might be buggy though)
eg:
(class Animal :constructor (fn (age) ;; define constructor (= this.age age)) :showAge (fn () (console.log "Called from Animal") (console.log this.age))) (class Dog extends Animal :constructor (fn (age) ;; define constructor (super age)) ;; call superclass constructor :showAge (fn () (console.log "Called from Dog") (super.showAge)) ;; call superclass method :bark (fn () (console.log "Bark!"))) (def dog (new Dog 5)) (dog.showAge) ;; Called from Dog ;; Called from Animal ;; 5 (dog.bark) ;; Bark!
Version 0.0.28
- 2015/3/1
- add case statement.
- eg:
(def test (x) (case x "apple" "This is apple" "orange" "This is orange" else "This is nothing")) (test "pear") ;; => This is nothing (test "apple") ;; => This is apple (test "orange") ;; => This is orange
- fix one if and cond bug.
- 2015/2/25
- fix demo link error.
- 2015/2/24
- add loop macro
- eg:
;; calculate factorial 10 (loop i 10 acc 1 (if (== i 0) acc (recur (- i 1) (* i acc))))
- 2015/2/23
- add REPL demo
- fix <= >= < > == != comparison operator bug, they now support multiple arguments.
- eg:
(== 1 1 1) (<= 1 2 3 4 5 2)
- Version 0.0.24
- 2015/2/22
- add -> macro
- eg:
(-> console (.log "Hello World")) (-> $ (.post "test.php") (.done (fn () "done")) (.fail (fn () "fail"))) (-> "i am cool" .length)
console.log("Hello World"); $.post("test.php").done(function() { return "done"; }).fail(function() { return "fail"; }); "i am cool".length;
- Version 0.0.20 - 0.0.22
- 2015/2/17
- Happy New Year []~( ̄▽ ̄)~*
- Add and, or, not macros that behave the same as && || !
- Change default parameters and keyword parameters.
- For example:
- Default Parameters
(def add (:a 1 :b 2) (+ a b)) (add) ;; => 3 (add 2) ;; => 4 (add 3 4) ;; => 7
- Keyword Parameters
(def add ({:x 1 :y 2}) (+ x y)) (add) ;; => 3 (add :x 3) ;; => 5 (add :y 6) ;; => 7 (add :x 4 :y 5) ;; => 9 (add :y 1 :x 5) ;; => 6
- Version 0.0.18
- 2015/2/16
- Add yield and throw support.
- 2015/2/9
- Improve compatibility with es5
- 2015/2/7
- Change the way of defining the default parameters and calling function with named parameters
- 2015/1/31
- Fix one macro bug.
- 2015/1/26
- Change do function.
(do ...) will be wrapped as function when it is argument or assignment value.
- Change do function.
- Version 0.0.13
- add in support.
(in 'a {'a 12})
("a" in {"a": 12});
- add in support.
- Version 0.0.12
- fix one macro bug.
- 2015/1/23
- change . & for rest parameters
- . => list
- & => array
(def add (a & b) ;; b here is Array (+ a b[0])) (def add (a . b) ;; b here is List (+ a (car b)))
// es6 var add = function(a, ...b){ return a + b[0]; } var add = function(a, ...b) { b = list.apply(null, b); return (a + car(b)); };
- 2015/1/19
- add get fn
- fix "abc".length like exp bug.
2015/1/14
- add cond
- add recur support
- add try/catch/finally support
- change if statement
Went snowboarding and fell down too many times. I twisted my wrist unfortunately. (T_T)
2015/1/7
- add support for fn with name .
(fn add (x) (+ x y))
function add(x) {
return (x + y);
};
* fix one macro bug
- 2015/1/5
- add support for const
- change let . see doc above.
- fix several bugs.
- 2015/1/5 First Release
- There are still lots of bugs.
- ...
MIT License ;)
0.0.36
10 years ago
0.0.35
10 years ago
0.0.34
10 years ago
0.0.33
10 years ago
0.0.32
10 years ago
0.0.31
10 years ago
0.0.30
10 years ago
0.0.29
10 years ago
0.0.28
10 years ago
0.0.27
10 years ago
0.0.26
10 years ago
0.0.25
10 years ago
0.0.24
10 years ago
0.0.23
10 years ago
0.0.22
10 years ago
0.0.21
10 years ago
0.0.20
10 years ago
0.0.18
10 years ago
0.0.17
10 years ago
0.0.16
10 years ago
0.0.15
10 years ago
0.0.13
10 years ago
0.0.12
10 years ago
0.0.11
10 years ago
0.0.10
10 years ago
0.0.9
10 years ago
0.0.8
11 years ago
0.0.7
11 years ago
0.0.6
11 years ago
0.0.5
11 years ago
0.0.4
11 years ago
0.0.3
11 years ago
0.0.2
11 years ago
0.0.1
11 years ago