Skip to main content

php_ast/ast/
decls.rs

1use serde::Serialize;
2
3use crate::Span;
4
5use super::{ArenaVec, Attribute, Block, Comment, Expr, Ident, Name, TypeHint};
6
7/// A named function declaration: `function foo() {}`.
8#[derive(Debug, Serialize)]
9pub struct FunctionDecl<'arena, 'src> {
10    /// Function name.
11    pub name: Ident<'src>,
12    /// Declared parameters.
13    pub params: ArenaVec<'arena, Param<'arena, 'src>>,
14    /// Function body.
15    pub body: &'arena Block<'arena, 'src>,
16    /// Declared return type, if any.
17    pub return_type: Option<TypeHint<'arena, 'src>>,
18    /// `true` when by reference (`&`).
19    pub by_ref: bool,
20    /// `#[...]` attributes applied to this node.
21    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
22    /// The immediately preceding `/** */` doc-block, if any.
23    ///
24    /// When present, this comment is **removed** from
25    /// `ParseResult::comments` — the
26    /// two collections are disjoint. All other comment forms (line, hash,
27    /// block) remain in `ParseResult::comments` regardless of position.
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub doc_comment: Option<Comment<'src>>,
30}
31
32/// A function, method, closure or hook parameter.
33#[derive(Debug, Serialize)]
34pub struct Param<'arena, 'src> {
35    /// Parameter name without `$`.
36    pub name: Ident<'src>,
37    /// Declared parameter type.
38    pub type_hint: Option<TypeHint<'arena, 'src>>,
39    /// Default value expression.
40    pub default: Option<Expr<'arena, 'src>>,
41    /// `true` when by reference (`&`).
42    pub by_ref: bool,
43    /// `true` for a variadic parameter (`...$x`).
44    pub variadic: bool,
45    /// `true` for a `readonly` promoted property.
46    pub is_readonly: bool,
47    /// `true` for a `final` promoted property.
48    pub is_final: bool,
49    /// Visibility of a promoted constructor property.
50    pub visibility: Option<Visibility>,
51    /// Asymmetric write visibility, e.g. `private(set)` (PHP 8.4+).
52    pub set_visibility: Option<Visibility>,
53    /// `#[...]` attributes applied to this node.
54    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
55    /// Property hooks on a promoted property (PHP 8.4+).
56    #[serde(skip_serializing_if = "ArenaVec::is_empty")]
57    pub hooks: ArenaVec<'arena, PropertyHook<'arena, 'src>>,
58    /// A doc-block attached directly to this parameter (PHP 8.6 recognizes
59    /// this for reflection purposes), either immediately before it or
60    /// trailing it up to the comma. Parsed at every version since a bare
61    /// comment is legal PHP regardless of target version.
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub doc_comment: Option<Comment<'src>>,
64    /// Source range of this node.
65    pub span: Span,
66}
67
68/// Member visibility modifier.
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
70pub enum Visibility {
71    /// `public` — accessible from anywhere.
72    Public,
73    /// `protected` — accessible within the class and its subclasses.
74    Protected,
75    /// `private` — accessible only within the declaring class.
76    Private,
77}
78
79/// The braced member list of a class-like declaration.
80#[derive(Debug, Serialize)]
81pub struct ClassBody<'arena, 'src> {
82    /// Class members in source order.
83    pub members: ArenaVec<'arena, ClassMember<'arena, 'src>>,
84    /// Span covering `{` to `}` of the body.
85    #[serde(skip)]
86    pub span: Span,
87}
88
89/// A class declaration, or the body of an anonymous class.
90#[derive(Debug, Serialize)]
91pub struct ClassDecl<'arena, 'src> {
92    /// Class name; `None` for anonymous classes.
93    pub name: Option<Ident<'src>>,
94    /// `abstract`, `final` and `readonly` modifiers.
95    pub modifiers: ClassModifiers,
96    /// Parent class.
97    pub extends: Option<Name<'arena, 'src>>,
98    /// Implemented interfaces.
99    pub implements: ArenaVec<'arena, Name<'arena, 'src>>,
100    /// Class body, flattened on serialization.
101    #[serde(flatten)]
102    pub body: ClassBody<'arena, 'src>,
103    /// `#[...]` attributes applied to this node.
104    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
105    /// Preceding `/** */` doc-block, if any.
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub doc_comment: Option<Comment<'src>>,
108}
109
110/// Modifiers preceding `class`.
111#[derive(Debug, Clone, Serialize, Default)]
112pub struct ClassModifiers {
113    /// `true` for `abstract class`.
114    pub is_abstract: bool,
115    /// `true` for `final class`.
116    pub is_final: bool,
117    /// `true` for `readonly class`.
118    pub is_readonly: bool,
119}
120
121/// A member of a class, interface or trait body.
122#[derive(Debug, Serialize)]
123pub struct ClassMember<'arena, 'src> {
124    /// Kind of member.
125    pub kind: ClassMemberKind<'arena, 'src>,
126    /// Source range of this node.
127    pub span: Span,
128}
129
130/// The kinds of class-like member.
131#[derive(Debug, Serialize)]
132pub enum ClassMemberKind<'arena, 'src> {
133    /// Property declaration.
134    Property(PropertyDecl<'arena, 'src>),
135    /// Method declaration.
136    Method(MethodDecl<'arena, 'src>),
137    /// Class constant declaration.
138    ClassConst(ClassConstDecl<'arena, 'src>),
139    /// Trait `use` statement.
140    TraitUse(TraitUseDecl<'arena, 'src>),
141}
142
143/// A property declaration: `public int $x = 0;`.
144#[derive(Debug, Serialize)]
145pub struct PropertyDecl<'arena, 'src> {
146    /// Property name without `$`.
147    pub name: Ident<'src>,
148    /// Declared visibility, if any.
149    pub visibility: Option<Visibility>,
150    /// Asymmetric write visibility, e.g. `private(set)` (PHP 8.4+).
151    pub set_visibility: Option<Visibility>,
152    /// `true` for `static`.
153    pub is_static: bool,
154    /// `true` for `readonly`.
155    pub is_readonly: bool,
156    /// Declared type, if any.
157    pub type_hint: Option<TypeHint<'arena, 'src>>,
158    /// Default value expression.
159    pub default: Option<Expr<'arena, 'src>>,
160    /// `#[...]` attributes applied to this node.
161    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
162    /// Property hooks (PHP 8.4+).
163    #[serde(skip_serializing_if = "ArenaVec::is_empty")]
164    pub hooks: ArenaVec<'arena, PropertyHook<'arena, 'src>>,
165    /// Preceding `/** */` doc-block, if any.
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub doc_comment: Option<Comment<'src>>,
168}
169
170/// Which accessor a property hook implements.
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
172pub enum PropertyHookKind {
173    /// `get` hook — called when the property is read.
174    Get,
175    /// `set` hook — called when the property is written; receives the incoming value as `$value`.
176    Set,
177}
178
179/// The body form of a property hook.
180#[derive(Debug, Serialize)]
181pub enum PropertyHookBody<'arena, 'src> {
182    /// `{ stmts }` — a full statement block.
183    Block(&'arena Block<'arena, 'src>),
184    /// `=> expr` — short-form expression body.
185    Expression(Expr<'arena, 'src>),
186    /// No body — the hook is declared abstract (on an abstract class or interface).
187    Abstract,
188}
189
190/// A property hook: `get { ... }` or `set => ...` (PHP 8.4+).
191#[derive(Debug, Serialize)]
192pub struct PropertyHook<'arena, 'src> {
193    /// Whether this is a `get` or `set` hook.
194    pub kind: PropertyHookKind,
195    /// Hook body.
196    pub body: PropertyHookBody<'arena, 'src>,
197    /// `true` for a `final` hook.
198    pub is_final: bool,
199    /// `true` for `&get`.
200    pub by_ref: bool,
201    /// Explicit parameters, e.g. `set(string $v)`.
202    pub params: ArenaVec<'arena, Param<'arena, 'src>>,
203    /// `#[...]` attributes applied to this node.
204    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
205    /// Source range of this node.
206    pub span: Span,
207}
208
209/// A method declaration inside a class-like body.
210#[derive(Debug, Serialize)]
211pub struct MethodDecl<'arena, 'src> {
212    /// Method name.
213    pub name: Ident<'src>,
214    /// Declared visibility, if any.
215    pub visibility: Option<Visibility>,
216    /// `true` for `static`.
217    pub is_static: bool,
218    /// `true` for `abstract`.
219    pub is_abstract: bool,
220    /// `true` for `final`.
221    pub is_final: bool,
222    /// `true` when by reference (`&`).
223    pub by_ref: bool,
224    /// Declared parameters.
225    pub params: ArenaVec<'arena, Param<'arena, 'src>>,
226    /// Declared return type, if any.
227    pub return_type: Option<TypeHint<'arena, 'src>>,
228    /// `None` for an abstract/interface method.
229    pub body: Option<&'arena Block<'arena, 'src>>,
230    /// `#[...]` attributes applied to this node.
231    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
232    /// Preceding `/** */` doc-block, if any.
233    #[serde(skip_serializing_if = "Option::is_none")]
234    pub doc_comment: Option<Comment<'src>>,
235}
236
237/// A class constant: `const X = 1;`.
238#[derive(Debug, Serialize)]
239pub struct ClassConstDecl<'arena, 'src> {
240    /// Constant name.
241    pub name: Ident<'src>,
242    /// Declared visibility, if any.
243    pub visibility: Option<Visibility>,
244    /// `true` for `final`.
245    pub is_final: bool,
246    /// Typed class constant type (PHP 8.3+).
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub type_hint: Option<&'arena TypeHint<'arena, 'src>>,
249    /// Constant value expression.
250    pub value: Expr<'arena, 'src>,
251    /// `#[...]` attributes applied to this node.
252    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
253    /// Preceding `/** */` doc-block, if any.
254    #[serde(skip_serializing_if = "Option::is_none")]
255    pub doc_comment: Option<Comment<'src>>,
256}
257
258/// A `use` of traits inside a class-like body.
259#[derive(Debug, Serialize)]
260pub struct TraitUseDecl<'arena, 'src> {
261    /// Traits being used.
262    pub traits: ArenaVec<'arena, Name<'arena, 'src>>,
263    /// `insteadof` and `as` rules from the adaptation block.
264    pub adaptations: ArenaVec<'arena, TraitAdaptation<'arena, 'src>>,
265    /// Start byte offset of the `{` that opens the adaptations block; `None` when there are no adaptations.
266    #[serde(skip)]
267    pub adaptations_brace_start: Option<u32>,
268    /// Preceding `/** */` doc-block, if any.
269    #[serde(skip_serializing_if = "Option::is_none")]
270    pub doc_comment: Option<Comment<'src>>,
271}
272
273/// A single rule in a trait `use` adaptation block.
274#[derive(Debug, Serialize)]
275pub struct TraitAdaptation<'arena, 'src> {
276    /// Kind of adaptation rule.
277    pub kind: TraitAdaptationKind<'arena, 'src>,
278    /// Source range of this node.
279    pub span: Span,
280}
281
282/// The kinds of trait adaptation rule.
283#[derive(Debug, Serialize)]
284pub enum TraitAdaptationKind<'arena, 'src> {
285    /// `A::foo insteadof B, C;`
286    Precedence {
287        /// Trait qualifying the method, if written.
288        trait_name: Name<'arena, 'src>,
289        /// Method being adapted.
290        method: Name<'arena, 'src>,
291        /// Traits whose method is excluded.
292        insteadof: ArenaVec<'arena, Name<'arena, 'src>>,
293    },
294    /// `foo as bar;` or `A::foo as protected bar;` or `foo as protected;`
295    Alias {
296        /// Trait qualifying the method, if written.
297        trait_name: Option<Name<'arena, 'src>>,
298        /// Method being adapted.
299        method: Name<'arena, 'src>,
300        /// New visibility, if changed.
301        new_modifier: Option<Visibility>,
302        /// Alias name, if given.
303        new_name: Option<Name<'arena, 'src>>,
304    },
305}
306
307/// An interface declaration.
308#[derive(Debug, Serialize)]
309pub struct InterfaceDecl<'arena, 'src> {
310    /// Interface name.
311    pub name: Ident<'src>,
312    /// Extended interfaces.
313    pub extends: ArenaVec<'arena, Name<'arena, 'src>>,
314    /// Interface body, flattened on serialization.
315    #[serde(flatten)]
316    pub body: ClassBody<'arena, 'src>,
317    /// `#[...]` attributes applied to this node.
318    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
319    /// Preceding `/** */` doc-block, if any.
320    #[serde(skip_serializing_if = "Option::is_none")]
321    pub doc_comment: Option<Comment<'src>>,
322}
323
324/// A trait declaration.
325#[derive(Debug, Serialize)]
326pub struct TraitDecl<'arena, 'src> {
327    /// Trait name.
328    pub name: Ident<'src>,
329    /// Trait body, flattened on serialization.
330    #[serde(flatten)]
331    pub body: ClassBody<'arena, 'src>,
332    /// `#[...]` attributes applied to this node.
333    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
334    /// Preceding `/** */` doc-block, if any.
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub doc_comment: Option<Comment<'src>>,
337}
338
339/// The braced member list of an enum.
340#[derive(Debug, Serialize)]
341pub struct EnumBody<'arena, 'src> {
342    /// Enum members in source order.
343    pub members: ArenaVec<'arena, EnumMember<'arena, 'src>>,
344    /// Span covering `{` to `}` of the body.
345    #[serde(skip)]
346    pub span: Span,
347}
348
349/// An enum declaration (PHP 8.1+).
350#[derive(Debug, Serialize)]
351pub struct EnumDecl<'arena, 'src> {
352    /// Enum name.
353    pub name: Ident<'src>,
354    /// Backing type of a backed enum.
355    pub scalar_type: Option<Name<'arena, 'src>>,
356    /// Implemented interfaces.
357    pub implements: ArenaVec<'arena, Name<'arena, 'src>>,
358    /// Enum body, flattened on serialization.
359    #[serde(flatten)]
360    pub body: EnumBody<'arena, 'src>,
361    /// `#[...]` attributes applied to this node.
362    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
363    /// Preceding `/** */` doc-block, if any.
364    #[serde(skip_serializing_if = "Option::is_none")]
365    pub doc_comment: Option<Comment<'src>>,
366}
367
368/// A member of an enum body.
369#[derive(Debug, Serialize)]
370pub struct EnumMember<'arena, 'src> {
371    /// Kind of member.
372    pub kind: EnumMemberKind<'arena, 'src>,
373    /// Source range of this node.
374    pub span: Span,
375}
376
377/// The kinds of enum member.
378#[derive(Debug, Serialize)]
379pub enum EnumMemberKind<'arena, 'src> {
380    /// An enum case: `case Foo;` or `case Foo = 'foo';` (backed enum).
381    Case(EnumCase<'arena, 'src>),
382    /// A method defined inside the enum body.
383    Method(MethodDecl<'arena, 'src>),
384    /// A constant defined inside the enum body: `const X = 1;`.
385    ClassConst(ClassConstDecl<'arena, 'src>),
386    /// A trait use inside the enum body: `use SomeTrait;`.
387    TraitUse(TraitUseDecl<'arena, 'src>),
388}
389
390/// A `case` inside an enum.
391#[derive(Debug, Serialize)]
392pub struct EnumCase<'arena, 'src> {
393    /// Case name.
394    pub name: Ident<'src>,
395    /// Backing value of a backed case.
396    pub value: Option<Expr<'arena, 'src>>,
397    /// `#[...]` attributes applied to this node.
398    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
399    /// Preceding `/** */` doc-block, if any.
400    #[serde(skip_serializing_if = "Option::is_none")]
401    pub doc_comment: Option<Comment<'src>>,
402}