mago_ast/ast/loop/
foreach.rs

1use serde::Deserialize;
2use serde::Serialize;
3use strum::Display;
4
5use mago_span::HasSpan;
6use mago_span::Span;
7
8use crate::ast::expression::Expression;
9use crate::ast::keyword::Keyword;
10use crate::ast::statement::Statement;
11use crate::ast::terminator::Terminator;
12use crate::sequence::Sequence;
13
14/// Represents a foreach statement in PHP.
15///
16/// Example:
17///
18/// ```php
19/// <?php
20///
21/// foreach ($array as $value) {
22///    echo $value;
23/// }
24/// ```
25#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
26#[repr(C)]
27pub struct Foreach {
28    pub foreach: Keyword,
29    pub left_parenthesis: Span,
30    pub expression: Box<Expression>,
31    pub r#as: Keyword,
32    pub target: ForeachTarget,
33    pub right_parenthesis: Span,
34    pub body: ForeachBody,
35}
36
37/// Represents the target of a foreach statement.
38#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
39#[serde(tag = "type", content = "value")]
40#[repr(C, u8)]
41pub enum ForeachTarget {
42    Value(ForeachValueTarget),
43    KeyValue(ForeachKeyValueTarget),
44}
45
46/// Represents the target of a foreach statement that only assigns the value.
47///
48/// Example:
49///
50/// ```php
51/// <?php
52///
53/// foreach ($array as $value) {
54///   echo $value;
55/// }
56/// ```
57#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
58#[repr(C)]
59pub struct ForeachValueTarget {
60    pub value: Box<Expression>,
61}
62
63/// Represents the target of a foreach statement that assigns both the key and value.
64///
65/// Example:
66///
67/// ```php
68/// <?php
69///
70/// foreach ($array as $key => $value) {
71///   echo $key . ' => ' . $value . PHP_EOL;
72/// }
73/// ```
74#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
75#[repr(C)]
76pub struct ForeachKeyValueTarget {
77    pub key: Box<Expression>,
78    pub double_arrow: Span,
79    pub value: Box<Expression>,
80}
81
82/// Represents the body of a foreach statement.
83#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
84#[serde(tag = "type", content = "value")]
85#[repr(C, u8)]
86pub enum ForeachBody {
87    /// The body is a statement.
88    Statement(Box<Statement>),
89    /// The body is a colon-delimited body.
90    ColonDelimited(ForeachColonDelimitedBody),
91}
92
93/// Represents a colon-delimited body of a foreach statement.
94///
95/// Example:
96///
97/// ```php
98/// <?php
99///
100/// foreach ($array as $value):
101///   echo $value;
102/// endforeach;
103/// ```
104#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
105#[repr(C)]
106pub struct ForeachColonDelimitedBody {
107    pub colon: Span,
108    pub statements: Sequence<Statement>,
109    pub end_foreach: Keyword,
110    pub terminator: Terminator,
111}
112
113impl HasSpan for Foreach {
114    fn span(&self) -> Span {
115        self.foreach.span().join(self.body.span())
116    }
117}
118
119impl HasSpan for ForeachTarget {
120    fn span(&self) -> Span {
121        match self {
122            ForeachTarget::Value(value) => value.span(),
123            ForeachTarget::KeyValue(key_value) => key_value.span(),
124        }
125    }
126}
127
128impl HasSpan for ForeachValueTarget {
129    fn span(&self) -> Span {
130        self.value.span()
131    }
132}
133
134impl HasSpan for ForeachKeyValueTarget {
135    fn span(&self) -> Span {
136        self.key.span().join(self.value.span())
137    }
138}
139
140impl HasSpan for ForeachBody {
141    fn span(&self) -> Span {
142        match self {
143            ForeachBody::Statement(statement) => statement.span(),
144            ForeachBody::ColonDelimited(body) => body.span(),
145        }
146    }
147}
148
149impl HasSpan for ForeachColonDelimitedBody {
150    fn span(&self) -> Span {
151        self.colon.join(self.terminator.span())
152    }
153}