kei-lisp
v2.2.0
Published
A Lisp interpreter implemented in TypeScript
Maintainers
Readme
kei-lisp
A Lisp interpreter implemented in TypeScript. Use it from the command line as an interactive REPL, or embed it in your application as a library.
Features
- Common Lisp-inspired syntax (
setq,defun,let,cond, ...) - CLI tool and embeddable library
- ESM and CommonJS dual output with TypeScript types
- Zero runtime dependencies
Installation
# Use as a CLI tool
npm install -g kei-lisp
# Use as a library
npm install kei-lispRequires Node.js >= 24.
Quick start
CLI
$ kei-lisp
>> (+ 1 2 3)
6
>> (defun square (x) (* x x))
square
>> (square 7)
49
>> (exit)
Bye!kei-lisp --version # Show version
kei-lisp --help # Show helpLibrary
import { LispInterpreter, Cons } from 'kei-lisp';
const interpreter = new LispInterpreter();
const result = interpreter.evalString('(+ 1 2 3)');
console.log(Cons.toString(result)); // "6"CommonJS is also supported:
const { LispInterpreter, Cons } = require('kei-lisp');API
| Export | Description |
| ------------------- | ---------------------------------------------------------- |
| LispInterpreter | Programmatic interpreter (parse / eval / environment) |
| Repl | Interactive REPL on stdin / stdout |
| Cons | Cons cell (pair) data type with type predicates |
| InterpretedSymbol | Lisp symbol (interned) |
| KeiLispError | Base class for parse / eval failures (subclass of Error) |
| ParseError | Thrown on parse failure (subclass of KeiLispError) |
| EvalError | Thrown on evaluation failure (subclass of KeiLispError) |
| ExitError | Thrown when (exit) is evaluated; catch to handle exit |
LispInterpreter
const interpreter = new LispInterpreter();
// Evaluate source and return the last expression's result
interpreter.evalString('(+ 1 2)'); // 3
// Evaluate multiple expressions and return all results
interpreter.evalAll('(setq x 10) (* x x)'); // [10, 100]Repl
import { Repl } from 'kei-lisp';
// Start an interactive REPL on stdin/stdout
new Repl().run();Error handling
evalString, evalAll, eval, and parse throw on failure. Catch the
errors at the boundary; ExitError is intentionally separate from the
KeiLispError family so a generic Lisp-error catch does not swallow it.
import { LispInterpreter, KeiLispError, ExitError } from 'kei-lisp';
const interpreter = new LispInterpreter();
try {
interpreter.evalString(userInput);
} catch (error) {
if (error instanceof ExitError) {
// Lisp called (exit) — graceful shutdown
return;
}
if (error instanceof KeiLispError) {
// ParseError or EvalError — display to user and continue
console.error(`${error.name}: ${error.message}`);
return;
}
throw error;
}Examples
Arithmetic
(+ 1 2 3) ;; => 6
(- 10 3) ;; => 7
(* 4 5) ;; => 20
(/ 100 4) ;; => 25
(mod 10 3) ;; => 1Lists
(list 1 2 3) ;; => (1 2 3)
(car (list 1 2 3)) ;; => 1
(cdr (list 1 2 3)) ;; => (2 3)
(cons 0 (list 1 2 3)) ;; => (0 1 2 3)
(length (list 1 2 3)) ;; => 3Defining functions
(defun factorial (n)
(if (= n 0) 1 (* n (factorial (- n 1)))))
(factorial 10) ;; => 3628800Conditionals and bindings
(if (= 1 1) "yes" "no") ;; => "yes"
(cond ((= 1 2) "a") ((= 1 1) "b") (t "c")) ;; => "b"
(let ((x 10) (y 20)) (+ x y)) ;; => 30Runnable TypeScript examples live in examples/:
pnpm build # build the package once
pnpm exec tsx examples/basic-eval.ts
pnpm exec tsx examples/exit-handling.tsReference
In-depth documentation of each language area:
- API Reference — TypeScript / JavaScript library API
- Atoms — numbers, symbols, strings, nil
- Cons — pairs and lists
- Built-in Functions — full Lisp reference
Development
git clone https://github.com/ike-keichan/kei-lisp.git
cd kei-lisp
pnpm install
pnpm startRequires pnpm and Node.js 24+
(see .node-version for the exact version).
| Command | Description |
| ----------------- | ----------------------------------------- |
| pnpm build | Build for distribution |
| pnpm start | Run the built CLI |
| pnpm test | Run tests |
| pnpm test:watch | Run tests in watch mode |
| pnpm check | Run all checks (format, lint, spell, ...) |
| pnpm fix | Auto-fix format and lint issues |
