Skip to main content

php_ast/ast/
misc.rs

1#[cfg(feature = "serde")]
2use serde::Serialize;
3
4use crate::Span;
5
6use super::{ArenaVec, Expr, Name, Stmt};
7
8/// A comment found in the source file.
9#[derive(Debug, Clone, Copy)]
10#[cfg_attr(feature = "serde", derive(Serialize))]
11pub struct Comment<'src> {
12    /// Comment syntax form.
13    pub kind: CommentKind,
14    /// Raw text of the comment including its delimiters (e.g. `// foo`, `/* bar */`, `/** baz */`).
15    pub text: &'src str,
16    /// Source range of the comment.
17    pub span: Span,
18}
19
20/// Distinguishes the four syntactic forms of PHP comment.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(Serialize))]
23#[non_exhaustive]
24pub enum CommentKind {
25    /// `// …` — single-line slash comment
26    Line,
27    /// `# …` — single-line hash comment
28    Hash,
29    /// `/* … */` — block comment
30    Block,
31    /// `/** … */` — doc-block comment (first non-whitespace char after `/*` is `*`)
32    Doc,
33}
34
35/// The root AST node representing a complete PHP file.
36#[derive(Debug)]
37#[cfg_attr(feature = "serde", derive(Serialize))]
38pub struct Program<'arena, 'src> {
39    /// Top-level statements.
40    pub stmts: ArenaVec<'arena, Stmt<'arena, 'src>>,
41    /// Source range of this node.
42    pub span: Span,
43}
44
45/// A call argument, including named, spread and by-reference forms.
46#[derive(Debug)]
47#[cfg_attr(feature = "serde", derive(Serialize))]
48#[non_exhaustive]
49pub struct Arg<'arena, 'src> {
50    /// Argument name in a named argument (PHP 8.0+).
51    pub name: Option<Name<'arena, 'src>>,
52    /// What the argument passes.
53    pub kind: ArgKind<'arena, 'src>,
54    /// Source range of this node.
55    pub span: Span,
56}
57
58impl<'arena, 'src> Arg<'arena, 'src> {
59    /// Builds a `Arg` from its identifying fields with every other field empty. Set
60    /// the rest by assignment, as with `Param::new`.
61    pub fn new(name: Option<Name<'arena, 'src>>, kind: ArgKind<'arena, 'src>, span: Span) -> Self {
62        Self { name, kind, span }
63    }
64}
65
66/// The form of a call argument.
67#[derive(Debug)]
68#[cfg_attr(feature = "serde", derive(Serialize))]
69#[non_exhaustive]
70pub enum ArgKind<'arena, 'src> {
71    /// A plain value: `f($x)`, or `f(name: $x)` when the argument has a name.
72    Value(Expr<'arena, 'src>),
73    /// A spread: `f(...$args)`.
74    Spread(Expr<'arena, 'src>),
75    /// Call-time pass-by-reference: `f(&$x)`, a fatal error since PHP 5.4.
76    ByRef(Expr<'arena, 'src>),
77    /// The PHP 8.6 partial-application placeholder `?`.
78    Placeholder,
79    /// The PHP 8.6 partial-application placeholder `...`.
80    SpreadPlaceholder,
81}
82
83impl<'arena, 'src> Arg<'arena, 'src> {
84    /// The argument expression; `None` for a placeholder.
85    pub fn value(&self) -> Option<&Expr<'arena, 'src>> {
86        match &self.kind {
87            ArgKind::Value(e) | ArgKind::Spread(e) | ArgKind::ByRef(e) => Some(e),
88            ArgKind::Placeholder | ArgKind::SpreadPlaceholder => None,
89        }
90    }
91
92    /// Mutable access to the argument expression; `None` for a placeholder.
93    pub fn value_mut(&mut self) -> Option<&mut Expr<'arena, 'src>> {
94        match &mut self.kind {
95            ArgKind::Value(e) | ArgKind::Spread(e) | ArgKind::ByRef(e) => Some(e),
96            ArgKind::Placeholder | ArgKind::SpreadPlaceholder => None,
97        }
98    }
99
100    /// Whether the argument is a `...` spread (not the `...` placeholder).
101    pub fn is_spread(&self) -> bool {
102        matches!(self.kind, ArgKind::Spread(_))
103    }
104
105    /// Whether the argument is a PHP 8.6 `?` or `...` placeholder.
106    pub fn is_placeholder(&self) -> bool {
107        matches!(self.kind, ArgKind::Placeholder | ArgKind::SpreadPlaceholder)
108    }
109}
110
111/// A single attribute: `#[Name(args)]`.
112#[derive(Debug)]
113#[cfg_attr(feature = "serde", derive(Serialize))]
114#[non_exhaustive]
115pub struct Attribute<'arena, 'src> {
116    /// Attribute class name.
117    pub name: Name<'arena, 'src>,
118    /// Attribute arguments.
119    pub args: ArenaVec<'arena, Arg<'arena, 'src>>,
120    /// Source range of this node.
121    pub span: Span,
122}
123
124impl<'arena, 'src> Attribute<'arena, 'src> {
125    /// Builds a `Attribute` from its identifying fields with every other field empty. Set
126    /// the rest by assignment, as with `Param::new`.
127    pub fn new(arena: &'arena bumpalo::Bump, name: Name<'arena, 'src>, span: Span) -> Self {
128        Self {
129            name,
130            args: ArenaVec::new_in(arena),
131            span,
132        }
133    }
134}