Skip to content

zawatton/nelisp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,657 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NeLisp — Self-Hosted Emacs Lisp VM (v2.0)

Note on language: I’m a non-native English speaker. The phrasing in this README is shaped with help from an LLM, but the design decisions and technical claims are mine. If something reads oddly, please ask and I’ll clarify.

TL;DR

NeLisp is a from-scratch Emacs Lisp runtime where essentially the entire language layer (JIT, allocator, GC, coding-system, evaluator, bytecode interp, reader, special forms, builtin dispatcher, object file writers, native code emitters) is written in Elisp itself. The Rust footprint has been driven down to 11 LOC — a thin ABI shell holding extern "C" declarations and a cc_wrap_batch! macro that glues elisp-emitted .o files to the binary entry point.

v2.0 (2026-05-22) ships:

  • 11 LOC of Rust in build-tool/src/ (= 99.8% reduction from v1.0’s ~5,156 LOC src tree). See Pure-Elisp Migration Progress.
  • Cross-platform support on 5 targets — linux/x86_64, linux/aarch64, macos/x86_64, macos/aarch64, windows/x86_64 — with pure-elisp object-file writers (ELF, Mach-O, PE/COFF) and pure-elisp asm encoders (x86_64 with both SysV and Microsoft x64 ABIs, plus AArch64 AAPCS).

Use cases: running Elisp on machines without Emacs, and as a substrate for Lisp Machine / new-dialect experiments.

What NeLisp is

A research project to implement Emacs Lisp on a substrate other than the existing Emacs C core — modeled after SBCL (Common Lisp implemented in itself, on a small non-Lisp runtime) and deliberately not a Scheme rewrite (Guile-Emacs) or a Rust rewrite of the entire Emacs C core (Remacs).

Two layers. The language runtime is implemented in Elisp itself. Rust is now just an ABI shell — extern "C" declarations + a single cc_wrap_batch! macro invocation that exposes elisp-emitted .o symbols to the binary entry point. A build-time-only Elisp bootstrap evaluator lives in build-tool/ as an escape hatch until the native-compiled Elisp seed seam (Doc 49) ships end-to-end.

LoC split (2026-05-22): ~34k Elisp (= lisp/ ~22k + packages/ ~12k) vs 11 LOC Rust in build-tool/src/. Extension crates (sqlite / fileio / filenotify / process) live as sibling Cargo packages but are optional via --no-default-features.

History:

  • v1.0 (2026-04-27): ~54k Elisp vs ~19k Rust.
  • 2026-05-14 (post-v1.0): ~34k Elisp vs ~26k Rust (anvil-runtime crate deleted -5.8k, Phase 47 infrastructure added +7k).
  • v2.0 (2026-05-22): 11 LOC Rust in build-tool/src/ — 99.8% reduction. Achieved via systematic .o file migration: every function body that can be elisp-emitted is, leaving only the irreducible ABI link layer in Rust.

Elisp — the language runtime (v1.0 snapshot: 45 files, 54,511 LoC)

The breakdown below is the 2026-04-27 v1.0 snapshot and is retained for reference. Current totals (2026-05-14) are lisp/ 46 files ~20k LOC

  • packages/ 27 files ~14k LOC; see Pure-Elisp Migration Progress

for what shifted.

SubsystemFilesLoCPhase
JIT compiler (SSA + linear-scan, x86_64 + arm64; written in Elisp itself)1312,1967.1
Memory management (allocator + GC)56,2907.2–7.3
Lisp evaluator (reader, eval, special forms, closures, macros)74,035
Module loading and bootstrap32,1477.5
Coding-system (logic)11,9287.4
Bytecode interpreter11,845
Emacs compatibility shims31,680
Multi-threading / parallel worker pool (process-level concurrency, file-notify)51,405
Buffer model21,076
Other infrastructure (dev-audit, heap-types, EC bridge, entry point)41,094
Character tables (JIS, data)120,815

Rust — the no-Emacs path (v2.0: 11 LOC across 4 files)

Current Rust footprint (2026-05-22):

