>_ENGINEERING REPORT
vimlrs is a standalone interpreter for VimL (Vimscript), ported faithfully from Neovim's C eval engine and hosted on the fusevm bytecode VM. This report describes the architecture, the porting methodology, the current state of the tree, and the dependency posture. The numbers below are facts about the design and the manifest, not aspirational metrics.
Summary
Vimscript has historically been inseparable from its host editor. vimlrs separates the two: it ports the language semantics out of Neovim's C eval/* tree and runs them on a compiled VM, so .vim scripts execute as standalone programs. It is the fourth consumer of fusevm — after zshrs, stryke, and awkrs — and reuses that shared bytecode VM and three-tier Cranelift JIT rather than shipping its own.
The current tree has the Vim-native value layer ported (typval, list, insertion-ordered dict, blob); the lexer/parser, AST-to-bytecode lowering, and builtin surface are implemented (and the builtin surface keeps growing); and the standalone binary, rkyv bytecode cache, AOT native compiler, DAP debugger, and LSP server are implemented.
Hosting on fusevm
vimlrs contains no virtual machine or JIT of its own. The execution path is:
VimL source → lexer → parser → AST → lower to fusevm bytecode → fusevm VM + Cranelift JIT
Shared engine
fusevm is pulled from crates.io with the jit and jit-disk-cache features. JIT and VM improvements land once and benefit zshrs, stryke, awkrs, and vimlrs together.
Persistent native code
jit-disk-cache persists compiled machine code across runs, so warm starts skip recompilation.
Portable bytecode
The bytecode is architecture-portable; the Cranelift JIT covers x86-64 and aarch64 (macOS + Linux) today.
Same pattern as zshrs
vimlrs hosts VimL the way zshrs hosts zsh — lower to bytecode, run on the shared VM — rather than re-implementing an interpreter loop.
Port methodology
The semantics are ported faithfully from Neovim's C eval engine — the C source is the specification, not a starting point for an ad-hoc re-implementation. The vendored Neovim sources live under vendor/ (the eval/* tree in vendor/eval/, plus the supporting translation units it depends on) and are the porting reference; they carry no build role and are excluded from the crate via exclude = ["/vendor/", …]. Every ported fn under src/ported/ traces back to a real C name in that tree — a drift-gate test (tests/ported_fn_names_match_c.rs) fails the build on any invented helper that has no vendor/ origin and no sanctioned allowlist entry.
The Vim-native runtime values were ported first so the rest of the engine has a faithful substrate to build on: list and blob behave as in Vim, and dict preserves insertion order to match Vim's observable hashtab iteration and keep echo / string() output deterministic.
Component status
| Component | State | Notes |
|---|---|---|
| typval / list / dict / blob | Ported | Insertion-ordered dict; deterministic string output. |
| lexer / parser → AST | Implemented | Ported from the Neovim eval engine. |
| AST → fusevm bytecode | Implemented | Targets the shared fusevm opcode set; no local VM. |
| builtin functions | Implemented | Ported from eval/funcs.c; the surface keeps growing. |
standalone vimlrs binary | Implemented | Run .vim scripts from the CLI (src/main.rs). |
| rkyv bytecode cache | Implemented | Versioned, migration-safe on-disk format (src/script_cache.rs). |
DAP debugger (--dap) | Implemented | Breakpoints, stepping, variables (src/dap.rs). |
LSP server (--lsp) | Implemented | Diagnostics, hover, completion (src/lsp.rs). |
Dependency posture
Dependencies are kept foundational and durable — the goal is a crate that still builds cleanly years from now. Direct dependencies from Cargo.toml:
| Crate | Role |
|---|---|
| fusevm | Language-agnostic bytecode VM + three-tier Cranelift JIT (jit, jit-disk-cache) |
| clap | CLI argument parsing (derive, cargo) |
| thiserror | Error type derivation |
| rustc-hash | Fast hashing for interner / maps |
| indexmap | Insertion-ordered dict storage (matches Vim hashtab iteration) |
| rkyv | Zero-copy bytecode script cache (versioned from day one) |
| memmap2 | mmap hot path for the script cache |
| dirs | Platform cache / config directories |
| lsp-server / lsp-types | LSP transport + protocol types (--lsp server) |
Compatibility & longevity
Versioned caches
The rkyv script-cache format is versioned from the first release so an old cached .vim upgrades or rebuilds silently rather than breaking.
Faithful semantics
Behaviour tracks the Neovim reference, so scripts that run there are the compatibility target.
Cross-architecture
macOS aarch64 and Linux x86_64 / aarch64 via the Cranelift JIT; portable bytecode underneath.
Standalone crate
An explicit empty [workspace] keeps vimlrs buildable on its own, independent of the meta repo.
Links
- Docs — index.html
- Source — github.com/MenkeTechnologies/vimlrs
- Issues — github.com/MenkeTechnologies/vimlrs/issues
- fusevm — github.com/MenkeTechnologies/fusevm (the shared VM)
- License — MIT (LICENSE)