// KOTLINRS — ENGINEERING REPORT

kotlinrs v0.1.6 · Kotlin on fusevm · lex/parse → AST → bytecode → Cranelift JIT · no JVM · MIT · in active development

Docs Reference GitHub

>_ENGINEERING REPORT

How kotlinrs is put together: a pure Kotlin frontend over the fusevm bytecode VM and Cranelift JIT, with no bespoke VM or JIT of its own.

Value model

kotlinrs values ride through the VM as fusevm Value variants — Int, Float (Kotlin Double), Bool, Str, and Undef (Kotlin Unit). The compiler tracks coarse static types (ast::Type) so it can pick + versus string concatenation and integer versus float division at lowering time without a full type checker. Only three behaviours the universal ops cannot express are served by the extension handler: Kotlin toString() display form, and truncating integer / and %.

Compilation pipeline

StageFileOutput
Lexingsrc/lexer.rsToken stream with pre-split string-interpolation parts and per-token source lines.
Parsingsrc/parser.rsA list of FunDecl AST nodes; each statement carries its source line for diagnostics and debugging.
Loweringsrc/compiler.rsA single fusevm::Chunk: native ops for arithmetic / comparison / control flow / calls, extension ops for the three Kotlin coercions.
Executionsrc/runtime.rs, src/host.rsfusevm VM run with the Kotlin extension handler installed; the Cranelift JIT can trace hot loops.

Toolchain internals

LSP (src/lsp.rs)

Diagnostics reuse the runtime's own parser::parse_program, so an editor error maps to the exact line the runtime would report. Completion and hover draw on a single corpus that also feeds the generated reference page — the server and the docs never drift.

DAP (src/dap.rs)

A debug-only compile emits a stack-neutral KT_DBG_LINE marker before each statement. The debug extension handler fires a line hook that checks breakpoints and step targets, reads live locals from the current frame's slots, and services DAP requests in place. The debuggee's stdout is redirected to a pipe and forwarded as output events.

FFI (src/rust_ffi.rs)

A rust { … } block is desugared at the source level (via fusevm::RustSugar) into a __rust_compile call; the host routes it to fusevm::ffi, which compiles a cached cdylib. Exported extern "C" functions become callable by name.

Disassembly (--disasm)

Reuses the shared fusevm::Chunk::disassemble, so the printed listing is exactly the engine's own view of the lowered bytecode.

Dependency posture

The core runtime depends only on fusevm (with the jit and ffi features). The toolchain adds lsp-server / lsp-types / serde / serde_json for the LSP and DAP protocol servers and libc for the DAP stdout pipe. There is no JVM, no kotlinc, and no bespoke VM or JIT — execution and codegen live entirely in fusevm, shared with the sibling language hosts.

Links