FileLOCPurpose
build-tool/src/lib.rs8extern "C" block + cc_wrap_batch! macro for elisp .o symbols
build-tool/src/eval/mod.rs1Inline-module statement (all eval logic via elisp .o)
build-tool/src/bin/nelisp.rs1CLI entry
build-tool/src/bin/sexp-abi-emit.rs1ABI offset dump for make sexp-abi-check
Total11

Extension crates (nelisp-syscall-* / nelisp-sqlite-rs / nelisp-runtime / nelisp-runtime-cli) live as sibling Cargo packages but are optional via --no-default-features.

v2.0 ships the four cores Emacs’s C core normally gives you — native compile, allocator, GC, coding-system — all written in Elisp itself. Object file writers, asm encoders, ABI-aware codegen for 5 OS×arch targets are also pure Elisp.

Two things Emacs proper doesn’t ship in the same form

  • A JIT compiler written in Elisp itself. Emacs 28+ has native-comp, but it depends on libgccjit (an external C library) and is used as AOT in practice. NeLisp’s JIT is ~12k LoC of Elisp source you can read end-to-end and modify, with runtime codegen via mmap + PROT_EXEC.
  • Real parallel execution. Emacs’s make-thread is cooperative — one Lisp thread runs at a time. NeLisp’s worker pool gives process-level concurrency under the same Lisp runtime, which is what made the orchestrator and the long-running MCP handler design tractable.

Pure-Elisp Migration Progress (v2.0, 2026-05-22)

The long-term goal was bin/nelisp Rust runtime LOC → 0 (pure-elisp self-host). v2.0 reaches an effective floor: 11 LOC Rust in build-tool/src/ (-99.8% from session-start 5,156 LOC). Every functional module has been migrated to elisp-emitted .o files; what remains in Rust is the irreducible ABI link layer.

Rust LOC reductions — the v2.0 march

The reduction was accomplished over a sustained series of ~80 waves (Wave α/β/γ/δ/ε in the May 2026 surgery + Waves a–z, aa–zz, aaaa–qqqq in the long-tail compression). Categories:

  • Structural migration (Waves a/b/c+/d/e/f/g/h/i/j/k/l/n2/v/w/o/m/q
    • 18s-O / 18v-FF / 18w-HH families): each Rust function body whose

    logic could be expressed in Phase 47 elisp was moved to a new lisp/nelisp-cc-*.el file; the Rust side kept only an extern "C" declaration and a thin cc_wrap! wrapper.

  • Macro consolidation (Waves α / β / aaaa / cc / r / x / zzz + cc_wrap_batch! Wave qqqq): repeated cc_wrap! invocations, NlBox scaffolding, define_nlbox!, mirror_op!, sexp_box_ptr_accessor!, etc. collapsed into single macro expansions.
  • Dead code removal (Waves d / 18z-WW / various): functions with zero Rust callers (mirror_clear_value, frame_bind_rust_direct, is_fbound, set_function, intern_constant, push_frame, pop_frame, bind_local, etc.) deleted after rewiring callers.
  • Module inlining (Waves hhhh / kkkk / llll / mmmm / nnnn / oooo / pppp): files reduced to single declarations were inlined into parent modules as mod foo { ... } blocks, then the parent itself collapsed to one physical line.
  • Doc/comment/blank-line strip (Waves gg / hh / nn): cosmetic compression eliminated -1,795 LOC in a single pass across 103 files.

Pure-Elisp substrate shipped

  • Phase 47 self-emission (Doc 85 / 91–97): ~7,550+ LoC of Elisp for the x86_64 + arm64 assemblers, ELF + Mach-O + PE/COFF writers, static linker, crt0, the Sexp DSL, and the Phase 47 compiler. 600+ ERT. (fact 5) compiles end-to-end to a native .o, links, and runs.
  • Sexp ABI freeze (Doc 100 §100.B/C): three-artifact contract ( docs/arch/sexp-abi.md + lisp/nelisp-sexp-layout.el + build-tool/src/bin/sexp-abi-emit.rs ) kept in sync by make sexp-abi-check. Unlocks elisp-emitted .o files calling Rust with a stable layout.
  • Cross-platform native emit (May 2026 — see Cross-Platform Support below): 5 OS×arch targets supported entirely from elisp.
  • GC pure-elisp (Doc 79 v7 Phase C Stage 5.3): Bacon-Rajan cycle collector at lisp/nelisp-stdlib-gc.el ( 806 LoC ).
  • All special forms, builtins, env / mirror / frame ops, NlBox Clone/Drop, reader (lexer + parser), JIT trampolines, syscall handlers — now live in elisp via Phase 47 .o.

