Wasm Interpreter for S-expression Processing — a tiny Lisp interpreter compiled to WebAssembly, designed as the foundation for programmable digital organisms.
WISP is a minimal but complete Lisp interpreter written in Rust, compiled to WebAssembly, and runnable in the browser. It's the substrate layer — a clean, extensible core that can later support persistence, self-inspection, multiple agents, and eventually self-replicating digital organisms.
This phase is just the interpreter + WASM + browser REPL. No agents, no replication, no networking — just a solid foundation.
# Build the WASM package
cd wisp
wasm-pack build --target web --out-dir ../www/pkg
# Serve the browser demo (from project root)
cd ../www
python3 -m http.server 8080
# or: npx serve .Open http://localhost:8080 in your browser.
cd wisp
cargo testWISP implements a small, coherent subset of Lisp:
| Type | Examples |
|---|---|
| Integer | 42, -7, 0 |
| Boolean | #t, #f |
| Symbol | foo, my-var, + |
| List | (1 2 3), () |
| Nil | nil |
| Form | Description |
|---|---|
(quote x) or 'x |
Return x unevaluated |
(if cond then else?) |
Conditional |
(define name value) |
Bind a value |
(define (f x y) body) |
Define a function (sugar) |
(lambda (params) body) |
Anonymous function |
(fn (params) body) |
Alias for lambda |
(let ((x 1) (y 2)) body) |
Local bindings |
(begin e1 e2 ...) |
Sequential evaluation |
(do e1 e2 ...) |
Alias for begin |
| Category | Functions |
|---|---|
| Arithmetic | + - * / mod abs min max |
| Comparison | = < > <= >= |
| Logic | not and or |
| Lists | list cons car cdr null? length |
| Type checks | number? symbol? list? boolean? |
| Utility | display |
;; Arithmetic
(+ 2 3) ; => 5
(* (+ 1 2) (- 10 5)) ; => 15
;; Functions
(define (square x) (* x x))
(square 7) ; => 49
;; Recursion
(define (factorial n)
(if (= n 0) 1
(* n (factorial (- n 1)))))
(factorial 10) ; => 3628800
;; Closures
(define (make-adder n)
(lambda (x) (+ x n)))
(define add10 (make-adder 10))
(add10 32) ; => 42
;; Higher-order functions
(define (map f lst)
(if (null? lst) '()
(cons (f (car lst))
(map f (cdr lst)))))
(map square '(1 2 3 4 5)) ; => (1 4 9 16 25)wisp/src/
├── types.rs # Value enum, error type
├── parser.rs # Tokenizer + recursive-descent parser
├── env.rs # Lexical environments with scope chains
├── eval.rs # Tree-walking evaluator
├── stdlib.rs # Built-in functions
├── interpreter.rs # Top-level Interpreter facade
├── wasm.rs # WebAssembly bindings (wasm-bindgen)
└── lib.rs # Crate root
www/
├── index.html # Browser REPL (self-contained)
└── pkg/ # WASM build output (generated)
The WASM interface exposes two functions:
wisp_eval(source: string) → string— evaluate Lisp source, return resultwisp_reset()— clear all definitions, reset to fresh state
- Vec-based lists instead of cons cells — simpler, cache-friendly, easy to serialize later.
- Environment store (indexed by usize) instead of
Rc<RefCell<Env>>— avoids reference cycles, opens path to persistent/serializable environments. - No tail-call optimization yet — keeps the evaluator simple. Natural future addition.
- Clone-heavy values — prioritizes clarity over performance. Sharing/interning is a future optimization.
- Single-file browser demo — no build tooling needed for the frontend.
This interpreter is the substrate for a digital organism system. Planned layers:
- Persistence — serialize environments and programs to durable storage
- Self-inspection — let programs examine their own structure and environment
- Multiple agents — independent Lisp processes with message passing
- Resource budgets — computation limits, energy metaphors
- Mutation — controlled random modification of programs
- Replication — programs that can copy and modify themselves
- Selection — fitness-based survival in a shared world
Each layer builds on the previous one. The current interpreter is designed so these extensions don't require rewriting the core.
MIT