Overview
MCC prioritizes maintainability over novelty. We prefer the smallest change that keeps the codebase coherent and boring. This guide will help you contribute effectively to the project.
Before You Start
Core Principles
When contributing to MCC, remember these five essential practices:
- Read the entry point and neighbors before changing anything
- State intent + boundaries (what you will change, what you will not)
- Keep diffs small and reviewable (≤5 files / ≤200 LOC unless requested)
- Follow existing repo patterns and architectural invariants
- Prove it works (run the relevant checks, or give exact commands + expected outputs)
Required Expertise
Contributors should be familiar with:
- Rust (crates, cargo, traits, Salsa)
- Compilers and language implementation (parsing, IR, codegen)
- Tree-sitter and incremental compilation
- C language and system tooling (preprocessor, assembler, linker)
Development Workflow
1. Read First
Before making any changes:
- Find the exact entry point(s) involved:
- CLI in
mcc-driver
- Pipeline stage in
mcc
- AST in
mcc-syntax
- Build tooling in
xtask
- Read neighboring code to learn local invariants and patterns
- Search the codebase for existing conventions rather than guessing
2. State Intent and Boundaries
- Briefly state what you’re changing, what you’re not changing, and why
- If requirements are ambiguous, choose the safest minimal interpretation and state assumptions
- Only ask questions if ambiguity would change public APIs, pipeline contracts, or crate boundaries
3. Implement in Small Steps
- Keep changes logically grouped
- Don’t mix refactors/formatting with functional changes
- Keep changes locally scoped to the relevant crate/module
4. Prove It Works
- Prefer test-driven / iterative verification (red → green → refactor)
- Run the relevant verification commands
- If you cannot run commands, list exactly what should be run and what success looks like
Verification Commands
Run the smallest relevant set for your change. CI uses these commands:
Full Workspace
cargo check --workspace --locked
cargo build --workspace --locked
cargo nextest run --workspace --locked
cargo test --doc --workspace --locked
cargo fmt --all -- --check
cargo clippy --workspace
Single Crate
cargo check -p <crate-name> --locked
cargo nextest run -p <crate-name> --locked
Integration Tests
From the repo root:
cargo test -p integration-tests --test integration
This runs the compiler against the writing-a-c-compiler-tests suite. Use --ignored to run tests beyond the default chapter cap.
If a command fails, fix it properly. Don’t skip checks to make things “look green”.
Hard Boundaries
Unless explicitly requested, do not:
- Add new dependencies, crates, or workspace members
- Introduce new pipeline stages or change stage boundaries
- Put compilation logic in
mcc-syntax or orchestration logic in mcc
- Change Salsa tracking or break incremental compilation invariants
- Restructure the pipeline (preprocessing → parsing → lowering → codegen → render → assembling)
If you believe a boundary must be crossed, explain:
- The minimum change required
- Why it’s necessary for the task
- What risks it introduces
Maintainability Guardrails
No Bloat
Don’t add wrappers/adapters/helpers “for cleanliness” unless there is a concrete, local benefit.
Avoid Duplication
- Don’t paste near-identical blocks across files
- Prefer small helpers in the same module before creating new crates or shared libs
- If duplication is unavoidable, explain why reuse isn’t appropriate
Interfaces and Traits
Introduce a trait only if:
- There are at least two plausible implementations now, or
- Tests clearly benefit and call sites depend on the trait (not the concrete type)
Don’t Paper Over Failures
- Fix root causes; don’t “make tests pass” by weakening them
- Avoid
#[allow(...)] / ignoring lints unless you can justify why it’s safe
Security and Safety
- Never commit secrets, tokens, API keys, private certs, or real credentials
- Prefer
.env/secret managers and clearly document required variables
- Don’t log secrets (including in debug logs)
Generated Code
- Don’t hand-edit generated files (e.g. tree-sitter grammar outputs) unless a local README explicitly allows it
- Change the source of truth, then regenerate
Done Checklist
Before considering work “done”:
License
Contributions are dual-licensed under MIT OR Apache-2.0. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.