nova-ast 0.3.0

The Nova language's syntax tree (internal to the nova toolchain)
Documentation
//! Top-level item AST nodes.

use nova_diagnostics::{Span, Spanned};

use crate::{expr::Expr, ty::Type, Block, Path};

/// Re-export from expr for convenience (AssignOp needed by callers of item).
pub use crate::expr::AssignOp;

/// An `@name` or `@name(arg, ...)` attribute on an item.
///
/// Arguments are bare identifiers, not expressions: the two forms the spec uses
/// are `@test(should_panic)` and `@derive(Copy, Clone)`, both identifier lists.
/// Widening this to expressions later is additive; narrowing it would not be.
#[derive(Debug, Clone)]
pub struct Attribute {
    pub name: Spanned<String>,
    pub args: Vec<Spanned<String>>,
    pub span: Span,
}

/// Visibility of a declaration.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Visibility {
    Pub,
    Private,
}

/// A function parameter.
#[derive(Debug, Clone)]
pub struct Param {
    pub is_mut: bool,
    pub name: Spanned<String>,
    pub ty: Spanned<Type>,
}

/// A `where` clause bound, e.g. `T: Display + Clone`.
#[derive(Debug, Clone)]
pub struct WhereBound {
    pub ty: Spanned<Type>,
    pub bounds: Vec<Spanned<Path>>,
}

/// A function or method declaration.
#[derive(Debug, Clone)]
pub struct Function {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub is_async: bool,
    pub name: Spanned<String>,
    pub generics: Vec<crate::ty::TypeParam>,
    pub params: Vec<Param>,
    pub return_ty: Option<Spanned<Type>>,
    pub where_clause: Vec<WhereBound>,
    pub body: Spanned<Block>,
}

/// A `record` (struct) declaration.
#[derive(Debug, Clone)]
pub struct Record {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub name: Spanned<String>,
    pub generics: Vec<crate::ty::TypeParam>,
    pub fields: Vec<RecordField>,
}

/// A single field inside a `record { ... }` body.
#[derive(Debug, Clone)]
pub struct RecordField {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub vis: Visibility,
    pub name: Spanned<String>,
    pub ty: Spanned<Type>,
}

/// A `type` alias or sum type declaration.
///
/// ```nova
/// type Color = | Red | Green | Blue
/// type Alias<T> = Vec<T>
/// ```
#[derive(Debug, Clone)]
pub struct TypeDecl {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub name: Spanned<String>,
    pub generics: Vec<crate::ty::TypeParam>,
    pub def: TypeDef,
}

/// The right-hand side of a `type` declaration.
#[derive(Debug, Clone)]
pub enum TypeDef {
    /// A plain type alias.
    Alias(Spanned<Type>),
    /// A sum type (algebraic data type / enum).
    Sum(Vec<Variant>),
}

/// A variant of a sum type.
#[derive(Debug, Clone)]
pub struct Variant {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub name: Spanned<String>,
    /// Fields of a tuple-style variant, e.g. `Ok(T)` has one field.
    pub fields: Vec<Spanned<Type>>,
}

/// A `trait` declaration.
#[derive(Debug, Clone)]
pub struct TraitDecl {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub name: Spanned<String>,
    pub generics: Vec<crate::ty::TypeParam>,
    pub supertraits: Vec<Spanned<Path>>,
    /// A `where` clause on the trait itself (e.g. `trait B where Self: A`), as
    /// opposed to the `trait B: A` shorthand (stored in `supertraits`). Parsed
    /// but not otherwise supported yet — `nova-typeck` reports `E0900` for a
    /// non-empty clause here rather than acting on it.
    pub where_clause: Vec<WhereBound>,
    pub items: Vec<TraitItem>,
}

/// An item inside a trait body.
#[derive(Debug, Clone)]
pub enum TraitItem {
    /// A required method (signature only).
    Required(FunctionSig),
    /// A provided method (with default body).
    Provided(Function),
    /// An associated type declaration: `type Item`.
    ///
    /// `bounds` is parsed (`type Item: Display`) but **not** supported —
    /// `nova-typeck` reports `E0900` for a non-empty list, the same way a
    /// `where` clause on a trait is parsed here and rejected there. Parsing it
    /// gives a precise span and a real diagnostic instead of a syntax error.
    AssocType {
        /// The `///` lines before it, as on the items above.
        docs: Vec<Spanned<String>>,
        name: Spanned<String>,
        bounds: Vec<Spanned<Path>>,
    },
}

/// A function signature without a body.
#[derive(Debug, Clone)]
pub struct FunctionSig {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub is_async: bool,
    pub name: Spanned<String>,
    pub generics: Vec<crate::ty::TypeParam>,
    pub params: Vec<Param>,
    pub return_ty: Option<Spanned<Type>>,
    pub where_clause: Vec<WhereBound>,
}

/// An `impl` block.
#[derive(Debug, Clone)]
pub struct ImplBlock {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub generics: Vec<crate::ty::TypeParam>,
    /// If `Some`, this is a trait impl: `impl Trait for Type`.
    pub trait_: Option<Spanned<Path>>,
    pub ty: Spanned<Type>,
    pub where_clause: Vec<WhereBound>,
    pub functions: Vec<Function>,
    pub consts: Vec<ConstDecl>,
    /// Associated types this impl binds (`type Item = Int`).
    ///
    /// A third parallel vector beside `functions` and `consts`, not a variant
    /// of a shared item enum: an `ImplBlock` has never had a unified item
    /// list, and adding one would touch every consumer of the other two.
    pub assoc_types: Vec<AssocTypeBinding>,
}

/// One associated-type binding inside an `impl` block: `type Item = Int`.
///
/// There is deliberately no `vis` field. An associated-type binding is not an
/// independently nameable item — it is only ever reached through a projection
/// on the impl's trait, whose own visibility already governs it — so a `pub`
/// here would be stored and honoured by nothing. `nova-parser` rejects one
/// instead of dropping it silently.
#[derive(Debug, Clone)]
pub struct AssocTypeBinding {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub name: Spanned<String>,
    pub ty: Spanned<Type>,
}

/// A `const` declaration.
#[derive(Debug, Clone)]
pub struct ConstDecl {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub name: Spanned<String>,
    pub ty: Spanned<Type>,
    pub value: Spanned<Expr>,
}

/// An `import` declaration.
#[derive(Debug, Clone)]
pub struct Import {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub path: Spanned<Path>,
    pub kind: ImportKind,
}

/// How an import is bound into the current namespace.
#[derive(Debug, Clone)]
pub enum ImportKind {
    /// `import foo` — binds the last segment name.
    Simple,
    /// `import foo as bar` — binds under an alias.
    Alias(Spanned<String>),
    /// `import foo::{a, b, c}` — destructures selected names.
    List(Vec<Spanned<String>>),
}

/// A `module` declaration (refers to another file).
#[derive(Debug, Clone)]
pub struct Module {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub path: Spanned<Path>,
}

/// An `extern` block for FFI declarations.
#[derive(Debug, Clone)]
pub struct ExternBlock {
    /// The `///` lines before it, one entry per line, holding the text after
    /// the `///` (spec
    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
    pub docs: Vec<Spanned<String>>,
    pub attrs: Vec<Attribute>,
    pub abi: Option<String>,
    pub items: Vec<ExternItem>,
}

/// An item inside an `extern` block.
#[derive(Debug, Clone)]
pub enum ExternItem {
    Fn(FunctionSig),
}