ecma-syntax-cat 0.1.0

ECMAScript abstract syntax tree as comp-cat-rs-idiomatic Rust types. ESTree-shaped, ES2024-complete, no panics, no Rc, no interior mutability. Foundation crate for boa-cat and related downstream tooling.
Documentation
//! Variable declarations.

use crate::expression::Expression;
use crate::pattern::Pattern;

/// A variable declaration (`var x = 1, y;` etc.).
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariableDeclaration {
    kind: VariableKind,
    declarators: Vec<VariableDeclarator>,
}

impl VariableDeclaration {
    /// Build a variable declaration.
    #[must_use]
    pub fn new(kind: VariableKind, declarators: Vec<VariableDeclarator>) -> Self {
        Self { kind, declarators }
    }

    /// Whether the declaration uses `var`, `let`, or `const`.
    #[must_use]
    pub fn kind(&self) -> VariableKind {
        self.kind
    }

    /// The individual declarators (`x = 1`, `y`, etc.).
    #[must_use]
    pub fn declarators(&self) -> &[VariableDeclarator] {
        &self.declarators
    }
}

impl std::fmt::Display for VariableDeclaration {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{} ", self.kind)?;
        let parts = self
            .declarators
            .iter()
            .map(|d| format!("{d}"))
            .collect::<Vec<_>>()
            .join(", ");
        f.write_str(&parts)
    }
}

/// Which keyword introduces a variable declaration.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VariableKind {
    /// `var` (function-scoped).
    Var,
    /// `let` (block-scoped, mutable).
    Let,
    /// `const` (block-scoped, immutable binding).
    Const,
}

impl std::fmt::Display for VariableKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(match self {
            Self::Var => "var",
            Self::Let => "let",
            Self::Const => "const",
        })
    }
}

/// One declarator inside a variable declaration: a binding pattern with an
/// optional initialiser.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VariableDeclarator {
    id: Pattern,
    init: Option<Expression>,
}

impl VariableDeclarator {
    /// Build a declarator.
    #[must_use]
    pub fn new(id: Pattern, init: Option<Expression>) -> Self {
        Self { id, init }
    }

    /// The binding pattern (often just an identifier).
    #[must_use]
    pub fn id(&self) -> &Pattern {
        &self.id
    }

    /// The optional initialiser expression.
    #[must_use]
    pub fn init(&self) -> Option<&Expression> {
        self.init.as_ref()
    }
}

impl std::fmt::Display for VariableDeclarator {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.init {
            Some(expr) => write!(f, "{} = {expr}", self.id),
            None => write!(f, "{}", self.id),
        }
    }
}