// VIMLRS — ENGINEERING REPORT

vimlrs v0.2.0 · standalone VimL interpreter · faithful Neovim eval port · fusevm + Cranelift JIT · MIT · in active development

Docs GitHub
// Color scheme

>_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.

4th
fusevm language host
3
Cranelift JIT tiers
v0.2.0
version
MIT
license · free / OSS

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

ComponentStateNotes
typval / list / dict / blobPortedInsertion-ordered dict; deterministic string output.
lexer / parser → ASTImplementedPorted from the Neovim eval engine.
AST → fusevm bytecodeImplementedTargets the shared fusevm opcode set; no local VM.
builtin functionsImplementedPorted from eval/funcs.c; the surface keeps growing.
standalone vimlrs binaryImplementedRun .vim scripts from the CLI (src/main.rs).
rkyv bytecode cacheImplementedVersioned, migration-safe on-disk format (src/script_cache.rs).
DAP debugger (--dap)ImplementedBreakpoints, stepping, variables (src/dap.rs).
LSP server (--lsp)ImplementedDiagnostics, 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:

CrateRole
fusevmLanguage-agnostic bytecode VM + three-tier Cranelift JIT (jit, jit-disk-cache)
clapCLI argument parsing (derive, cargo)
thiserrorError type derivation
rustc-hashFast hashing for interner / maps
indexmapInsertion-ordered dict storage (matches Vim hashtab iteration)
rkyvZero-copy bytecode script cache (versioned from day one)
memmap2mmap hot path for the script cache
dirsPlatform cache / config directories
lsp-server / lsp-typesLSP 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