Skip to main content

Architecture

Kalem is one implementation in Rust: the compiler, the bytecode, the VM and the execution model. The same VM runs in three places:

TargetBuilt asUsed by
Servera native library behind a C interfaceCaria's Go server through cgo: the world's authority, deterministic and saved
Native gamea static librarythe Cocos native app, exposed to JavaScript through SWIG (coming)
Browser and editorWebAssemblyPlay's view in Sakin Editor: client scripts

As in Papyrus, the layers are separate and their borders are hard: the compiler is a tool of its own, the bytecode format is the only contract between it and the VM, and the VM does not know its host. The language's rules are Kalem's; the world's rules are the host's.

The compiler​

.kalem → tokens and syntax → syntax tree → typed form (names, types and effects checked) → Kalem IR → bytecode; a verifier checks the result once more. The parser tolerates errors and is the same code the language server uses.

It produces:

  • bytecode: typed, register-based instructions with a constant pool and 32-bit indexes; the header carries a signature and the format, language and ABI versions. The client's package holds only client scripts, and the compiler enforces that filter.
  • a manifest: side, host type, label, category, version, description; properties and their groups; memory; fields, input, events, timers and states; the ABI version and a digest of the source. Editors build their forms from it.
  • debug information: instruction → line and column, local names and their scopes.

The crates​

Crate
kalem-corevalue types and the exact operations (Determinism), random numbers, the standard library's native schema: only what every layer shares
kalem-bytecodethe format, its header, encoding and verifier
kalem-parsertokens, the error-tolerant parser, what names refer to, the manifest
kalem-typesname, type and effect checking, with tables of every expression's type and of what names and calls refer to
kalem-compilerKalem IR from the checked tree (names are indexes; widening, compound assignment and string parts are explicit) and bytecode
kalem-vmexecuting instructions, open frames, budgets, debugging hooks
kalem-runtimethe execution model (How scripts run), saving and migration (Saves), debugging and profiling
kalem-host-apithe one border with the host: the catalog, contract fields, applying effects, calling natives, delivering events, resolving ids
kalem-capithe C interface (Embedding Kalem)
kalem-wasmthe browser build: client scripts and visual effects
kalem-lspthe language server (Tools)
kalem-clithe kalem command (Tools)

Nothing of the game goes into a Kalem crate: an economy step, opening a business or a rent is either a host native or a Kalem script. A test fails if a Kalem crate's source holds a word of the game's world.

Frames are data​

Call frames and the instruction position are plain data from the start: the debugger shows them, and the next version's tasks go on from the same ground.

Compiling and caching​

  • Scripts are compiled when Play or Debug starts; while editing, the language server only checks. The cache key is the source's digest, the compiler's version, the native ABI version and the event schemas used.
  • A binding's check also depends on the contract's revision: when a contract changes, bindings are checked again.
  • A broken new compile does not break the last valid catalog entry or a running Play session; its error shows.
  • Bytecode is not kept in version control.