Skip to content

Architecture Overview

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.

The pipeline

.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.

Toolchain decisions

StagePrimary choiceFallbackWhy
ParserFork ruff_python_parserrustpython-parserFastest, most spec-compliant Python parser in Rust. Not on crates.io, so vendor it.
ASTFork ruff_python_astHand-writtenAST is partly TOML-generated; adding Typhon variants is mechanical.
Incremental enginesalsa (salsa-rs)Hand-rolled query cachePowers rust-analyzer and ty. Free cancellation and parallel queries.
Type checkerCustom on Salsa, ty as referenceEmbed ty as a libraryTyphon-specific rules need their own checker; ty handles the Python subset (deferred).
Code emissionHand-written pretty-printerFork ruff_python_codegen (deferred)Hand-written printer tracks line offsets for .py.map.
LSP transporttower-lsp-serverlsp-server (rust-analyzer style)Ergonomic, active fork on lsp-types 0.97+.
CLIclap v4 derive—Standard.
Diagnosticsmiette + thiserrorariadneBest-in-class source-span rendering.
Configserde + toml—Standard.

Why vendor the Ruff parser

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.

Where next