1use serde::Deserialize;
2use serde::Serialize;
3use strum::Display;
4
5use mago_span::HasSpan;
6use mago_span::Span;
7
8use crate::ast::block::Block;
9use crate::ast::class_like::Class;
10use crate::ast::class_like::Enum;
11use crate::ast::class_like::Interface;
12use crate::ast::class_like::Trait;
13use crate::ast::constant::Constant;
14use crate::ast::control_flow::r#if::If;
15use crate::ast::control_flow::switch::Switch;
16use crate::ast::declare::Declare;
17use crate::ast::echo::Echo;
18use crate::ast::expression::Expression;
19use crate::ast::function_like::function::Function;
20use crate::ast::global::Global;
21use crate::ast::goto::Goto;
22use crate::ast::goto::Label;
23use crate::ast::halt_compiler::HaltCompiler;
24use crate::ast::inline::Inline;
25use crate::ast::r#loop::Break;
26use crate::ast::r#loop::Continue;
27use crate::ast::r#loop::do_while::DoWhile;
28use crate::ast::r#loop::r#for::For;
29use crate::ast::r#loop::foreach::Foreach;
30use crate::ast::r#loop::r#while::While;
31use crate::ast::namespace::Namespace;
32use crate::ast::r#return::Return;
33use crate::ast::r#static::Static;
34use crate::ast::tag::ClosingTag;
35use crate::ast::tag::OpeningTag;
36use crate::ast::terminator::Terminator;
37use crate::ast::r#try::Try;
38use crate::ast::unset::Unset;
39use crate::ast::r#use::Use;
40
41use super::DeclareBody;
42use super::ForBody;
43use super::ForeachBody;
44use super::IfBody;
45use super::NamespaceBody;
46use super::WhileBody;
47
48#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
49#[repr(C)]
50pub struct ExpressionStatement {
51 pub expression: Box<Expression>,
52 pub terminator: Terminator,
53}
54
55#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
57#[serde(tag = "type", content = "value")]
58#[repr(C, u8)]
59pub enum Statement {
60 OpeningTag(OpeningTag),
61 ClosingTag(ClosingTag),
62 Inline(Inline),
63 Namespace(Namespace),
64 Use(Use),
65 Class(Class),
66 Interface(Interface),
67 Trait(Trait),
68 Enum(Enum),
69 Block(Block),
70 Constant(Constant),
71 Function(Function),
72 Declare(Declare),
73 Goto(Goto),
74 Label(Label),
75 Try(Try),
76 Foreach(Foreach),
77 For(For),
78 While(While),
79 DoWhile(DoWhile),
80 Continue(Continue),
81 Break(Break),
82 Switch(Switch),
83 If(If),
84 Return(Return),
85 Expression(ExpressionStatement),
86 Echo(Echo),
87 Global(Global),
88 Static(Static),
89 HaltCompiler(HaltCompiler),
90 Unset(Unset),
91 Noop(Span),
92}
93
94impl Statement {
95 #[inline]
96 #[must_use]
97 pub fn terminates_scripting(&self) -> bool {
98 match self {
99 Statement::ClosingTag(_) => true,
100 Statement::Namespace(Namespace { body: NamespaceBody::Implicit(implicit), .. }) => implicit
101 .statements
102 .last()
103 .map_or(implicit.terminator.is_closing_tag(), |statement| statement.terminates_scripting()),
104 Statement::Use(r#use) => r#use.terminator.is_closing_tag(),
105 Statement::Goto(goto) => goto.terminator.is_closing_tag(),
106 Statement::Declare(Declare { body: DeclareBody::Statement(b), .. }) => b.terminates_scripting(),
107 Statement::Declare(Declare { body: DeclareBody::ColonDelimited(b), .. }) => b.terminator.is_closing_tag(),
108 Statement::For(For { body: ForBody::Statement(b), .. }) => b.terminates_scripting(),
109 Statement::For(For { body: ForBody::ColonDelimited(b), .. }) => b.terminator.is_closing_tag(),
110 Statement::Foreach(Foreach { body: ForeachBody::Statement(b), .. }) => b.terminates_scripting(),
111 Statement::Foreach(Foreach { body: ForeachBody::ColonDelimited(b), .. }) => b.terminator.is_closing_tag(),
112 Statement::While(While { body: WhileBody::Statement(b), .. }) => b.terminates_scripting(),
113 Statement::While(While { body: WhileBody::ColonDelimited(b), .. }) => b.terminator.is_closing_tag(),
114 Statement::DoWhile(do_while) => do_while.terminator.is_closing_tag(),
115 Statement::Continue(cont) => cont.terminator.is_closing_tag(),
116 Statement::Break(brk) => brk.terminator.is_closing_tag(),
117 Statement::If(If { body: IfBody::Statement(stmt), .. }) => match &stmt.else_clause {
118 Some(else_clause) => else_clause.statement.terminates_scripting(),
119 None => stmt
120 .else_if_clauses
121 .iter()
122 .last()
123 .map_or(stmt.statement.terminates_scripting(), |clause| clause.statement.terminates_scripting()),
124 },
125 Statement::If(If { body: IfBody::ColonDelimited(body), .. }) => body.terminator.is_closing_tag(),
126 Statement::Return(ret) => ret.terminator.is_closing_tag(),
127 Statement::Expression(expression_statement) => expression_statement.terminator.is_closing_tag(),
128 Statement::Echo(echo) => echo.terminator.is_closing_tag(),
129 Statement::Global(global) => global.terminator.is_closing_tag(),
130 Statement::Static(r#static) => r#static.terminator.is_closing_tag(),
131 Statement::Unset(unset) => unset.terminator.is_closing_tag(),
132 Statement::HaltCompiler(_) => true,
133 _ => false,
134 }
135 }
136}
137
138impl HasSpan for ExpressionStatement {
139 fn span(&self) -> Span {
140 self.expression.span().join(self.terminator.span())
141 }
142}
143
144impl HasSpan for Statement {
145 fn span(&self) -> Span {
146 match self {
147 Statement::OpeningTag(statement) => statement.span(),
148 Statement::ClosingTag(statement) => statement.span(),
149 Statement::Inline(statement) => statement.span(),
150 Statement::Namespace(statement) => statement.span(),
151 Statement::Use(statement) => statement.span(),
152 Statement::Class(statement) => statement.span(),
153 Statement::Interface(statement) => statement.span(),
154 Statement::Trait(statement) => statement.span(),
155 Statement::Enum(statement) => statement.span(),
156 Statement::Block(statement) => statement.span(),
157 Statement::Constant(statement) => statement.span(),
158 Statement::Function(statement) => statement.span(),
159 Statement::Declare(statement) => statement.span(),
160 Statement::Goto(statement) => statement.span(),
161 Statement::Label(statement) => statement.span(),
162 Statement::Try(statement) => statement.span(),
163 Statement::Foreach(statement) => statement.span(),
164 Statement::For(statement) => statement.span(),
165 Statement::While(statement) => statement.span(),
166 Statement::DoWhile(statement) => statement.span(),
167 Statement::Continue(statement) => statement.span(),
168 Statement::Break(statement) => statement.span(),
169 Statement::Switch(statement) => statement.span(),
170 Statement::If(statement) => statement.span(),
171 Statement::Return(statement) => statement.span(),
172 Statement::Expression(statement) => statement.span(),
173 Statement::Echo(statement) => statement.span(),
174 Statement::Global(statement) => statement.span(),
175 Statement::Static(statement) => statement.span(),
176 Statement::Unset(statement) => statement.span(),
177 Statement::HaltCompiler(statement) => statement.span(),
178 Statement::Noop(span) => *span,
179 }
180 }
181}