mago_ast/ast/
statement.rs

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/// Represents a PHP statement.
56#[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}