1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::ast::argument::ArgumentList;
8use crate::ast::ast::expression::Expression;
9use crate::ast::ast::keyword::Keyword;
10use crate::ast::sequence::TokenSeparatedSequence;
11
12#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
13#[serde(tag = "type", content = "value")]
14#[repr(u8)]
15pub enum Construct<'arena> {
16 Isset(IssetConstruct<'arena>),
17 Empty(EmptyConstruct<'arena>),
18 Eval(EvalConstruct<'arena>),
19 Include(IncludeConstruct<'arena>),
20 IncludeOnce(IncludeOnceConstruct<'arena>),
21 Require(RequireConstruct<'arena>),
22 RequireOnce(RequireOnceConstruct<'arena>),
23 Print(PrintConstruct<'arena>),
24 Exit(ExitConstruct<'arena>),
25 Die(DieConstruct<'arena>),
26}
27
28#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
29pub struct IssetConstruct<'arena> {
30 pub isset: Keyword<'arena>,
31 pub left_parenthesis: Span,
32 pub values: TokenSeparatedSequence<'arena, Expression<'arena>>,
33 pub right_parenthesis: Span,
34}
35
36#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
37pub struct EmptyConstruct<'arena> {
38 pub empty: Keyword<'arena>,
39 pub left_parenthesis: Span,
40 pub value: &'arena Expression<'arena>,
41 pub right_parenthesis: Span,
42}
43
44#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
45pub struct EvalConstruct<'arena> {
46 pub eval: Keyword<'arena>,
47 pub left_parenthesis: Span,
48 pub value: &'arena Expression<'arena>,
49 pub right_parenthesis: Span,
50}
51
52#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
53pub struct IncludeConstruct<'arena> {
54 pub include: Keyword<'arena>,
55 pub value: &'arena Expression<'arena>,
56}
57
58#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
59pub struct IncludeOnceConstruct<'arena> {
60 pub include_once: Keyword<'arena>,
61 pub value: &'arena Expression<'arena>,
62}
63
64#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
65pub struct RequireConstruct<'arena> {
66 pub require: Keyword<'arena>,
67 pub value: &'arena Expression<'arena>,
68}
69
70#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
71pub struct RequireOnceConstruct<'arena> {
72 pub require_once: Keyword<'arena>,
73 pub value: &'arena Expression<'arena>,
74}
75
76#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
77pub struct PrintConstruct<'arena> {
78 pub print: Keyword<'arena>,
79 pub value: &'arena Expression<'arena>,
80}
81
82#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
83pub struct ExitConstruct<'arena> {
84 pub exit: Keyword<'arena>,
85 pub arguments: Option<ArgumentList<'arena>>,
86}
87
88#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
89pub struct DieConstruct<'arena> {
90 pub die: Keyword<'arena>,
91 pub arguments: Option<ArgumentList<'arena>>,
92}
93
94impl<'arena> Construct<'arena> {
95 #[must_use]
96 #[inline]
97 pub const fn is_import(&self) -> bool {
98 matches!(
99 self,
100 Construct::Include(_) | Construct::IncludeOnce(_) | Construct::Require(_) | Construct::RequireOnce(_)
101 )
102 }
103
104 #[must_use]
105 #[inline]
106 pub const fn has_bounds(&self) -> bool {
107 !matches!(
108 self,
109 Construct::Include(_)
110 | Construct::IncludeOnce(_)
111 | Construct::Require(_)
112 | Construct::RequireOnce(_)
113 | Construct::Print(_)
114 )
115 }
116}
117
118impl HasSpan for Construct<'_> {
119 fn span(&self) -> Span {
120 match self {
121 Construct::Isset(c) => c.span(),
122 Construct::Empty(c) => c.span(),
123 Construct::Eval(c) => c.span(),
124 Construct::Include(c) => c.span(),
125 Construct::IncludeOnce(c) => c.span(),
126 Construct::Require(c) => c.span(),
127 Construct::RequireOnce(c) => c.span(),
128 Construct::Print(c) => c.span(),
129 Construct::Exit(c) => c.span(),
130 Construct::Die(c) => c.span(),
131 }
132 }
133}
134
135impl HasSpan for IssetConstruct<'_> {
136 fn span(&self) -> Span {
137 self.isset.span().join(self.right_parenthesis.span())
138 }
139}
140
141impl HasSpan for EmptyConstruct<'_> {
142 fn span(&self) -> Span {
143 self.empty.span().join(self.right_parenthesis)
144 }
145}
146
147impl HasSpan for EvalConstruct<'_> {
148 fn span(&self) -> Span {
149 self.eval.span().join(self.right_parenthesis)
150 }
151}
152
153impl HasSpan for IncludeConstruct<'_> {
154 fn span(&self) -> Span {
155 self.include.span().join(self.value.span())
156 }
157}
158
159impl HasSpan for IncludeOnceConstruct<'_> {
160 fn span(&self) -> Span {
161 self.include_once.span().join(self.value.span())
162 }
163}
164
165impl HasSpan for RequireConstruct<'_> {
166 fn span(&self) -> Span {
167 self.require.span().join(self.value.span())
168 }
169}
170
171impl HasSpan for RequireOnceConstruct<'_> {
172 fn span(&self) -> Span {
173 self.require_once.span().join(self.value.span())
174 }
175}
176
177impl HasSpan for PrintConstruct<'_> {
178 fn span(&self) -> Span {
179 self.print.span().join(self.value.span())
180 }
181}
182
183impl HasSpan for ExitConstruct<'_> {
184 fn span(&self) -> Span {
185 if let Some(arguments) = &self.arguments { self.exit.span().join(arguments.span()) } else { self.exit.span() }
186 }
187}
188
189impl HasSpan for DieConstruct<'_> {
190 fn span(&self) -> Span {
191 if let Some(arguments) = &self.arguments { self.die.span().join(arguments.span()) } else { self.die.span() }
192 }
193}