Contributing¶
klio is an experiment. Contributions are welcome through GitHub pull requests; the workflow is small.
Setup¶
- Install Zig 0.16.0 and put
zigon yourPATH. zig buildonce to compile the interpreter.zig build testto confirm a clean baseline.
Parity tests need a kotlinc on PATH; the harness can auto-install
a pinned one. See Testing.
Branching and commits¶
- One topic per branch.
- Commit messages describe why, not what — the diff shows the what.
- Do not add a
Co-Authored-Bytrailer.
Adding a language feature¶
- Read the relevant Kotlin Language Specification section (PDFs in
kotlin-language-spec/) and cross-reference thekotlin/source. - Extend the passes in order:
parserfor new syntax, thenirlowering and theinterp_irVm for execution. Updateresolver/typeckif the feature affects theklio checkdiagnostics path. - Add at least one corpus program under
tests/fixtures/parity_corpus/that exercises the feature end-to-end. - Add at least one
examples/program demonstrating it with deterministic output, and updateexamples/README.md. - Run
scripts/gate.sh(or the targeted subset from the iteration playbook). A feature is not done until tests fail when it is reverted.
Adding a pack¶
klio pack new kotlin-klio/klio-mylib --id mylibto scaffold.- Edit
klio.tomland the Kotlin shim underklioMain/. - For native bindings, add a Zig module exposing
hostBindings()and wire it into the CLI'smergedHostBindings()andbuild.zig. - Add a smoke
.ktundertests/fixtures/for the new pack. - Document the public surface under
docs/packs/shipped/<name>.md.
Diagnostics¶
User-facing diagnostic messages must not cite the Kotlin Language
Specification. Phrase the problem and the fix in user-actionable
terms; spec references belong in /// comments above the emitting
code. See Diagnostics.
Zig conventions¶
klio began as a Rust codebase and was fully ported to Zig; the port is complete. The conventions that outlived it:
- One module per subsystem:
src/<name>/<name>.zigis the root file and re-exports the module's public API. Cross-module use goes through@import("span"),@import("ast"), … as registered inbuild.zig'smod_list; intra-module files use relative@import("foo.zig"). - Diagnostics are data, not Zig errors: user-facing parse/type
errors collect into a
DiagnosticSink. Reserve Zigerrorvalues for out-of-memory, IO, and truly exceptional control flow. - Thread
std.mem.Allocatorexplicitly. Prefer an arena per phase (parse, lower, eval); every type that owns heap memory outside an arena gets adeinit. Document ownership at API boundaries. - Containers default to the unmanaged
std.ArrayList(T)(allocator passed toappend/deinit); hash maps use the managed API (.init(allocator)). - snake_case fields, camelCase functions/methods, TitleCase types.
Style¶
zig fmtand a cleanzig build testare enforced in CI.- Integration tests over the public API live under
src/itests/; unit tests over internals live alongside the code intest {}blocks within each.zigfile.