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
10fn is_false(b: &bool) -> bool {
11 !b
12}
13
14#[derive(Debug, Serialize)]
15pub struct Stmt<'arena, 'src> {
16 pub kind: StmtKind<'arena, 'src>,
17 pub span: Span,
18 #[serde(skip_serializing_if = "Option::is_none")]
35 pub doc_comment: Option<&'arena Comment<'src>>,
36}
37
38impl<'arena, 'src> Stmt<'arena, 'src> {
39 pub fn leading_doc_comment(&self) -> Option<&Comment<'src>> {
60 if let Some(doc) = self.doc_comment {
61 return Some(doc);
62 }
63 match &self.kind {
64 StmtKind::Function(f) => f.doc_comment.as_ref(),
65 StmtKind::Class(c) => c.doc_comment.as_ref(),
66 StmtKind::Interface(i) => i.doc_comment.as_ref(),
67 StmtKind::Trait(t) => t.doc_comment.as_ref(),
68 StmtKind::Enum(e) => e.doc_comment.as_ref(),
69 StmtKind::Const(items) => items.first().and_then(|i| i.doc_comment.as_ref()),
70 _ => None,
71 }
72 }
73}
74
75#[derive(Debug, Serialize)]
81#[serde(transparent)]
82pub struct Block<'arena, 'src> {
83 pub stmts: ArenaVec<'arena, Stmt<'arena, 'src>>,
84 #[serde(skip)]
87 pub span: Span,
88}
89
90#[derive(Debug, Serialize)]
91pub enum StmtKind<'arena, 'src> {
92 Expression(&'arena Expr<'arena, 'src>),
94
95 Echo(ArenaVec<'arena, Expr<'arena, 'src>>),
97
98 Return(Option<&'arena Expr<'arena, 'src>>),
100
101 Block(&'arena Block<'arena, 'src>),
103
104 If(&'arena IfStmt<'arena, 'src>),
106
107 While(&'arena WhileStmt<'arena, 'src>),
109
110 For(&'arena ForStmt<'arena, 'src>),
112
113 Foreach(&'arena ForeachStmt<'arena, 'src>),
115
116 DoWhile(&'arena DoWhileStmt<'arena, 'src>),
118
119 Function(&'arena FunctionDecl<'arena, 'src>),
121
122 Break(Option<&'arena Expr<'arena, 'src>>),
124
125 Continue(Option<&'arena Expr<'arena, 'src>>),
127
128 Switch(&'arena SwitchStmt<'arena, 'src>),
130
131 Goto(Ident<'src>),
133
134 Label(&'arena str),
136
137 Declare(&'arena DeclareStmt<'arena, 'src>),
139
140 Unset(ArenaVec<'arena, Expr<'arena, 'src>>),
142
143 Throw(&'arena Expr<'arena, 'src>),
145
146 TryCatch(&'arena TryCatchStmt<'arena, 'src>),
148
149 Global(ArenaVec<'arena, Expr<'arena, 'src>>),
151
152 Class(&'arena ClassDecl<'arena, 'src>),
154
155 Interface(&'arena InterfaceDecl<'arena, 'src>),
157
158 Trait(&'arena TraitDecl<'arena, 'src>),
160
161 Enum(&'arena EnumDecl<'arena, 'src>),
163
164 Namespace(&'arena NamespaceDecl<'arena, 'src>),
166
167 Use(&'arena UseDecl<'arena, 'src>),
169
170 Const(ArenaVec<'arena, ConstItem<'arena, 'src>>),
172
173 StaticVar(ArenaVec<'arena, StaticVar<'arena, 'src>>),
175
176 HaltCompiler(&'src str),
178
179 Nop,
181
182 InlineHtml(&'src str),
184
185 Error,
187}
188
189#[derive(Debug, Serialize)]
190pub struct IfStmt<'arena, 'src> {
191 pub condition: Expr<'arena, 'src>,
192 pub then_branch: &'arena Stmt<'arena, 'src>,
193 pub elseif_branches: ArenaVec<'arena, ElseIfBranch<'arena, 'src>>,
194 pub else_branch: Option<&'arena Stmt<'arena, 'src>>,
195 #[serde(skip)]
197 pub else_kw_start: Option<u32>,
198 #[serde(default, skip_serializing_if = "is_false")]
199 pub uses_alternative: bool,
200}
201
202#[derive(Debug, Serialize)]
203pub struct ElseIfBranch<'arena, 'src> {
204 pub condition: Expr<'arena, 'src>,
205 pub body: Stmt<'arena, 'src>,
206 pub span: Span,
207}
208
209#[derive(Debug, Serialize)]
210pub struct WhileStmt<'arena, 'src> {
211 pub condition: Expr<'arena, 'src>,
212 pub body: &'arena Stmt<'arena, 'src>,
213 #[serde(default, skip_serializing_if = "is_false")]
214 pub uses_alternative: bool,
215}
216
217#[derive(Debug, Serialize)]
218pub struct ForStmt<'arena, 'src> {
219 pub init: ArenaVec<'arena, Expr<'arena, 'src>>,
220 pub condition: ArenaVec<'arena, Expr<'arena, 'src>>,
221 pub update: ArenaVec<'arena, Expr<'arena, 'src>>,
222 pub body: &'arena Stmt<'arena, 'src>,
223 #[serde(default, skip_serializing_if = "is_false")]
224 pub uses_alternative: bool,
225}
226
227#[derive(Debug, Serialize)]
228pub struct ForeachStmt<'arena, 'src> {
229 pub expr: Expr<'arena, 'src>,
230 pub key: Option<Expr<'arena, 'src>>,
231 pub value: Expr<'arena, 'src>,
232 pub body: &'arena Stmt<'arena, 'src>,
233 #[serde(default, skip_serializing_if = "is_false")]
234 pub uses_alternative: bool,
235}
236
237#[derive(Debug, Serialize)]
238pub struct DoWhileStmt<'arena, 'src> {
239 pub body: &'arena Stmt<'arena, 'src>,
240 pub condition: Expr<'arena, 'src>,
241}
242
243#[derive(Debug, Serialize)]
244pub struct SwitchBody<'arena, 'src> {
245 pub cases: ArenaVec<'arena, SwitchCase<'arena, 'src>>,
246 #[serde(skip)]
247 pub span: Span,
248}
249
250#[derive(Debug, Serialize)]
251pub struct SwitchStmt<'arena, 'src> {
252 pub expr: Expr<'arena, 'src>,
253 #[serde(flatten)]
254 pub body: SwitchBody<'arena, 'src>,
255 #[serde(default, skip_serializing_if = "is_false")]
256 pub uses_alternative: bool,
257}
258
259#[derive(Debug, Serialize)]
260pub struct SwitchCase<'arena, 'src> {
261 pub value: Option<Expr<'arena, 'src>>,
262 pub body: ArenaVec<'arena, Stmt<'arena, 'src>>,
263 pub span: Span,
264}
265
266#[derive(Debug, Serialize)]
267pub struct TryCatchStmt<'arena, 'src> {
268 pub body: &'arena Block<'arena, 'src>,
269 pub catches: ArenaVec<'arena, CatchClause<'arena, 'src>>,
270 pub finally: Option<&'arena Block<'arena, 'src>>,
271 #[serde(skip)]
273 pub finally_kw_start: Option<u32>,
274}
275
276#[derive(Debug, Serialize)]
277pub struct CatchClause<'arena, 'src> {
278 pub types: ArenaVec<'arena, Name<'arena, 'src>>,
279 pub var: Option<&'src str>,
280 pub body: &'arena Block<'arena, 'src>,
281 pub span: Span,
282}
283
284#[derive(Debug, Serialize)]
285pub struct NamespaceDecl<'arena, 'src> {
286 pub name: Option<Name<'arena, 'src>>,
287 pub body: NamespaceBody<'arena, 'src>,
288}
289
290#[derive(Debug, Serialize)]
291pub enum NamespaceBody<'arena, 'src> {
292 Braced(&'arena Block<'arena, 'src>),
294 Simple,
296}
297
298#[derive(Debug, Serialize)]
299pub struct DeclareStmt<'arena, 'src> {
300 pub directives: ArenaVec<'arena, (&'src str, Expr<'arena, 'src>)>,
301 pub body: Option<&'arena Stmt<'arena, 'src>>,
302 #[serde(default, skip_serializing_if = "is_false")]
303 pub uses_alternative: bool,
304}
305
306#[derive(Debug, Serialize)]
307pub struct UseDecl<'arena, 'src> {
308 pub kind: UseKind,
309 pub uses: ArenaVec<'arena, UseItem<'arena, 'src>>,
310}
311
312#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
313pub enum UseKind {
314 Normal,
316 Function,
318 Const,
320}
321
322#[derive(Debug, Serialize)]
323pub struct UseItem<'arena, 'src> {
324 pub name: Name<'arena, 'src>,
325 pub alias: Option<&'src str>,
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub kind: Option<UseKind>,
328 pub span: Span,
329}
330
331#[derive(Debug, Serialize)]
332pub struct ConstItem<'arena, 'src> {
333 pub name: Ident<'src>,
334 pub value: Expr<'arena, 'src>,
335 pub attributes: ArenaVec<'arena, Attribute<'arena, 'src>>,
336 pub span: Span,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub doc_comment: Option<Comment<'src>>,
339}
340
341#[derive(Debug, Serialize)]
342pub struct StaticVar<'arena, 'src> {
343 pub name: Ident<'src>,
344 pub default: Option<Expr<'arena, 'src>>,
345 pub span: Span,
346}