Skip to main content

php_ast/ast/
stmts.rs

1use serde::Serialize;
2
3use crate::Span;
4
5use super::{
6    ArenaVec, Attribute, ClassDecl, Comment, EnumDecl, Expr, FunctionDecl, Ident, InterfaceDecl,
7    Name, TraitDecl,
8};
9
10#[derive(Debug, Serialize)]
11pub struct Stmt<'arena, 'src> {
12    pub kind: StmtKind<'arena, 'src>,
13    pub span: Span,
14}
15
16#[derive(Debug, Serialize)]
17pub enum StmtKind<'arena, 'src> {
18    /// Expression statement (e.g. `foo();`)
19    Expression(&'arena Expr<'arena, 'src>),
20
21    /// Echo statement: `echo expr1, expr2;`
22    Echo(ArenaVec<'arena, Expr<'arena, 'src>>),
23
24    /// Return statement: `return expr;`
25    Return(Option<&'arena Expr<'arena, 'src>>),
26
27    /// Block statement: `{ stmts }`
28    Block(ArenaVec<'arena, Stmt<'arena, 'src>>),
29
30    /// If statement
31    If(&'arena IfStmt<'arena, 'src>),
32
33    /// While loop
34    While(&'arena WhileStmt<'arena, 'src>),
35
36    /// For loop
37    For(&'arena ForStmt<'arena, 'src>),
38
39    /// Foreach loop
40    Foreach(&'arena ForeachStmt<'arena, 'src>),
41
42    /// Do-while loop
43    DoWhile(&'arena DoWhileStmt<'arena, 'src>),
44
45    /// Function declaration
46    Function(&'arena FunctionDecl<'arena, 'src>),
47
48    /// Break statement
49    Break(Option<&'arena Expr<'arena, 'src>>),
50
51    /// Continue statement
52    Continue(Option<&'arena Expr<'arena, 'src>>),
53
54    /// Switch statement
55    Switch(&'arena SwitchStmt<'arena, 'src>),
56
57    /// Goto statement
58    Goto(Ident<'src>),
59
60    /// Label statement
61    Label(&'arena str),
62
63    /// Declare statement
64    Declare(&'arena DeclareStmt<'arena, 'src>),
65
66    /// Unset statement
67    Unset(ArenaVec<'arena, Expr<'arena, 'src>>),
68
69    /// Throw statement (also can be expression in PHP 8)
70    Throw(&'arena Expr<'arena, 'src>),
71
72    /// Try/catch/finally
73    TryCatch(&'arena TryCatchStmt<'arena, 'src>),
74
75    /// Global declaration
76    Global(ArenaVec<'arena, Expr<'arena, 'src>>),
77
78    /// Class declaration
79    Class(&'arena ClassDecl<'arena, 'src>),
80
81    /// Interface declaration
82    Interface(&'arena InterfaceDecl<'arena, 'src>),
83
84    /// Trait declaration
85    Trait(&'arena TraitDecl<'arena, 'src>),
86
87    /// Enum declaration
88    Enum(&'arena EnumDecl<'arena, 'src>),
89
90    /// Namespace declaration
91    Namespace(&'arena NamespaceDecl<'arena, 'src>),
92
93    /// Use declaration
94    Use(&'arena UseDecl<'arena, 'src>),
95
96    /// Top-level constant: `const FOO = expr;`
97    Const(ArenaVec<'arena, ConstItem<'arena, 'src>>),
98
99    /// Static variable declaration: `static $x = 1;`
100    StaticVar(ArenaVec<'arena, StaticVar<'arena, 'src>>),
101
102    /// __halt_compiler(); with remaining data
103    HaltCompiler(&'src str),
104
105    /// Nop (empty statement `;`)
106    Nop,
107
108    /// Inline HTML
109    InlineHtml(&'src str),
110
111    /// Error placeholder — parser always produces a tree
112    Error,
113}
114
115#[derive(Debug, Serialize)]
116pub struct IfStmt<'arena, 'src> {
117    pub condition: Expr<'arena, 'src>,
118    pub then_branch: &'arena Stmt<'arena, 'src>,
119    pub elseif_branches: ArenaVec<'arena, ElseIfBranch<'arena, 'src>>,
120    pub else_branch: Option<&'arena Stmt<'arena, 'src>>,
121}
122
123#[derive(Debug, Serialize)]
124pub struct ElseIfBranch<'arena, 'src> {
125    pub condition: Expr<'arena, 'src>,
126    pub body: Stmt<'arena, 'src>,
127    pub span: Span,
128}
129
130#[derive(Debug, Serialize)]
131pub struct WhileStmt<'arena, 'src> {
132    pub condition: Expr<'arena, 'src>,
133    pub body: &'arena Stmt<'arena, 'src>,
134}
135
136#[derive(Debug, Serialize)]
137pub struct ForStmt<'arena, 'src> {
138    pub init: ArenaVec<'arena, Expr<'arena, 'src>>,
139    pub condition: ArenaVec<'arena, Expr<'arena, 'src>>,
140    pub update: ArenaVec<'arena, Expr<'arena, 'src>>,
141    pub body: &'arena Stmt<'arena, 'src>,
142}
143
144#[derive(Debug, Serialize)]
145pub struct ForeachStmt<'arena, 'src> {
146    pub expr: Expr<'arena, 'src>,
147    pub key: Option<Expr<'arena, 'src>>,
148    pub value: Expr<'arena, 'src>,
149    pub body: &'arena Stmt<'arena, 'src>,
150}
151
152#[derive(Debug, Serialize)]
153pub struct DoWhileStmt<'arena, 'src> {
154    pub body: &'arena Stmt<'arena, 'src>,
155    pub condition: Expr<'arena, 'src>,
156}
157
158#[derive(Debug, Serialize)]
159pub struct SwitchStmt<'arena, 'src> {
160    pub expr: Expr<'arena, 'src>,
161    pub cases: ArenaVec<'arena, SwitchCase<'arena, 'src>>,
162}
163
164#[derive(Debug, Serialize)]
165pub struct SwitchCase<'arena, 'src> {
166    pub value: Option<Expr<'arena, 'src>>,
167    pub body: ArenaVec<'arena, Stmt<'arena, 'src>>,
168    pub span: Span,
169}
170
171#[derive(Debug, Serialize)]
172pub struct TryCatchStmt<'arena, 'src> {
173    pub body: ArenaVec<'arena, Stmt<'arena, 'src>>,
174    pub catches: ArenaVec<'arena, CatchClause<'arena, 'src>>,
175    pub finally: Option<ArenaVec<'arena, Stmt<'arena, 'src>>>,
176}
177
178#[derive(Debug, Serialize)]
179pub struct CatchClause<'arena, 'src> {
180    pub types: ArenaVec<'arena, Name<'arena, 'src>>,
181    pub var: Option<&'src str>,
182    pub body: ArenaVec<'arena, Stmt<'arena, 'src>>,
183    pub span: Span,
184}
185
186#[derive(Debug, Serialize)]
187pub struct NamespaceDecl<'arena, 'src> {
188    pub name: Option<Name<'arena, 'src>>,
189    pub body: NamespaceBody<'arena, 'src>,
190}
191
192#[derive(Debug, Serialize)]
193pub enum NamespaceBody<'arena, 'src> {
194    /// `namespace Foo { … }` — braced form; the statements are scoped to this namespace.
195    Braced(ArenaVec<'arena, Stmt<'arena, 'src>>),
196    /// `namespace Foo;` — simple form; all subsequent statements until the next `namespace` or EOF are in scope.
197    Simple,
198}
199
200#[derive(Debug, Serialize)]
201pub struct DeclareStmt<'arena, 'src> {
202    pub directives: ArenaVec<'arena, (&'src str, Expr<'arena, 'src>)>,
203    pub body: Option<&'arena Stmt<'arena, 'src>>,
204}
205
206#[derive(Debug, Serialize)]
207pub struct UseDecl<'arena, 'src> {
208    pub kind: UseKind,
209    pub uses: ArenaVec<'arena, UseItem<'arena, 'src>>,
210}
211
212#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
213pub enum UseKind {
214    /// `use Foo\Bar` — imports a class, interface, trait, or enum.
215    Normal,
216    /// `use function Foo\bar` — imports a function.
217    Function,
218    /// `use const Foo\BAR` — imports a constant.
219    Const,
220}
221
222#[derive(Debug, Serialize)]
223pub struct UseItem<'arena, 'src> {
224    pub name: Name<'arena, 'src>,
225    pub alias: Option<&'src str>,
226    #[serde(skip_serializing_if = "Option::is_none")]
227    pub kind: Option<UseKind>,
228    pub span: Span,
229}
230
231#[derive(Debug, Serialize)]
232pub struct ConstItem<'arena, 'src> {
233    pub name: Ident<'src>,
234    pub value: Expr<'arena, 'src>,
235    pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
236    pub span: Span,
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub doc_comment: Option<Comment<'src>>,
239}
240
241#[derive(Debug, Serialize)]
242pub struct StaticVar<'arena, 'src> {
243    pub name: Ident<'src>,
244    pub default: Option<Expr<'arena, 'src>>,
245    pub span: Span,
246}