mago_syntax/ast/ast/
array.rs

1use serde::Deserialize;
2use serde::Serialize;
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::sequence::TokenSeparatedSequence;
10
11#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
12#[repr(C)]
13pub struct ArrayAccess {
14    pub array: Box<Expression>,
15    pub left_bracket: Span,
16    pub index: Box<Expression>,
17    pub right_bracket: Span,
18}
19
20#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
21#[repr(C)]
22pub struct ArrayAppend {
23    pub array: Box<Expression>,
24    pub left_bracket: Span,
25    pub right_bracket: Span,
26}
27
28/// Represents a PHP list, defined using `list` keyword and parentheses `()`.
29///
30/// # Example:
31///
32/// ```php
33/// <?php
34///
35/// list($a, 'b' => $c, /* missing */, ...$rest) = $arr;
36/// ```
37#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
38#[repr(C)]
39pub struct List {
40    pub list: Keyword,
41    pub left_parenthesis: Span,
42    pub elements: TokenSeparatedSequence<ArrayElement>,
43    pub right_parenthesis: Span,
44}
45
46/// Represents a standard PHP array, defined using square brackets `[]`.
47///
48/// # Example:
49///
50/// ```php
51/// <?php
52///
53/// $arr = ['apple', 'banana', 3 => 'orange'];
54/// ```
55#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
56#[repr(C)]
57pub struct Array {
58    pub left_bracket: Span,
59    pub elements: TokenSeparatedSequence<ArrayElement>,
60    pub right_bracket: Span,
61}
62
63/// Represents a legacy PHP array, defined using `array` keyword and parentheses `()`.
64///
65/// # Example:
66///
67/// ```php
68/// <?php
69///
70/// $arr = array('apple', 'banana', 3 => 'orange');
71/// ```
72#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
73#[repr(C)]
74pub struct LegacyArray {
75    pub array: Keyword,
76    pub left_parenthesis: Span,
77    pub elements: TokenSeparatedSequence<ArrayElement>,
78    pub right_parenthesis: Span,
79}
80
81/// Represents an array element.
82#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
83#[serde(tag = "type", content = "value")]
84#[repr(C, u8)]
85pub enum ArrayElement {
86    KeyValue(KeyValueArrayElement),
87    Value(ValueArrayElement),
88    Variadic(VariadicArrayElement),
89    Missing(MissingArrayElement),
90}
91
92/// Represents a key-value pair in an array.
93///
94/// # Example:
95///
96/// ```php
97/// <?php
98///
99/// $arr = [
100///   1 => 'orange',
101/// ];
102/// ```
103#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
104#[repr(C)]
105pub struct KeyValueArrayElement {
106    pub key: Box<Expression>,
107    pub double_arrow: Span,
108    pub value: Box<Expression>,
109}
110
111/// Represents a value in an array.
112///
113/// # Example:
114///
115/// ```php
116/// <?php
117///
118/// $arr = [
119///   'orange',
120/// ];
121/// ```
122#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
123#[repr(C)]
124pub struct ValueArrayElement {
125    pub value: Box<Expression>,
126}
127
128/// Represents a variadic array element.
129///
130/// # Example:
131///
132/// ```php
133/// <?php
134///
135/// $arr = [
136///   ...$other,
137/// ];
138/// ```
139#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
140#[repr(C)]
141pub struct VariadicArrayElement {
142    pub ellipsis: Span,
143    pub value: Box<Expression>,
144}
145
146/// Represents a missing array element.
147///
148/// # Example:
149///
150/// ```php
151/// <?php
152///
153/// $arr = [
154///   'first',
155///   ,
156///   'third',
157/// ];
158#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
159#[repr(C)]
160pub struct MissingArrayElement {
161    pub comma: Span,
162}
163
164impl ArrayElement {
165    #[inline]
166    pub const fn is_variadic(&self) -> bool {
167        matches!(self, ArrayElement::Variadic(_))
168    }
169
170    #[inline]
171    pub const fn is_missing(&self) -> bool {
172        matches!(self, ArrayElement::Missing(_))
173    }
174
175    #[inline]
176    pub const fn is_key_value(&self) -> bool {
177        matches!(self, ArrayElement::KeyValue(_))
178    }
179
180    #[inline]
181    pub const fn is_value(&self) -> bool {
182        matches!(self, ArrayElement::Value(_))
183    }
184
185    #[inline]
186    pub fn get_key(&self) -> Option<&Expression> {
187        match self {
188            ArrayElement::KeyValue(element) => Some(&element.key),
189            ArrayElement::Value(_) => None,
190            ArrayElement::Variadic(_) => None,
191            ArrayElement::Missing(_) => None,
192        }
193    }
194
195    #[inline]
196    pub fn get_value(&self) -> Option<&Expression> {
197        match self {
198            ArrayElement::KeyValue(element) => Some(&element.value),
199            ArrayElement::Value(element) => Some(&element.value),
200            ArrayElement::Variadic(element) => Some(&element.value),
201            ArrayElement::Missing(_) => None,
202        }
203    }
204}
205
206impl HasSpan for ArrayAccess {
207    fn span(&self) -> Span {
208        self.array.span().join(self.right_bracket)
209    }
210}
211
212impl HasSpan for ArrayAppend {
213    fn span(&self) -> Span {
214        self.array.span().join(self.right_bracket)
215    }
216}
217
218impl HasSpan for List {
219    fn span(&self) -> Span {
220        self.list.span().join(self.right_parenthesis)
221    }
222}
223
224impl HasSpan for Array {
225    fn span(&self) -> Span {
226        self.left_bracket.join(self.right_bracket)
227    }
228}
229
230impl HasSpan for LegacyArray {
231    fn span(&self) -> Span {
232        self.array.span().join(self.right_parenthesis)
233    }
234}
235
236impl HasSpan for ArrayElement {
237    fn span(&self) -> Span {
238        match self {
239            ArrayElement::KeyValue(element) => element.span(),
240            ArrayElement::Value(element) => element.span(),
241            ArrayElement::Variadic(element) => element.span(),
242            ArrayElement::Missing(element) => element.span(),
243        }
244    }
245}
246
247impl HasSpan for KeyValueArrayElement {
248    fn span(&self) -> Span {
249        self.key.span().join(self.value.span())
250    }
251}
252
253impl HasSpan for ValueArrayElement {
254    fn span(&self) -> Span {
255        self.value.span()
256    }
257}
258
259impl HasSpan for VariadicArrayElement {
260    fn span(&self) -> Span {
261        self.ellipsis.join(self.value.span())
262    }
263}
264
265impl HasSpan for MissingArrayElement {
266    fn span(&self) -> Span {
267        self.comma
268    }
269}