This document defines all naming conventions, API boundaries, shared types, and contracts between the 23 workspace crates. All implementors MUST follow these rules.
Layer 0 (no deps): magpie_ast, magpie_rt
Layer 1 (ast only): magpie_diag
Layer 2 (ast+diag): magpie_lex, magpie_types
Layer 3: magpie_parse (lex+ast+diag), magpie_csnf (ast+diag),
magpie_hir (ast+types+diag)
Layer 4: magpie_sema (ast+hir+types+diag),
magpie_mpir (hir+types+diag)
Layer 5: magpie_mono (hir+types+diag),
magpie_own (hir+types+diag),
magpie_arc (mpir+types+diag)
Layer 6: magpie_codegen_llvm (mpir+types+diag),
magpie_codegen_wasm (mpir+types+diag),
magpie_gpu (mpir+types+diag),
magpie_pkg (diag), magpie_memory (diag),
magpie_web (types+diag)
Layer 7: magpie_jit (codegen_llvm+diag),
magpie_ctx (memory+diag)
Layer 8: magpie_driver (ast+lex+parse+csnf+hir+sema+types+mono+own+mpir+arc+diag+pkg)
Layer 9: magpie_cli (driver+diag)
Rule: No circular dependencies. Lower layers MUST NOT depend on higher layers.
All crates MUST use these exact types for cross-crate references:
| Type | Definition | Usage |
|---|---|---|
FileId(u32) |
magpie_ast::FileId |
Source file identifier |
Span |
magpie_ast::Span |
Byte-offset source span |
Spanned<T> |
magpie_ast::Spanned<T> |
Node with span |
PackageId(u32) |
magpie_types::PackageId |
Package in build graph |
ModuleId(u32) |
magpie_types::ModuleId |
Module in build graph |
DefId(u32) |
magpie_types::DefId |
Definition (fn/type/global) |
TypeId(u32) |
magpie_types::TypeId |
Interned type |
InstId(u32) |
magpie_types::InstId |
Monomorphization instance |
FnId(u32) |
magpie_types::FnId |
Function ID |
GlobalId(u32) |
magpie_types::GlobalId |
Global variable ID |
LocalId(u32) |
magpie_types::LocalId |
SSA local within a function |
BlockId(u32) |
magpie_types::BlockId |
Basic block within a function |
Sid(String) |
magpie_types::Sid |
Stable ID: <Kind>:<10chars> |
- Crate names:
magpie_<component>(snake_case) - Module names: snake_case
- Struct names: PascalCase
- Enum names: PascalCase
- Enum variant names: PascalCase
- Function names: snake_case
- Constants: UPPER_SNAKE_CASE
- Type parameters: single uppercase or PascalCase
- Functions:
@<snake_case>(e.g.,@println,@hash_Str) - Types:
T<PascalCase>(e.g.,TPerson,TOption) - SSA locals:
%<snake_case>(e.g.,%msg,%age_val) - Block labels:
bb<digits>(e.g.,bb0,bb1) - Modules:
<dotted.path>(e.g.,pkg.sub.module)
- Module:
M:<10 base32 crockford chars> - Function:
F:<10 chars> - Type:
T:<10 chars> - Global:
G:<10 chars> - Extern:
E:<10 chars> - Instance:
I:<16 chars>
Input: "magpie:sid:v0.1|<kind>|<canonical_string>"
Hash: blake3(input), encode first 5 bytes (10 chars) as base32 crockford uppercase.
- Prefix:
mp$0$ - Functions:
mp$0$FN$<F_sid_suffix> - Mono instances:
mp$0$FN$<F_sid_suffix>$I$<inst_suffix16> - Globals:
mp$0$GL$<G_sid_suffix> - Type info:
mp$0$TI$<T_sid_suffix> - Drop fn:
mp$0$DROP$<T_sid_suffix> - Type init:
mp$0$INIT_TYPES$<M_sid_suffix> - Program entry: C
main→mp_rt_init()→ allINIT_TYPES→ Magpie@main
| Prefix | Domain | Crate |
|---|---|---|
MPP |
Parse/lex | magpie_parse, magpie_lex |
MPT |
Types | magpie_types, magpie_sema |
MPO |
Ownership | magpie_own |
MPA |
ARC | magpie_arc |
MPS |
SSA verification | magpie_mpir, magpie_hir |
MPAS |
Async | magpie_sema |
MPF |
FFI | magpie_codegen_llvm |
MPG |
GPU | magpie_gpu |
MPW |
Web | magpie_web |
MPK |
Package manager | magpie_pkg |
MPL |
Lint / LLM features | magpie_diag |
// magpie_lex public API
pub struct Token {
pub kind: TokenKind,
pub span: Span,
pub text: String, // only for identifiers/literals
}
pub enum TokenKind {
// Keywords, punctuation, literals, identifiers, EOF
// ~60 variants matching §7.1
}
pub fn lex(file_id: FileId, source: &str, diag: &mut DiagnosticBag) -> Vec<Token>;// magpie_parse public API
pub fn parse_file(
tokens: &[Token],
file_id: FileId,
diag: &mut DiagnosticBag,
) -> Result<AstFile, ()>;// magpie_csnf public API
pub fn format_csnf(ast: &AstFile, source_map: &SourceMap) -> String;
pub fn compute_digest(canonical_source: &str) -> String; // blake3 hex// magpie_sema public API
pub struct SymbolTable { /* per-module symbols: fns, types, globals, sigs */ }
pub struct ResolvedModule { /* AST + resolved names + symbol table */ }
pub fn resolve_modules(
files: &[AstFile],
diag: &mut DiagnosticBag,
) -> Result<Vec<ResolvedModule>, ()>;// magpie_types public API
pub struct TypeCtx { /* interning + layout */ }
impl TypeCtx {
pub fn intern(&mut self, kind: TypeKind) -> TypeId;
pub fn lookup(&self, id: TypeId) -> Option<&TypeKind>;
}// magpie_hir public API
pub struct HirModule {
pub module_id: ModuleId,
pub functions: Vec<HirFunction>,
pub globals: Vec<HirGlobal>,
pub type_decls: Vec<HirTypeDecl>,
}
pub struct HirFunction {
pub fn_id: FnId,
pub sid: Sid,
pub name: String,
pub params: Vec<(LocalId, TypeId)>,
pub ret_ty: TypeId,
pub blocks: Vec<HirBlock>,
pub is_async: bool,
}
pub fn lower_ast_to_hir(
resolved: &ResolvedModule,
type_ctx: &mut TypeCtx,
diag: &mut DiagnosticBag,
) -> Result<HirModule, ()>;// magpie_own public API
pub fn check_ownership(
module: &HirModule,
type_ctx: &TypeCtx,
diag: &mut DiagnosticBag,
) -> Result<(), ()>;// magpie_mpir public API
pub struct MpirModule { /* §17.1 */ }
pub fn lower_hir_to_mpir(
hir: &HirModule,
type_ctx: &TypeCtx,
diag: &mut DiagnosticBag,
) -> Result<MpirModule, ()>;
pub fn verify_mpir(
module: &MpirModule,
type_ctx: &TypeCtx,
diag: &mut DiagnosticBag,
) -> Result<(), ()>;
pub fn print_mpir(module: &MpirModule, type_ctx: &TypeCtx) -> String;// magpie_arc public API
pub fn insert_arc_ops(
module: &mut MpirModule,
type_ctx: &TypeCtx,
diag: &mut DiagnosticBag,
) -> Result<(), ()>;
pub fn optimize_arc(module: &mut MpirModule, type_ctx: &TypeCtx);// magpie_codegen_llvm public API
pub struct LlvmCodegen { /* LLVM module handle */ }
impl LlvmCodegen {
pub fn new(target_triple: &str) -> Result<Self, String>;
pub fn compile_module(
&mut self,
mpir: &MpirModule,
type_ctx: &TypeCtx,
) -> Result<(), String>;
pub fn emit_llvm_ir(&self) -> String;
pub fn emit_object(&self, path: &std::path::Path) -> Result<(), String>;
pub fn link_executable(
objects: &[&std::path::Path],
output: &std::path::Path,
rt_lib: &std::path::Path,
) -> Result<(), String>;
}// magpie_driver public API
pub struct DriverConfig {
pub entry: String,
pub profile: String,
pub target: Option<String>,
pub emit: Vec<String>,
pub max_errors: u32,
pub llm_mode: bool,
pub token_budget: Option<u32>,
}
pub struct BuildResult {
pub success: bool,
pub diagnostics: Vec<Diagnostic>,
pub artifacts: Vec<String>,
pub timing_ms: std::collections::HashMap<String, u64>,
}
pub fn build(config: &DriverConfig) -> BuildResult;
pub fn format_files(paths: &[String], fix_meta: bool) -> BuildResult;
pub fn run_tests(filter: Option<&str>) -> BuildResult;All functions use C ABI (extern "C"). Header layout:
typedef struct MpRtHeader {
_Atomic uint64_t strong; // offset 0
_Atomic uint64_t weak; // offset 8
uint32_t type_id; // offset 16
uint32_t flags; // offset 20
uint64_t reserved0; // offset 24
} MpRtHeader; // sizeof=32, payload at offset 32| Symbol | Signature |
|---|---|
mp_rt_init |
() -> void |
mp_rt_register_types |
(*const MpRtTypeInfo, u32) -> void |
mp_rt_type_info |
(u32) -> *const MpRtTypeInfo |
mp_rt_alloc |
(u32, u64, u64, u32) -> *mut MpRtHeader |
mp_rt_retain_strong |
(*mut MpRtHeader) -> void |
mp_rt_release_strong |
(*mut MpRtHeader) -> void |
mp_rt_retain_weak |
(*mut MpRtHeader) -> void |
mp_rt_release_weak |
(*mut MpRtHeader) -> void |
mp_rt_weak_upgrade |
(*mut MpRtHeader) -> *mut MpRtHeader |
mp_rt_str_from_utf8 |
(*const u8, u64) -> *mut MpRtHeader |
mp_rt_str_bytes |
(*mut MpRtHeader, *mut u64) -> *const u8 |
mp_rt_panic |
(*mut MpRtHeader) -> ! |
All arr.*, map.*, str.* lower to mp_rt_arr_*, mp_rt_map_*, mp_rt_str_*.
See §20.1.5 for exact signatures.
| ID | Type |
|---|---|
| 0 | unit |
| 1 | bool/i1 |
| 2-6 | i8, i16, i32, i64, i128 |
| 7-11 | u8, u16, u32, u64, u128 |
| 12 | u1 |
| 13-15 | f16, f32, f64 |
| 20 | Str |
| 21 | TStrBuilder |
| 22-26 | Array/Map/TOption/TResult/TCallable bases |
| 30-32 | GPU types |
| ≥1000 | User-defined types |
Stage 1: Parse + CSNF → AstFile + digest [magpie_lex, magpie_parse, magpie_csnf]
Stage 2: Resolve → HirModule (resolved names) [magpie_sema]
Stage 3: Typecheck → typed HIR (TypeIds, layouts) [magpie_types, magpie_sema]
Stage 3.5: Async lowering → coroutine state machines [magpie_hir]
Stage 4: Verify HIR → SSA + borrow-locality ok [magpie_hir]
Stage 5: Ownership check → ownership proofs or errors [magpie_own]
Stage 6: Lower to MPIR → MpirModule (no ARC ops) [magpie_mpir]
Stage 7: MPIR verify → SSA + type refs + phi ok [magpie_mpir]
Stage 8: ARC insertion → MPIR with ARC ops [magpie_arc]
Stage 9: ARC optimization → optimized retain/release [magpie_arc]
Stage 10: LLVM codegen → LLVM module [magpie_codegen_llvm]
Stage 11: Link → executable/shared lib [magpie_codegen_llvm]
Stage 12: MMS update → updated retrieval index [magpie_memory]
Each stage MUST:
- Accept input from the previous stage
- Collect up to
max_errorsdiagnostics - Skip if previous stage produced errors
- Return diagnostics via
DiagnosticBag
- Source fixtures:
tests/fixtures/<name>.mp - Expected MPIR:
tests/fixtures/<name>.mpir - Expected JSON:
tests/fixtures/<name>.json - Snapshot tests use
instacrate - Golden tests compare output byte-for-byte after CSNF normalization