Skip to content

Latest commit

 

History

995 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CinderKit

CinderKit

A small typed language that compiles to cindervm bytecode (.cdx). Lexer · Parser · Type checker · Stack-machine codegen — zero dependencies.

| crates.io | Apache-2.0 | Docs | Example |

cinderkit build walkthrough

cinderkit build main.ck.cdxcindervm assembles and verifies.


Contents


What this is

CinderVM executes verified bytecode, and it consumes .cdx assembly. Writing .cdx by hand is fine for tests, but real programs want locals, conditionals, loops, and calls — without label arithmetic. CinderKit is the front end: a small typed language that compiles to .cdx, so the verifier stays the single gate between source and execution.

Property Mechanism
Front end is decoupled from the container Emits .cdx text, not .cdxb (src/codegen.rs)
Bad programs never reach the verifier Type checking runs before codegen (src/typeck.rs)
The output is inspectable What we emit is exactly what CinderVM disassembles
No dependencies, no build step One Rust crate, cargo build only

Why a frontend

The alternatives and why they were rejected:

Hand-written .cdx. Every branch needs a label, every temporary needs a stack slot, and a metering instruction must appear in every loop. It is readable, but it is not productive: a ten-line program becomes fifty lines of assembly with label bookkeeping the author has to keep straight.

Compile directly to .cdxb. The sealed container embeds checksums and section layout that are CinderVM's contract. Emitting text keeps the front end stable against container changes, and a codegen bug shows up as wrong (but visible) assembly rather than a container that fails to load.

A full systems language. Generics, closures, traits — the stack machine has none of those concepts. A small language maps 1:1 onto the instruction set, which keeps the compiler honest and the output short.


Mental model

main.ck ──► lexer ──► parser ──► typeck ──► codegen ──► out.cdx
               │          │          │
               └──────────┴──────────┴──► diagnostics (E_* codes)

Every stage is a pure function of the previous stage's output. There is no shared mutable compiler state, which is what keeps the diagnostics stable and the pipeline testable stage by stage.

Quickstart

cargo build --release
./target/release/cinderkit build main.ck -o main.cdx
# then feed the output to cindervm:
cinderc build main.cdx -o main.cdxb
cinderc run main.cdxb

cinderkit check main.ck runs only the front half of the pipeline and reports type errors without emitting anything.

The language

fn main() -> i32 {
    let total = 2 + 3 * 4;
    if total > 10 { return 1; }
    return 0;
}
  • Types: i32, bool, void
  • Statements: let, if/else, while, return, expression statements
  • Operators: + - * / < > ==, with standard precedence
  • Calls: helper() — arguments are packed into a list before the call
  • Comments: // to end of line

Loops are compiled with an implicit reserve 0 on the token dimension, because CinderVM's verifier rejects unmetered back-edges — the language makes it impossible to write a program the verifier will refuse.

The type checker

One pass per function body:

  • every variable is declared before use, and duplicates are rejected
  • + - * / require i32 operands; == < > require matching operands
  • if/while conditions must be bool
  • return must match the function's declared type
  • a non-void function must return on every path
  • calls are checked against the declared function signatures

The code generator

Expressions compile to postfix on the operand stack; locals live in frame slots behind the stack pointer. a > b lowers to b a lt because cdx has no gt. if/else lower to brz/br label pairs, while to a metered head-check loop.

Diagnostics

Every error carries a stable code (E_TYPE_MISMATCH, E_UNKNOWN_FN, ...) and a source line:

error[E_TYPE_MISMATCH]: return type must be i32, found bool (at line 3)

Tooling can grep the codes; humans get line numbers.

Performance

Measured on a 2022-era laptop (the crate's test corpus):

Stage Time
lexer + parser (1,200 tokens) 0.4 ms
type check (200 statements) 0.2 ms
codegen (800 instructions) 0.3 ms

The whole pipeline is a single pass per stage with no re-scans.

Building from source

cargo build --release
cargo test          # 12 tests: lexer, parser, checker, codegen
cargo clippy        # warnings-only, no unsafe

Repository layout

CinderKit/
├── src/
│   ├── lib.rs          # pipeline entry: compile()
│   ├── lexer.rs        # hand-rolled scanner
│   ├── parser.rs       # recursive descent → AST
│   ├── typeck.rs       # single-pass checker
│   ├── codegen.rs      # AST → .cdx text
│   └── diag.rs         # stable error codes
├── src/bin/cinderkit.rs   # CLI: build / check
├── examples/           # sample programs
├── docs/               # usage guide + assets
└── tests/              # integration tests

Stability

The .cdx output targets cdx/4 only. If CinderVM bumps the ISA, CinderKit will either emit the new version or fail loudly — it will never emit bytecode the verifier cannot read. The language itself is frozen for 0.9: additions land as new features, not changed semantics.

FAQ

Why i32 and not i64? CinderVM's integer type is 64-bit under the hood; the language calls it i32 because every constant in the demo programs fits comfortably and the arithmetic is wrapping either way.

Can I write a struct or a closure? No. The stack machine has a tagged arena for lists; a higher-level type like a record would compile to a list with a positional contract, which is a library pattern, not a language feature.

Do I need CinderVM installed to compile? No — CinderKit only emits text. You need cinderc to assemble and run the result.

Why does every loop get a reserve? CinderVM's verifier requires metering on back-edges (see CinderVM's verify.rs). Emitting it implicitly means a program that type-checks always verifies.

License

Apache-2.0 — see LICENSE.

About

A small typed language that compiles to cindervm bytecode (.cdx) - lexer, parser, type checker, stack-machine codegen. Zero dependencies.

Topics

Resources

Stars

15 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages