The Pipeline
→ — each stage in detail, with the queries it owns.
tyc is a multi-stage compiler with an embedded LSP, structured as a Cargo workspace of small crates that mirror the pipeline stages. Each stage produces a typed Rust value that the next stage consumes; analysis results are stored as Salsa queries so the LSP can reuse them incrementally.
.ty source files │ ▼[tyc-syntax] → Typhon AST (Python AST + Typhon nodes) │ ▼[tyc-resolve] → symbol tables, scopes, let/mut classification │ ▼[tyc-types] → typed AST, structural subtyping, sealed unions │ ▼[tyc-analyse] → purity, async/concurrency, comptime, optimisation hints │ ▼[tyc-desugar] → plain Python AST │ ▼[tyc-emit] → .py source via hand-written printer (tracks .py.map offsets) │ ▼[tyc-format] → in-process whitespace pass + `ruff format` wrap (when on PATH) │ ▼[tyc-lsp] → reuses the above stages incrementally via Salsa
Parallel surface:[tyc-vm] → walks the parsed Typhon AST directly (default for `tyc run`)This is the same crate-per-stage layout used by oxc and rust-analyzer. The single most important meta-rule: every external crate gets wrapped behind a one-function-wide module of our own, so when Salsa changes its API or Ruff renames a node, the blast radius stays small.
The Pipeline
→ — each stage in detail, with the queries it owns.
Workspace Layout
→ — every crate, its responsibility, and its dependencies.
Salsa Queries
→ — the incremental query layer.
The Vendored Ruff Fork
→ — what we vendored from Ruff and why.
Adding a Diagnostic
→ — the worked walk-through for compiler contributors.
Contributing
→ — how to send a PR.
| Stage | Primary choice | Fallback | Why |
|---|---|---|---|
| Parser | Fork ruff_python_parser | rustpython-parser | Fastest, most spec-compliant Python parser in Rust. Not on crates.io, so vendor it. |
| AST | Fork ruff_python_ast | Hand-written | AST is partly TOML-generated; adding Typhon variants is mechanical. |
| Incremental engine | salsa (salsa-rs) | Hand-rolled query cache | Powers rust-analyzer and ty. Free cancellation and parallel queries. |
| Type checker | Custom on Salsa, ty as reference | Embed ty as a library | Typhon-specific rules need their own checker; ty handles the Python subset (deferred). |
| Code emission | Hand-written pretty-printer | Fork ruff_python_codegen (deferred) | Hand-written printer tracks line offsets for .py.map. |
| LSP transport | tower-lsp-server | lsp-server (rust-analyzer style) | Ergonomic, active fork on lsp-types 0.97+. |
| CLI | clap v4 derive | — | Standard. |
| Diagnostics | miette + thiserror | ariadne | Best-in-class source-span rendering. |
| Config | serde + toml | — | Standard. |
Python’s significant-whitespace lexing is non-trivial. Hand-writing a full Python parser using chumsky or lalrpop would mean spending months catching up to mainstream Python syntax before writing a single new feature. Vendoring Ruff’s parser inherits its battle-testing on real codebases and its same-AST contract with ty, which simplifies later type-checker integration. The cost is grammar-sync work whenever Python releases new syntax.