Compiler Mod SDK
Platform spec node
Compiler Mod SDK
Spec standingStandard
No architecture decision records under adr/ for this feature yet. Standard features must
publish at least one ADR or keep a ## Decisions summary on the hub.
- Compiler Mod SDK Beskid-side compiler-mod contracts, Beskid.Syntax mirror, declarative query, and typed AST operations.
- Language macros Module-level macro rules with fragment parameters, `name!` invocation, and typed AST expansion in any project kind.
- Metaprogramming Source generators, attributes that drive compiler plug-ins, and scheduling relative to other analyses. The broader generator roadmap may live in guides; v0.1 rules are normative here.
- Serialization packages Serialization core package, Serialization Mod, and format-specific packages (JSON).
0 revisions (git unavailable at build; counts may be empty)
No commits recorded for this path.
| Section id | Required | Found |
|---|---|---|
scope | yes | yes |
features | yes | yes |
Full tree: run pnpm verify:platform-spec-layout (writes src/generated/platform-spec-layout-report.json).
Package role
The Compiler Mod SDK (compiler-sdk package) is the Beskid-side surface for type: Mod projects. Mod behavior is declared through contracts and Beskid.Syntax operations — not through dedicated metaprogramming grammar items in the host language.
Contract hierarchy
All mod entrypoints derive from Collector:
| Contract | Role |
|---|---|
Collector | Declarative target collection and scope narrowing (replaces project-level attach metadata). |
Generator | Incremental by default; emits typed AST contributions only. |
Analyzer | Runs on host + generated code; emits diagnostics and registers rewrites as fixes. |
Rewriter<TSourceNode, TTargetNode> | Result<TTargetNode, FixError> Rewrite(TSourceNode sourceNode) — replaces any AST node with any valid typed AST node. |
AttributeGenerator | Defines attributes exported by mod packages (SDK infrastructure; domain mods such as Serialization Mod define concrete attributes). |
Hosts discover contract implementations from AOT-compiled Mod packages in the dependency graph (direct and transitive).
Contract discovery (normative)
Mod packages export contract implementations through public Beskid types that implement the SDK contract interfaces (Collector, Generator, Analyzer, Rewriter, AttributeGenerator). Authors do not register entrypoints in the manifest; discovery is entirely artifact-driven.
During mod.load, the Rust mod host:
- Resolves every transitive
type: Moddependency from the hostCompilePlan. - Locates the AOT artifact for the active target triple and cache key (see AOT artifact contract).
- Reads the export descriptor (
mod.descriptor.json) and/or the native object export table. - Builds a schedule of
(contractId, typeId, entrySymbol)tuples, where:contractId— stable SDK contract name (e.g.Beskid.Compiler.Collect.Collector).typeId— public type name in the mod assembly implementing that contract.entrySymbol— AOT-linked symbol used to invoke the contract entrypoint.
Duplicate or conflicting registrations must fail with E1829 / E1851–E1870 diagnostics before mod.collect runs. Missing required contracts for a scheduled mod must fail closed (no partial host merge).
Manifest attachTo / entryModules are not part of discovery; Collector owns scope narrowing at execution time.
Beskid.Syntax and declarative query
Beskid.Syntaxis the typed mirror of compiler syntax nodes (legacyBeskid.Compiler.Syntax/ “SyntaxMirror” naming is deprecated).Beskid.Syntax.Nodes.Nodeis a contract (not a variant enum): the sole navigation surface for mod traversal. Hosts materializeNodeRefhandles{ syntaxGenerationId, nodeId }with stable identities per syntax generation.Nodeexposes required identity and span metadata (Ref,Kind,Span) and child enumeration hooks. Query facade also exposes span helpers (Span,TrySpan) forNodeRef-first workflows.- Concrete mirrored types (
FunctionDefinition,Expression, …) remain forGenerator/Rewritertyped construction; mod traversal usesNodeRef+Beskid.Compiler.Query, thenAs*projections when a concrete shape is required. Program.itemsis aNodeListofNodeRefvalues (cons-list encoding); there is no mirrored item-wrapper enum for module items.- Mod code builds and transforms trees through declarative fluent APIs — no string formatting or source-text emission.
RewriterandGeneratoruse concrete mirrored types; query and merge invalidation keys useNodeRefidentities from the host snapshot.- AST manipulation ergonomics are standardized around a query-pipeline DSL (
Select/WhereKind/Replace/Remove/Insert*/Apply), with deterministic host execution and conflict diagnostics.
Pipeline interaction (Beskid view)
From a mod author’s perspective:
- Collect —
Collectornarrows targets for this mod instance. - Generate —
Generatorcontributes typed AST; host re-parses and merges (bounded bymaxGeneratorRounds). - Analyze —
Analyzerruns after semantic snapshot on merged program (including generated code). - Rewrite —
Rewriterapplies when an analyzer declares a fix; host validates typed replacement.
Rust-side phase ids and artifact lifecycle are specified under Compiler Mods.
Language macros vs Mod SDK
Language macros are not Mod contracts. They are ordinary macro module items expanded by the compiler macro.expand phase before mod.load.
| Language macros | Mod SDK | |
|---|---|---|
| Declaration | macro name (kind param) { ... } in any project | contract types in type: Mod packages |
| Invocation | name!(...) / name! { } | N/A (mods run on host compilation events) |
| Expansion host | Rust intrinsic in beskid_analysis | AOT mod artifacts + Collector / Generator |
| Discovery | Name resolution / use | mod.descriptor.json contract registry |
Mods may define and call language macros like any library; Generator output that contains foo! is expanded after re-parse per stage-ordering rules.
Language features used by mods
- Language macros — optional in mod-authored sources; expanded before mod phases on each syntax generation.
- extend type — primary extension syntax for generated members (replaces impl-block extension).
- Serialization packages — reference domain mod defining
[Serialize]. - Dynamic types and mapping (v0.3) — planned IR/runtime mapping for serializable types.
Non-goals
- No language-level
metaitems or collect/generate/analyze/rewrite blocks. - No runtime reflection over arbitrary Beskid objects.
- No mutation of Rust compiler composition graphs from Beskid mod code.