mago_syntax/ast/ast/control_flow/
switch.rs1use serde::Deserialize;
2use serde::Serialize;
3use strum::Display;
4
5use mago_span::HasSpan;
6use mago_span::Span;
7
8use crate::ast::ast::expression::Expression;
9use crate::ast::ast::keyword::Keyword;
10use crate::ast::ast::statement::Statement;
11use crate::ast::ast::terminator::Terminator;
12use crate::ast::sequence::Sequence;
13
14#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
16#[repr(C)]
17pub struct Switch {
18 pub switch: Keyword,
19 pub left_parenthesis: Span,
20 pub expression: Box<Expression>,
21 pub right_parenthesis: Span,
22 pub body: SwitchBody,
23}
24
25#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
27#[serde(tag = "type", content = "value")]
28#[repr(C, u8)]
29pub enum SwitchBody {
30 BraceDelimited(SwitchBraceDelimitedBody),
31 ColonDelimited(SwitchColonDelimitedBody),
32}
33
34#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
36#[repr(C)]
37pub struct SwitchBraceDelimitedBody {
38 pub left_brace: Span,
39 pub optional_terminator: Option<Terminator>,
40 pub cases: Sequence<SwitchCase>,
41 pub right_brace: Span,
42}
43
44#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
46#[repr(C)]
47pub struct SwitchColonDelimitedBody {
48 pub colon: Span,
49 pub optional_terminator: Option<Terminator>,
50 pub cases: Sequence<SwitchCase>,
51 pub end_switch: Keyword,
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 SwitchCase {
60 Expression(SwitchExpressionCase),
61 Default(SwitchDefaultCase),
62}
63
64#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
68#[repr(C)]
69pub struct SwitchExpressionCase {
70 pub case: Keyword,
71 pub expression: Box<Expression>,
72 pub separator: SwitchCaseSeparator,
73 pub statements: Sequence<Statement>,
74}
75
76#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
80#[repr(C)]
81pub struct SwitchDefaultCase {
82 pub default: Keyword,
83 pub separator: SwitchCaseSeparator,
84 pub statements: Sequence<Statement>,
85}
86
87#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
89#[serde(tag = "type", content = "value")]
90#[repr(C, u8)]
91pub enum SwitchCaseSeparator {
92 Colon(Span),
93 SemiColon(Span),
94}
95
96impl SwitchBody {
97 pub fn cases(&self) -> &[SwitchCase] {
98 match self {
99 SwitchBody::BraceDelimited(body) => body.cases.as_slice(),
100 SwitchBody::ColonDelimited(body) => body.cases.as_slice(),
101 }
102 }
103}
104
105impl SwitchCase {
106 pub fn statements(&self) -> &[Statement] {
108 match self {
109 SwitchCase::Expression(case) => case.statements.as_slice(),
110 SwitchCase::Default(case) => case.statements.as_slice(),
111 }
112 }
113
114 pub fn is_default(&self) -> bool {
116 match self {
117 SwitchCase::Expression(_) => false,
118 SwitchCase::Default(_) => true,
119 }
120 }
121
122 pub fn is_empty(&self) -> bool {
124 match self {
125 SwitchCase::Expression(case) => case.statements.is_empty(),
126 SwitchCase::Default(case) => case.statements.is_empty(),
127 }
128 }
129
130 pub fn is_fall_through(&self) -> bool {
135 let Some(last_statement) = self.statements().last() else {
136 return false;
137 };
138
139 !matches!(last_statement, Statement::Break(_))
140 }
141}
142
143impl HasSpan for Switch {
144 fn span(&self) -> Span {
145 Span::between(self.switch.span(), self.body.span())
146 }
147}
148
149impl HasSpan for SwitchBody {
150 fn span(&self) -> Span {
151 match self {
152 SwitchBody::BraceDelimited(body) => body.span(),
153 SwitchBody::ColonDelimited(body) => body.span(),
154 }
155 }
156}
157
158impl HasSpan for SwitchBraceDelimitedBody {
159 fn span(&self) -> Span {
160 Span::between(self.left_brace, self.right_brace)
161 }
162}
163
164impl HasSpan for SwitchColonDelimitedBody {
165 fn span(&self) -> Span {
166 Span::between(self.colon, self.terminator.span())
167 }
168}
169
170impl HasSpan for SwitchCase {
171 fn span(&self) -> Span {
172 match self {
173 SwitchCase::Expression(case) => case.span(),
174 SwitchCase::Default(case) => case.span(),
175 }
176 }
177}
178
179impl HasSpan for SwitchExpressionCase {
180 fn span(&self) -> Span {
181 Span::between(
182 self.case.span(),
183 self.statements.last().map(|statement| statement.span()).unwrap_or(self.separator.span()),
184 )
185 }
186}
187
188impl HasSpan for SwitchDefaultCase {
189 fn span(&self) -> Span {
190 Span::between(
191 self.default.span(),
192 self.statements.last().map(|statement| statement.span()).unwrap_or(self.separator.span()),
193 )
194 }
195}
196
197impl HasSpan for SwitchCaseSeparator {
198 fn span(&self) -> Span {
199 match self {
200 SwitchCaseSeparator::Colon(span) => *span,
201 SwitchCaseSeparator::SemiColon(span) => *span,
202 }
203 }
204}