mago_syntax/ast/ast/loop/
foreach.rs1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::ast::expression::Expression;
8use crate::ast::ast::keyword::Keyword;
9use crate::ast::ast::statement::Statement;
10use crate::ast::ast::terminator::Terminator;
11use crate::ast::sequence::Sequence;
12
13#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
25pub struct Foreach<'arena> {
26 pub foreach: Keyword<'arena>,
27 pub left_parenthesis: Span,
28 pub expression: &'arena Expression<'arena>,
29 pub r#as: Keyword<'arena>,
30 pub target: ForeachTarget<'arena>,
31 pub right_parenthesis: Span,
32 pub body: ForeachBody<'arena>,
33}
34
35#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
37#[serde(tag = "type", content = "value")]
38pub enum ForeachTarget<'arena> {
39 Value(ForeachValueTarget<'arena>),
40 KeyValue(ForeachKeyValueTarget<'arena>),
41}
42
43#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
55pub struct ForeachValueTarget<'arena> {
56 pub value: &'arena Expression<'arena>,
57}
58
59#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
71pub struct ForeachKeyValueTarget<'arena> {
72 pub key: &'arena Expression<'arena>,
73 pub double_arrow: Span,
74 pub value: &'arena Expression<'arena>,
75}
76
77#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
79#[serde(tag = "type", content = "value")]
80pub enum ForeachBody<'arena> {
81 Statement(&'arena Statement<'arena>),
83 ColonDelimited(ForeachColonDelimitedBody<'arena>),
85}
86
87#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
99pub struct ForeachColonDelimitedBody<'arena> {
100 pub colon: Span,
101 pub statements: Sequence<'arena, Statement<'arena>>,
102 pub end_foreach: Keyword<'arena>,
103 pub terminator: Terminator<'arena>,
104}
105
106impl<'arena> ForeachTarget<'arena> {
107 #[must_use]
108 pub fn key(&self) -> Option<&Expression<'arena>> {
109 match self {
110 ForeachTarget::Value(_) => None,
111 ForeachTarget::KeyValue(key_value) => Some(key_value.key),
112 }
113 }
114
115 #[must_use]
116 pub fn value(&self) -> &Expression<'arena> {
117 match self {
118 ForeachTarget::Value(value) => value.value,
119 ForeachTarget::KeyValue(key_value) => key_value.value,
120 }
121 }
122}
123
124impl<'arena> ForeachBody<'arena> {
125 #[must_use]
126 pub fn statements(&self) -> &[Statement<'arena>] {
127 match self {
128 ForeachBody::Statement(statement) => std::slice::from_ref(statement),
129 ForeachBody::ColonDelimited(body) => body.statements.as_slice(),
130 }
131 }
132}
133
134impl HasSpan for Foreach<'_> {
135 fn span(&self) -> Span {
136 self.foreach.span().join(self.body.span())
137 }
138}
139
140impl HasSpan for ForeachTarget<'_> {
141 fn span(&self) -> Span {
142 match self {
143 ForeachTarget::Value(value) => value.span(),
144 ForeachTarget::KeyValue(key_value) => key_value.span(),
145 }
146 }
147}
148
149impl HasSpan for ForeachValueTarget<'_> {
150 fn span(&self) -> Span {
151 self.value.span()
152 }
153}
154
155impl HasSpan for ForeachKeyValueTarget<'_> {
156 fn span(&self) -> Span {
157 self.key.span().join(self.value.span())
158 }
159}
160
161impl HasSpan for ForeachBody<'_> {
162 fn span(&self) -> Span {
163 match self {
164 ForeachBody::Statement(statement) => statement.span(),
165 ForeachBody::ColonDelimited(body) => body.span(),
166 }
167 }
168}
169
170impl HasSpan for ForeachColonDelimitedBody<'_> {
171 fn span(&self) -> Span {
172 self.colon.join(self.terminator.span())
173 }
174}