6. Tooling loop: formatter + tests¶
This chapter explains the contributor “inner loop” for making changes safely:
- format code consistently
- run tests quickly
- prevent drift between syntax, compiler, and tooling
End-to-end checklist¶
Just like in the previous chapter, use this checklist to keep the pipeline aligned while you work:
Keep the pipeline aligned (to avoid language/tooling drift):
- Syntax crate (
crates/incan_syntax/): lexer → parser → AST → diagnostics - Formatter (
src/format/): prints AST back (idempotent; never emits invalid syntax) - Semantic core (
crates/incan_core/): canonical vocab / shared semantic helpers (avoid duplicating “meaning” in multiple layers) - Compiler (
src/frontend/,src/backend/):- typechecker validates and annotates
- lowering turns AST into IR
- emission generates correct Rust
- Runtime/stdlib (
crates/incan_stdlib/,stdlib/): behavior that can live outside the compiler should live here
Rule of thumb: prefer pushing shared meaning “down” into incan_core/incan_syntax/incan_stdlib, and keep the incan
(root) crate focused on orchestration and pipeline wiring.
Formatter (incan fmt)¶
The formatter is part of the toolchain and should remain aligned with the parser/AST:
- it should be idempotent (formatting twice yields the same output)
- it should never print invalid syntax
See:
Where it lives:
src/format/
Testing (Rust tests + integration checks)¶
Depending on your change, you will usually run:
make testfor the Rust unit/integration test suite (fast feedback)make pre-commitbefore pushing (fmt + clippy + udeps + tests + release build)make smoke-testwhen you want extra confidence (build + tests + examples + benchmarks-incan)
See:
A practical workflow¶
When you add a feature:
- add/adjust a small Rust regression test (parse/typecheck/codegen)
- run
make test - run
make pre-commitbefore opening the PR - run
make smoke-testif the change touches the pipeline end-to-end (parser/typechecker/codegen/tooling)
Next¶
Next chapter: 07. Tooling loop: LSP.