Skip to main content

mago_syntax/cst/
trivia.rs

1use strum::Display;
2
3use mago_allocator::CopyInto;
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::cst::Sequence;
8
9/// Represents the kind of trivia.
10#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, Display)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize))]
12#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
13pub enum TriviaKind {
14    WhiteSpace,
15    SingleLineComment,
16    MultiLineComment,
17    HashComment,
18    DocBlockComment,
19}
20
21/// Represents a trivia.
22///
23/// A trivia is a piece of information that is not part of the syntax tree,
24/// such as comments and white spaces.
25#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize))]
27pub struct Trivia<'arena> {
28    pub kind: TriviaKind,
29    pub span: Span,
30    pub value: &'arena [u8],
31}
32
33impl TriviaKind {
34    /// Returns `true` if the trivia kind is a comment.
35    #[inline]
36    #[must_use]
37    pub const fn is_comment(&self) -> bool {
38        matches!(
39            self,
40            TriviaKind::SingleLineComment
41                | TriviaKind::MultiLineComment
42                | TriviaKind::HashComment
43                | TriviaKind::DocBlockComment
44        )
45    }
46
47    #[inline]
48    #[must_use]
49    pub const fn is_docblock(&self) -> bool {
50        matches!(self, TriviaKind::DocBlockComment)
51    }
52
53    #[inline]
54    #[must_use]
55    pub const fn is_block_comment(&self) -> bool {
56        matches!(self, TriviaKind::MultiLineComment | TriviaKind::DocBlockComment)
57    }
58
59    #[inline]
60    #[must_use]
61    pub const fn is_single_line_comment(&self) -> bool {
62        matches!(self, TriviaKind::HashComment | TriviaKind::SingleLineComment)
63    }
64}
65
66impl HasSpan for Trivia<'_> {
67    fn span(&self) -> Span {
68        self.span
69    }
70}
71
72/// Iteration helpers over a trivia [`Sequence`].
73///
74/// `Sequence` lives in [`mago_syntax_core`], so PHP-specific helpers are
75/// exposed as an extension trait. `use crate::cst::*;` imports it.
76pub trait TriviaSequenceExt<'arena> {
77    fn comments<'borrow>(&'borrow self) -> impl Iterator<Item = &'borrow Trivia<'arena>>
78    where
79        'arena: 'borrow;
80}
81
82impl<'arena> TriviaSequenceExt<'arena> for Sequence<'arena, Trivia<'arena>> {
83    #[inline]
84    fn comments<'borrow>(&'borrow self) -> impl Iterator<Item = &'borrow Trivia<'arena>>
85    where
86        'arena: 'borrow,
87    {
88        self.iter().filter(|trivia| trivia.kind.is_comment())
89    }
90}
91
92impl CopyInto for Trivia<'_> {
93    type Output<'arena> = Trivia<'arena>;
94
95    fn copy_into<'arena, A>(&self, arena: &'arena A) -> Self::Output<'arena>
96    where
97        A: mago_allocator::Arena,
98    {
99        Trivia { kind: self.kind, span: self.span, value: arena.alloc_slice_copy(self.value) }
100    }
101}