Test gate

  • cargo test --release --lib = 10/10 pass (build-tool main lib shrunk to fit the 11 LOC core).
  • ERT coverage for elisp .o emission: 600+ tests including Win64-ABI-specific assertions (Wave 5).

Cross-Platform Support (v2.0, 2026-05-22)

NeLisp v2.0 builds and runs across 5 OS × architecture targets, with all object-file writers and asm codegen written in pure Elisp:

TargetObject writerAsm encoderABIgate
linux/x86_64nelisp-elf-write.elnelisp-asm-x86_64.elSysV AMD64
linux/aarch64nelisp-elf-write.elnelisp-asm-arm64.elAAPCS
macos/aarch64nelisp-mach-o-write.elnelisp-asm-arm64.elAAPCS
macos/x86_64nelisp-mach-o-write.elnelisp-asm-x86_64.elSysV AMD64
windows/x86_64nelisp-pe-write.elnelisp-asm-x86_64.elMicrosoft x64

Selected by target_os / target_arch at cargo build time. The PE/COFF writer (nelisp-pe-write.el, 765 LoC) and the Windows-specific codegen path (Phase 47 compiler --abi 'win64 mode with shadow space allocation + RCX/RDX/R8/R9 arg-reg remapping + RBP/RBX/RDI/RSI/R12-R15 callee-save) are pure elisp.

Deferred: aarch64 Windows (arm64ec) — currently x86_64 Windows only.

Status — v2.0 (2026-05-22)

NeLisp v2.0 — Rust core reduced to 11 LOC + cross-platform support across 5 OS×arch targets — and v1.0’s standalone deployment paths:

  1. Stage D v2.0 — bundled-Emacs tarball (~25 MB compressed). bin/anvil resolves a stripped Emacs from $ANVIL_HOME/emacs/bin/emacs first, so a host without apt install emacs can still run NeLisp. Existing dev checkouts fall through to system PATH unchanged. See README-stage-d-v2.0.org and RELEASE_NOTES.md.
  2. Phase 8.0 (v1.0) — Rust-side Elisp interpreter + MCP stdio server. bin/anvil mcp serve --no-emacs starts an MCP JSON-RPC server with zero Emacs process spawn: a single anvil-runtime Rust binary (~421 KB) implements the reader, evaluator, MCP protocol, and anvil tool registry. See docs/design/44-phase8.0-rust-elisp-interpreter.org (LOCKED).

    Post-v1.0 update (2026-05-09): Phase B Final B Stage 2 deletes the anvil-runtime Rust crate entirely. bin/anvil-runtime is now a pure-shell wrapper that drives a persistent UNIX-socket daemon running the MCP loop in Elisp (scripts/anvil-runtime-server-loop.el) on top of the standalone nelisp binary. Same MCP JSON-RPC surface, no Rust crate.

Install

Two paths.

Prerequisites by platform

The build itself (cargo build --release) is identical across platforms; only the toolchain prereqs vary. After the build, target/release/nelisp launches identically.

Tier guarantees (v2.0):

  • linux-x86_64 — 1st-class (CI blocker, every release must pass).
  • linux-aarch64 / macos-aarch64 / macos-x86_64 — supported by the elisp object-file writers, end-to-end CI gate pending.
  • windows-x86_64 — supported by nelisp-pe-write.el + Win64 ABI codegen; end-to-end link + execute verification pending CI setup.
  • windows-aarch64 (arm64ec) — deferred.

Linux (Debian / Ubuntu):

sudo apt install build-essential curl pkg-config git
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. "$HOME/.cargo/env"

Linux (Fedora / RHEL):

sudo dnf install gcc curl git
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. "$HOME/.cargo/env"

macOS (arm64 or x86_64):

xcode-select --install              # one-time
brew install rustup-init && rustup-init
. "$HOME/.cargo/env"

Windows — native x86_64 (v2.0 supported): Install Rust via https://rustup.rs (MSVC toolchain), then cargo build --release from cmd.exe / PowerShell — the elisp-side PE/COFF writer + Win64 ABI codegen produce native COFF .o files that link into the final nelisp.exe. WSL2 / MSYS2 alternatives still work via the Linux toolchain row above.

From source — recommended for hacking and using the Elisp API

git clone https://github.com/zawatton/nelisp ~/nelisp
cd ~/nelisp/nelisp-runtime
cargo build --release        # ~30 s on a warm cache
cargo test --lib              # 291 unit tests, all PASS

Build outputs land under target/release/:

  • libnelisp_runtime.so — cdylib for embedding (Rust API in src/lib.rs)
  • nelisp-runtime — minimal CLI (--version / --syscall-smoke)

The Elisp source for the host-Emacs entry points stays under ~/nelisp/src/.

Pre-built standalone tarball — single-binary deployment

For users who want NeLisp + the bundled Rust runtime without cloning / building. No Emacs install required at runtime:

curl -fsSL https://github.com/zawatton/nelisp/releases/latest/download/install-v3.sh | bash

Default install root: $HOME/.local/share/anvil-stage-d-v3.0/. (The anvil- prefix is historical packaging — the tarball is the NeLisp runtime; the bundled bin/anvil launcher is one optional front end.) Verification, manual extraction, and platform notes: README-stage-d-v3.0.org.

Older release lines, for reference only:

  • README-stage-d-v2.0.org — bundled-Emacs tarball, ~25 MB
  • README-stage-d.org — legacy host-Emacs-required path

Cross-PC verification

After clone + build, run the smoke script for your platform:

# Linux / macOS:
scripts/verify-cross-platform.sh

# Windows (PowerShell):
.\scripts\verify-cross-platform.ps1

Expected output ends with Cross-platform verify PASS.

Launch

The pre-built tarball ships a tiny nelisp CLI that wraps the Rust evaluator. No host Emacs needed:

nelisp --version                       # nelisp 0.5.0
nelisp eval "(+ 1 2 3)"                # => 6
nelisp eval "(mapcar (function (lambda (n) (* n n))) '(1 2 3 4))"
                                       # => (1 4 9 16)

# load + run a file (last form's value is printed)
nelisp -l ~/nelisp/examples/hello/hello.el

# pipe Elisp through stdin
echo '(defun sq (x) (* x x)) (sq 7)' | nelisp -
                                       # => 49

If you built from source, the CLI lives at nelisp-runtime/target/release/nelisp; the install tarball puts it on $PATH.

Quick start

For larger workflows the evaluator is reachable three ways; pick the one that matches your context.

From Emacs Lisp — REPL straight into NeLisp’s own evaluator

(add-to-list 'load-path "~/nelisp/src")        ; or the install root's src/
(require 'nelisp-bootstrap)
(nelisp-bootstrap-init)             ; one-time self-host load

(nelisp-eval-string "(+ 1 2 3)")    ; => 6
(nelisp-eval-string
 "(mapcar (lambda (n) (* n n)) '(1 2 3 4))")
;; => (1 4 9 16)

(nelisp-load-file "~/nelisp/examples/hello/hello.el")
(nelisp-eval-string "(hello-world)")
;; => "Hello, World!"

The forms go through NeLisp’s own reader + evaluator (the Rust crate in cdylib mode, bridged into Elisp). Host Emacs is a launcher only — result and host-evaluator state stay separate.

From Rust — embed the runtime as a library

use nelisp_runtime::{eval_str, Sexp};
let v: Sexp = eval_str("(+ 1 2 3)").unwrap();
assert_eq!(v, Sexp::Int(6));

Public Rust API: src/lib.rs. Entry points are eval, eval_str, eval_str_all, apply_function (see eval/mod.rs).

Acceptance demos via cargo test

The Phase 8.0.2 test suite carries acceptance demos that exercise representative Elisp on the runtime end-to-end:

cd ~/nelisp/nelisp-runtime
cargo test --lib eval::tests::demo

Covers arithmetic / let / lambda / mapcar / if / condition-case (6 demos, ~10 ms total).

One downstream MCP-server front end that exposes NeLisp’s evaluator as a Claude Code tool ships under bin/anvil in the standalone tarball. That layer is optional; the runtime above is self-contained.

Architecture

┌──────────────────────────────────────────────────┐
│ MCP client (Claude Code / Claude Desktop / …)    │
└─────────────────┬────────────────────────────────┘
                  │ MCP stdio JSON-RPC
┌─────────────────▼────────────────────────────────┐
│ bin/anvil-runtime (pure-shell wrapper)           │  Phase B Final B
│   UNIX-socket daemon ⇆ anvil-runtime-server-loop  │  Stage 2 SHIPPED
├──────────────────────────────────────────────────┤
│ Elisp anvil tool registry + MCP dispatch         │  formerly the
│   (= scripts/anvil-runtime-server-loop.el +       │  =anvil-runtime/=
│    lisp/* MCP handlers)                          │  Rust crate, now
│                                                  │  -5,795 LOC deleted
├──────────────────────────────────────────────────┤
│ standalone =nelisp= binary                       │  build-tool/src/bin/
│   reader / evaluator / macro / compiler / loader │  + STDLIB .image
│   (Phase 47 self-emission for new substrate code)│
├──────────────────────────────────────────────────┤
│ build-tool/src/ Rust core                        │  Rust-min target;
│   eval / jit / image / sexp / env_shim / ffi     │  per-trampoline
│                                                  │  deletion ongoing
├────────────┬─────────────────────┬───────────────┤
│ extension  │ extension           │ dev bridge    │
│ crates     │ crates              │ crate         │
│ ┌────────┐ │ ┌─────────────────┐ │ ┌───────────┐ │
│ │sqlite- │ │ │syscall-fileio   │ │ │runtime-cli│ │
│ │  rs    │ │ │syscall-filenoty│ │ │ exec-bytes│ │
│ │        │ │ │syscall-process  │ │ │ (JIT smoke│ │
│ └────────┘ │ │syscall-types    │ │ │  bridge)  │ │
│            │ └─────────────────┘ │ └───────────┘ │
├────────────┴─────────────────────┴───────────────┤
│ OS substrate (libc / Linux / macOS)              │  Phase 7.0 / 9d
└──────────────────────────────────────────────────┘

Two boundaries are pinned:

  • Doc 46 (architecture α boundary final) — build-tool/src/ owns no anvil_* or mcp modules. Originally enforced through a sibling anvil-runtime Rust crate; since Phase B Final B Stage 2 (2026-05-09) the crate is gone entirely and the MCP front end is implemented in Elisp on top of the standalone nelisp binary.
  • Doc 49 (Rust-min core / self-host) — nelisp-runtime owns no Elisp interpreter. Rust handles only OS ABI (raw syscalls, mmap/mprotect/munmap, icache flush) plus a NLSEED v1 seed image loader. Reader / evaluator / macro / compiler / stdlib loader live in native-compiled Elisp seed. Optional surfaces (sqlite / fileio / filenotify / process) are extension crates pulled through default-ON compatibility features; turning them off (cargo build --no-default-features -p nelisp-runtime / make runtime-core-min) gives the canonical Rust-min build. The nelisp-runtime-cli bin (nelisp-exec-bytes) is a dev bridge for raw native-code smoke and is not part of runtime core.

The Rust bootstrap reader / evaluator that previously lived inside nelisp-runtime is being migrated out under Doc 49. Until the seed seam ships end-to-end the bootstrap reader/evaluator stays in build-tool/ as a build-time-only escape hatch.

Soak gate (Doc 32 v2 §2.7)

TierDurationRSS growth ceilingStatus (2026-04-27)
blocker (CI)1h< 5 MBPASS (linux-x86_64)
post-ship audit24h< 10 MB / 24hscheduled, weekly

Tier matrix (Doc 32 v2 §11):

Platformv1.0 status
linux-x86_64blocker (CI gate, must pass)
macos-arm64best-effort 95%+ (v1.0 time-boxed)
linux-arm64best-effort 95%+ (v1.0 time-boxed)
windows-nativepost-v2.0 scope

v1.0 time-boxed = explicit time-boxed exception ratified in Doc 32 v2 §11. v1.1+ promotes arm64 to blocker; the audit grep guard in test/nelisp-release-test.el retires at that point.

What is not in v1.0

Said plainly so expectations are calibrated:

  • No buffer / marker / window primitives. NeLisp is the language runtime, not the editor. emacs-nox is the closest existing comparison if scripting is all you need; what’s different here is the 624 KB standalone tarball and a runtime small enough to read end-to-end.
  • Phase 8.0 evaluator is a minimal subset (25 special forms + 75 builtins): GC bridge, bignum, full backquote semantics, full save-excursion are deferred to Phase 8.x follow-up patches.
  • Default --no-emacs still falls back to emacs --batch for cold-init failures (3-year safety window).
  • macOS arm64 / Linux arm64 = best-effort only (= time-boxed for v1.0).
  • Windows native --no-emacs is post-v2.0 scope.

Test status (HEAD, 2026-05-14)

  • make test = 3604 tests / 3562 expected / 5 unexpected (all pre-existing flake) / 37 skipped on linux-x86_64. See Pure-Elisp Migration Progress section above for the flake breakdown.
  • The previous 2026-04-29 baseline was 2452 / 2409 / 0 unexpected. The ~1.5× growth in test count reflects the new sub-systems: Phase 47 self-emission (600+ ERT), Doc 79 v7 GC, Doc 102 mirror, Doc 100/110 ABI / arithmetic, Doc 81 cons cluster, Doc 86/87 Tier 1+2 builtins.
  • 3-platform 1-hour soak (Linux x86_64 / macOS M1 / Windows MSYS2) passed end-to-end at v1.0; macOS aarch64 build re-validation is pending a libffi-sys upstream fix (Doc 76 M1 verify pause).

Key design documents

DocTopicStatus
18Stage D launcher charterLOCKED
27Phase 7+ self-implemented C runtimeLOCKED-2026-04-25-v2
28Phase 7.1 NeLisp native compilerLOCKED-2026-04-25-v2
32Phase 7.5 integration + standalone E2ELOCKED-2026-04-25-v2
44Phase 8.0 Rust Elisp interpreterLOCKED-2026-04-27
76Phase 7 elisp-side OS surface migrationIN PROGRESS
77b/cRust min-JIT + Sexp ABI elisp self-hostSHIPPED partial
79 v7Pure-elisp GC (Bacon-Rajan cycle collector)Phase C Stage 5.3 SHIPPED
81nelisp-cc primitive trampoline extensionStage 81.2 SHIPPED
85Phase 47 feasibility spikeVALIDATED
91-97Phase 47 ELF writer / asm / linker / DSL / buildSHIPPED
100Sexp ABI freeze (3-artifact contract)§B/C SHIPPED
102env.rs → elisp migrationPhase 8 Sprint A SHIPPED, Sprint B/C deferred
110Phase 47 f64 ABI + float.rs/math.rs swapSHIPPED

Earlier status (Phase 0 — 2026-04-22) — preserved for reference

Phase 0 (design documents) was completed 2026-04-22. Key decisions locked at that time and still in force:

  • Bootstrap strategy: Host-Emacs bootstrap (Candidate A), transferring SBCL’s genesis methodology (Rhodes 2008) to Emacs as the host
  • Scope: Stage A only (= Elisp substrate). Stage B (AI-native Emacs) and Stage C (AI/Emacs boundary fusion) belong to anvil.el successors
  • Concurrency: Actor model as primary (Phase 4), STM experimental (Phase 4b), fiber (Phase 3), threads deferred (Phase 5)
  • Division of labor: NeLisp core team focuses on AI-critical paths (buffer/event/concurrency/eval/FFI); community handles long tail (display render, primitive utilities) post-v1.0 — Linux kernel / SBCL governance model

The roadmap is in docs/05-roadmap.org.

Philosophy (short form)

Emacs Lisp is not philosophically cleaner than Scheme or Common Lisp — but decades of accumulated, lived-in Elisp is a cultural asset worth self-hosting on its own terms, rather than porting it to someone else’s substrate (Scheme, Rust, JavaScript).

Esperanto is a constructed language of philosophical elegance, but English is the international language. Elisp is English here.

The long form lives in docs/00-motivation.org.

Non-goals

  • Scheme rewrite (Guile-Emacs direction) — rejected
  • Rust rewrite (Remacs direction) — rejected
  • A replacement editor for Emacs — out of scope for NeLisp itself (Stage B/C handled by anvil.el or successors)
  • Replacing all 3000 C functions — non-goal (Remacs failure pattern). NeLisp core team rewrites AI-critical paths, community fills the long tail

The three-stage vision

┌─────────────────────────────────────────────────┐
│ Stage C: AI and Emacs as one                    │ ← anvil.el (and beyond)
│ ┌─────────────────────────────────────────────┐ │
│ │ Stage B: Emacs made AI-native               │ │ ← anvil.el (and beyond)
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ Stage A: Emacs internals in pure Elisp  │ │ │ ← *NeLisp (this project)*
│ │ │ (no C to traverse — everything editable) │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘

NeLisp builds the substrate (Stage A). Stage B and C are built on top of NeLisp, as extension packages.

Repository layout

nelisp/
├── BRIEFING.org             # First-session design instructions
├── README.org               # This file
├── .gitignore
├── packages/                # Extracted optional libraries
│   ├── README.org           # Package split convention
│   └── nelisp-json/         # Pilot extracted library package
│       ├── README.org
│       ├── src/
│       └── test/
└── docs/
    ├── 00-motivation.org    # Why this, why now, why not Scheme (USER voice)
    ├── 01-related-work.org  # 7 projects audited + paper priorities
    ├── 02-scoping.org       # Stage A/B/C + AI-critical vs long tail
    ├── 03-architecture.org  # Bootstrap A, primitive boundary, Phase 1 subset
    ├── 04-concurrency.org   # Actor primary Phase 4, novelty claim
    ├── 05-roadmap.org       # Phase 1-5 timeline, release schedule
    ├── 90-ideas-backlog.org # Deferred interesting ideas
    └── papers/              # Academic paper reading stubs
        ├── README.org
        ├── rhodes-2008-sbcl.org           # Priority A: bootstrap methodology
        ├── corallo-2020-native-comp.org   # Priority A: AOT hybrid
        ├── bolz-2009-meta-tracing.org     # Priority A: JIT for Phase 3-4
        └── maclachlan-1992-python.org     # Priority A: CL-in-CL precedent

Optional packages

NeLisp v1.0 now supports an SBCL/Quicklisp-style split between the core src/ tree and individually extractable libraries under packages/*/. The nelisp-json package is the pilot extraction and defines the canonical layout for future package moves:

  • packages/<name>/src/<name>.el
  • packages/<name>/test/<name>-test.el
  • packages/<name>/README.org

The build keeps these packages on the Emacs load-path, so existing require forms continue to work unchanged. See packages/README.org and packages/nelisp-json/README.org.

Related work (audited)

ProjectApproachStatus / diff with NeLisp
RemacsEmacs C → RustArchived 2020, scope explosion
emacs-ngRust + Deno (JS)Low activity 2024, JS disabled
Guile-EmacsElisp on Guile (Scheme)12-year stall, relaunched EmacsConf 2024
native-compElisp → libgccjit → .elnShipped in Emacs 28+, does not rewrite VM
SBCLCL in CL (CMU CL fork)Methodology source (Rhodes 2008)
PyPyPython in RPython + JITSuccessful self-host, STM branch failed
PicoLispTiny Lisp, pil21 LLVMpil21 self-hosts LLVM phase
NeLispElisp in Elisp, editor-nativeFirst editor-integrated self-host

See docs/01-related-work.org §10 for the synthesis.

License

TBD. Leading candidate: GPLv3+ (to match Emacs) with per-module reconsideration if needed. Decided before Phase 1 push.

Contact

zawatton — kurozawawo@gmail.com

About

NeLisp = Emacs Lisp VM in pure Elisp + Rust syscall stub

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors