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
//! Function definitions shared between function declarations, function
//! expressions, and method definitions.

use crate::identifier::Identifier;
use crate::pattern::Pattern;
use crate::statement::Statement;

/// An ECMAScript function definition.
///
/// Distinguishes declarations from expressions only by where the value is
/// used; the structural shape is identical, so both share this type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Function {
    id: Option<Identifier>,
    params: Vec<Pattern>,
    body: Vec<Statement>,
    is_async: bool,
    is_generator: bool,
}

impl Function {
    /// Build a function definition.
    #[must_use]
    pub fn new(
        id: Option<Identifier>,
        params: Vec<Pattern>,
        body: Vec<Statement>,
        is_async: bool,
        is_generator: bool,
    ) -> Self {
        Self {
            id,
            params,
            body,
            is_async,
            is_generator,
        }
    }

    /// The function's name, if any.  Function declarations always have one;
    /// expressions may be anonymous.
    #[must_use]
    pub fn id(&self) -> Option<&Identifier> {
        self.id.as_ref()
    }

    /// The formal parameters.
    #[must_use]
    pub fn params(&self) -> &[Pattern] {
        &self.params
    }

    /// The statements making up the function body.
    #[must_use]
    pub fn body(&self) -> &[Statement] {
        &self.body
    }

    /// Whether the function was declared `async`.
    #[must_use]
    pub fn is_async(&self) -> bool {
        self.is_async
    }

    /// Whether the function was declared a generator (`function*`).
    #[must_use]
    pub fn is_generator(&self) -> bool {
        self.is_generator
    }
}

impl std::fmt::Display for Function {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.is_async {
            f.write_str("async ")?;
        }
        f.write_str("function")?;
        if self.is_generator {
            f.write_str("*")?;
        }
        if let Some(name) = &self.id {
            write!(f, " {name}")?;
        }
        let params = self
            .params
            .iter()
            .map(|p| format!("{p}"))
            .collect::<Vec<_>>()
            .join(", ");
        write!(f, "({params}) {{ ... }}")
    }
}

/// An arrow-function body: either an expression (concise body) or a block
/// of statements.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ArrowBody {
    /// `=> expr`
    Expression(Box<crate::expression::Expression>),
    /// `=> { stmts }`
    Block(Vec<Statement>),
}

/// An arrow function definition.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArrowFunction {
    params: Vec<Pattern>,
    body: ArrowBody,
    is_async: bool,
}

impl ArrowFunction {
    /// Build an arrow function.
    #[must_use]
    pub fn new(params: Vec<Pattern>, body: ArrowBody, is_async: bool) -> Self {
        Self {
            params,
            body,
            is_async,
        }
    }

    /// The formal parameters.
    #[must_use]
    pub fn params(&self) -> &[Pattern] {
        &self.params
    }

    /// The body (expression or block).
    #[must_use]
    pub fn body(&self) -> &ArrowBody {
        &self.body
    }

    /// Whether the arrow was declared `async`.
    #[must_use]
    pub fn is_async(&self) -> bool {
        self.is_async
    }
}

impl std::fmt::Display for ArrowFunction {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.is_async {
            f.write_str("async ")?;
        }
        let params = self
            .params
            .iter()
            .map(|p| format!("{p}"))
            .collect::<Vec<_>>()
            .join(", ");
        write!(f, "({params}) => ")?;
        match &self.body {
            ArrowBody::Expression(expr) => write!(f, "{expr}"),
            ArrowBody::Block(_) => f.write_str("{ ... }"),
        }
    }
}