>_ELISPRS REFERENCE
An Emacs Lisp runtime in Rust that runs .el outside Emacs. A Lisp-2 obarray (separate value/function cells) with lexical and dynamic binding and an elisp-correct reader that lowers to fusevm::Chunk and executes on the fusevm bytecode VM — the same Cranelift-JIT/AOT engine behind zshrs, stryke, awkrs, and vimlrs. There is no bespoke VM or JIT in elisprs.
What it is
Emacs Lisp has only ever run inside Emacs. elisprs takes the language out of the editor and runs .el as ordinary programs from the command line. It is the fifth language on the shared fusevm VM — elisp executes on the same Cranelift-JIT/AOT engine as the sibling languages, not a bespoke interpreter.
elisprs is a pure fusevm frontend: the reader (src/reader.rs) builds forms, macros expand, and the compiler (src/compiler.rs) lowers every top-level form to a fusevm::Chunk that runs on the VM (src/lib.rs::eval_forms → host::run_chunk). The elisp object heap (cons, symbol, vector, closure, hash-table cells) lives in ElispHost and rides through the VM as Value::Obj(u32) handles, reached from fusevm's extension handler. There is no tree-walk evaluator.
Architecture
Emacs Lisp is a Lisp-2 (separate value and function cells per symbol) with both lexical and dynamic scope — exactly what an off-the-shelf Lisp won't give you. elisprs owns those semantics and delegates execution to fusevm: reader → compiler → bytecode on the shared VM.
.el source → reader.rs → Value (fusevm Value; heap objects as Value::Obj handles)
→ macroexpand → compiler.rs → fusevm::Chunk → fusevm VM + Cranelift JIT / AOT
Lowers to fusevm
compiler.rs compiles each form to a fusevm::Chunk and host::run_chunk runs it on the VM — there is no interpreter. Hot numeric paths lower to native fusevm ops so they JIT/AOT-compile.
Reader is ours
A small elisp-correct reader handles core syntax other Lisps mis-tokenize — 1+/1-, #'foo, ?c, dotted pairs, and backquote (`/,/,@).
Lisp-2 + lexical/dynamic
A custom obarray gives every symbol a value cell and a function cell. let/closures bind lexically through captured Scope frames; special (defvar/defconst) vars bind dynamically through a specstack.
Heap as Value::Obj
Cons, symbol, vector, closure, subr, and hash-table cells live in the ElispHost arena and ride through fusevm as Value::Obj(u32) handles, resolved by the extension handler — no fork of the value enum.
Status & roadmap
The table reflects the current state of the tree, not aspiration.
| Component | State | Notes |
|---|---|---|
Elisp-correct reader (1+/#'/?c/:kw/dotted/backquote) | Working | Hand-written (src/reader.rs). |
| Lisp-2 obarray + lexical & dynamic binding | Working | Value + function cells; Scope frames + specstack. |
Special forms (22) + defmacro | Working | Macros expand and re-evaluate before lowering. |
| Subr standard library (234) | Working | Lists, numbers, strings, predicates, IO, functional + an elisp prelude. |
Standalone elisp binary + REPL | Working | File / -e / REPL. |
Form → fusevm::Chunk lowering | Working | compiler.rs; runs on fusevm via host::run_chunk. |
--aot / --aot-exe → fusevm::aot::compile_object | Working | Native object / standalone executable (src/aot.rs). |
LSP / DAP servers (--lsp / --dap) | Working | Full stdio servers (src/lsp.rs, src/dap.rs). |
Dotted pairs · backquote · lexical binding · setcar | Working | All implemented in the reader / host. |
rkyv bytecode cache (~/.elisprs/scripts.rkyv) | Working | src/cache.rs; warm runs skip read/lower. |
A taste
(defun fact (n) (if (<= n 1) 1 (* n (fact (1- n))))) (fact 6) ; => 720 (mapcar (lambda (x) (* x x)) '(1 2 3 4)) ; => (1 4 9 16) (mapcar #'1+ '(10 20 30)) ; => (11 21 31) (let ((x 10) (y 20)) (+ x y)) ; => 30 (format "%s = %d (hex %x)" 'count 255 255); => "count = 255 (hex ff)" (condition-case e (/ 1 0) (arith-error (format "caught %s" e))) ; => "caught (arith-error division by zero)"
Why elisprs
Elisp, standalone
Run .el as a program from the shell, with a REPL — no Emacs process required.
Faithful semantics
A real Lisp-2 with lexical and dynamic binding and separate function/value cells, not a Scheme wearing an Emacs hat.
One shared engine
elisp lowers to bytecode and inherits fusevm's three-tier Cranelift JIT and AOT — the same speedups that land for zshrs, stryke, awkrs, and vimlrs.
Ahead-of-time native
elisp --aot-exe links a .el against the elisprs runtime into a standalone native binary — no Emacs, no interpreter at run time.
Building from source
elisprs builds as a standalone Rust crate on top of fusevm (plus the LSP/regexp/cache support crates):
git clone https://github.com/MenkeTechnologies/elisprs cd elisprs cargo build --release cargo test # reader unit tests + end-to-end eval suite ./target/release/elisp examples/demo.el
License
elisprs is MIT OR Apache-2.0 — free and open source. See LICENSE.
Repository & links
- Engineering report — report.html (architecture, the fusevm lowering, the object heap, dependency posture)
- Source — github.com/MenkeTechnologies/elisprs
- Issues — github.com/MenkeTechnologies/elisprs/issues
- The shared VM — fusevm (also behind
zshrs,stryke,awkrs,vimlrs)