mago-syntax 1.45.0

A correct, fast, and memory-efficient PHP syntax implementation, including Lexer, Parser, AST, and utilities for Mago.
Documentation
use strum::Display;

use mago_allocator::CopyInto;
use mago_span::HasSpan;
use mago_span::Span;

use crate::cst::Sequence;

/// Represents the kind of trivia.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, Display)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
pub enum TriviaKind {
    WhiteSpace,
    SingleLineComment,
    MultiLineComment,
    HashComment,
    DocBlockComment,
}

/// Represents a trivia.
///
/// A trivia is a piece of information that is not part of the syntax tree,
/// such as comments and white spaces.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct Trivia<'arena> {
    pub kind: TriviaKind,
    pub span: Span,
    pub value: &'arena [u8],
}

impl TriviaKind {
    /// Returns `true` if the trivia kind is a comment.
    #[inline]
    #[must_use]
    pub const fn is_comment(&self) -> bool {
        matches!(
            self,
            TriviaKind::SingleLineComment
                | TriviaKind::MultiLineComment
                | TriviaKind::HashComment
                | TriviaKind::DocBlockComment
        )
    }

    #[inline]
    #[must_use]
    pub const fn is_docblock(&self) -> bool {
        matches!(self, TriviaKind::DocBlockComment)
    }

    #[inline]
    #[must_use]
    pub const fn is_block_comment(&self) -> bool {
        matches!(self, TriviaKind::MultiLineComment | TriviaKind::DocBlockComment)
    }

    #[inline]
    #[must_use]
    pub const fn is_single_line_comment(&self) -> bool {
        matches!(self, TriviaKind::HashComment | TriviaKind::SingleLineComment)
    }
}

impl HasSpan for Trivia<'_> {
    fn span(&self) -> Span {
        self.span
    }
}

/// Iteration helpers over a trivia [`Sequence`].
///
/// `Sequence` lives in [`mago_syntax_core`], so PHP-specific helpers are
/// exposed as an extension trait. `use crate::cst::*;` imports it.
pub trait TriviaSequenceExt<'arena> {
    fn comments<'borrow>(&'borrow self) -> impl Iterator<Item = &'borrow Trivia<'arena>>
    where
        'arena: 'borrow;
}

impl<'arena> TriviaSequenceExt<'arena> for Sequence<'arena, Trivia<'arena>> {
    #[inline]
    fn comments<'borrow>(&'borrow self) -> impl Iterator<Item = &'borrow Trivia<'arena>>
    where
        'arena: 'borrow,
    {
        self.iter().filter(|trivia| trivia.kind.is_comment())
    }
}

impl CopyInto for Trivia<'_> {
    type Output<'arena> = Trivia<'arena>;

    fn copy_into<'arena, A>(&self, arena: &'arena A) -> Self::Output<'arena>
    where
        A: mago_allocator::Arena,
    {
        Trivia { kind: self.kind, span: self.span, value: arena.alloc_slice_copy(self.value) }
    }
}