Skip to content

SaemonZixel/littlelisp.js

 
 

Repository files navigation

Little Lisp JS

A mini Lisp interpreter in JavaScript. Supports lists (obvs), function invocation, lambdas, OOP (!), TCO, Macroses (experimental), embedded JSON, if/while statements, numbers, strings and many other. Use "window" as default scope. Can call a JS functions, read/write object fields, call object methods, create JS objects.

Examples

(window.alert "ok!")
(setq x "ok!") 
(window.alert x)
(setq x "ok!") 
(window.alert (x.substring 0 2))
(setq x 1) 
(if (= x 1)
	(alert "x == 1") 
:else 
	(alert "x != 1")
)
;; examples of syntactic sugar (implemented in parser)
(x < 2)                ;; -> (< x 2)
((x < 2) && (x > -1))  ;; -> (&& (< x 2) (> x -1))
((x < 2) || (x > -1))  ;; -> (|| (< x 2) (> x -1))
(x + 1 2 3)            ;; -> (+ x 1 2 3) => x+1+2+3
(x ++)                 ;; -> (++ x) 
(++ x y z)             ;; -> increments variables x, y, z separately
(setq x (window.prompt "Value of X:")) ;; enter any value
(if (x = null)
	(setq x "(none)")
	(alert (+ "x = " x))
:else
	(alert (+ "x = " x))
)
(setq x (window.prompt "Value of X:")) 

;; empty string and 0 will be cast to false
(if x 
	(alert (+ "x = " x))
:elseif (x = " ")
	(alert "x = (empty string)")
:else
	(alert "x = (none)")
)
(setq i 0)
(while (i < 10)
	(console.log i)
	(++ i)
)
(setq i -1)
(while ((++ i) < 10)
	(console.log i)
	(if (i = 5) (break) 
	:else (continue))
)
(setq i 0 i2 0)
(while ((i < 10) && (i2 < 10))
	(console.log (i + i2))
	(++ i i2)
)
(setq i 0 list (1 2 3 4 5))
(while (i < list.length)
	(console.log list.@i)
	(++ i)
)
;; JS object creation example
(setq obj1 (new Object))
(setq obj1.a 123 obj1.b "abc")

(setq name "c")
(setq obj1.@name ())
(setq obj1.@name.0 111 obj1.@name.1 222 obj1.@name.2 333) 

(alert (obj1.c.join " ")) ;; show "111 222 333"
((lambda (x y) (window.alert (x + y)) "a" "b")
(defun f1 (x) (alert (x + " - ok!")))
(f1 "test 'f1'")
(typeof true) ;; "boolean"
(typeof undefined) ;; "undefined"
(typeof 123) ;; "number"
(typeof 123.45) ;; "number"
(typeof "abc") ;; "string"
(typeof abc) ;; "undefined" - because it's variable name 
(typeof :abc) ;; "atom" - in JavaScript it's String object with "atom_prefix" field
(typeof :abc-def-123) ;; "atom"
(typeof 'abc) ;; "atom"
(typeof #abc) ;; "atom"
(typeof it_is.0nly.1.at-om) ;; "undefined"
(typeof (1 2 3)) ;; "object" - return [1, 2, 3]
(typeof '(abc cde fgh)) ;; "object" - in JavaScript array is object
(typeof (new Object)) ;; "object"
(typeof null) ;; "object" - it's  historical bug of JavaScript language
(typeof 123 :eq "number") ;; return true
(catch (a.b)) ;; return Exception object (Error: "a" is undefined!)
(throw (new Error "Error!")) ;; throws JavaScript exception
;; evalute JS code
((new Function "" "alert(document.title);")) ;; show title of opened web page
;; embedded JSON
(setq obj1 {name: "object1", data:[1, 2, 3], toString: function(){ return this.name + "=" + this.data.join(","); }})

OOP examples

(defclass Class1
	:extends String
	:instvars "inst_var1 inst_var2"
	:constructor init
	:classvars "singleton_instance"
)

(defmeth-static Class1.getSingleton (arg1)(
	(if (Class1.singleton_instance = null)
		(setq Class1.singleton_instance (new Class1 arg1))
	)
	(return Class1.singleton_instance)
))

(defmeth Class1.alert (arg1) (
	(alert (this.inst_var1 + arg1))
))

;; will be constructor
(defmeth Class1.init (arg1) (
	(setq this.inst_var1 arg1)
	
	(if (arguments.length > 1)
		(setq arg_key 2)
		(while (arg_key < arguments.length)
			(put this arguments.@arg_key (get arguments (arg_key + 1)))
			(++ arg_key arg_key)
		)
	)
))

(setq tmp1 (new Class1 123 :inst_var2 "abc"))
(window.alert tmp1.inst_var1)
(tmp1.alert "456")

Macroses support (EXPERIMENTAL)

(defmacro assign (var_name value) `(setq ,var_name ,value))
(assign tmp 123)
(defmacro foreach (field_name _in obj _do code) 
	(setq tmp_keys (gensym) tmp_count (gensym) tmp_indx (gensym))
	
	`(let ((,tmp_keys (Object.keys ,obj)) (,tmp_count (get ,tmp_keys "length")) (,tmp_indx -1))
		(while ((++ ,tmp_indx) < ,tmp_count)
			(setq ,field_name (get ,tmp_keys ,tmp_indx))
			~code  ; Comma may be replaced to tilda
		)
	)
)

(foreach name :in document.location :do (console.log name))

About

A small Lisp interpreter in JavaScript

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 98.2%
  • Other 1.8%