mago_syntax/ast/
sequence.rs

1use std::slice::Iter;
2use std::vec::IntoIter;
3
4use serde::Deserialize;
5use serde::Serialize;
6
7use mago_span::HasSpan;
8use mago_span::Position;
9use mago_span::Span;
10
11use crate::token::Token;
12
13/// Represents a sequence of nodes.
14///
15/// An example of this is modifiers in a method declaration.
16///
17/// i.e. `public` and `static` in `public static function foo() {}`.
18#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
19#[repr(transparent)]
20pub struct Sequence<T> {
21    pub nodes: Vec<T>,
22}
23
24/// Represents a sequence of nodes separated by a token.
25///
26/// An example of this is arguments in a function call, where the tokens are commas.
27///
28/// i.e. `1`, `2` and `3` in `foo(1, 2, 3)`.
29#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
30pub struct TokenSeparatedSequence<T> {
31    pub nodes: Vec<T>,
32    pub tokens: Vec<Token>,
33}
34
35impl<T: HasSpan> Sequence<T> {
36    #[inline]
37    pub const fn new(inner: Vec<T>) -> Self {
38        Self { nodes: inner }
39    }
40
41    #[inline]
42    pub const fn empty() -> Self {
43        Self { nodes: vec![] }
44    }
45
46    #[inline]
47    pub fn len(&self) -> usize {
48        self.nodes.len()
49    }
50
51    #[inline]
52    pub fn is_empty(&self) -> bool {
53        self.nodes.is_empty()
54    }
55
56    #[inline]
57    #[must_use]
58    pub fn get(&self, index: usize) -> Option<&T> {
59        self.nodes.get(index)
60    }
61
62    #[inline]
63    #[must_use]
64    pub fn first(&self) -> Option<&T> {
65        self.nodes.first()
66    }
67
68    #[inline]
69    #[must_use]
70    pub fn first_span(&self) -> Option<Span> {
71        self.nodes.first().map(|node| node.span())
72    }
73
74    #[inline]
75    #[must_use]
76    pub fn last(&self) -> Option<&T> {
77        self.nodes.last()
78    }
79
80    #[inline]
81    #[must_use]
82    pub fn last_span(&self) -> Option<Span> {
83        self.nodes.last().map(|node| node.span())
84    }
85
86    #[inline]
87    #[must_use]
88    pub fn span(&self, from: Position) -> Span {
89        self.last_span().map_or(Span::new(from, from), |span| Span::new(from, span.end))
90    }
91
92    #[inline]
93    pub fn iter(&self) -> Iter<'_, T> {
94        self.nodes.iter()
95    }
96
97    #[inline]
98    #[must_use]
99    pub fn as_slice(&self) -> &[T] {
100        self.nodes.as_slice()
101    }
102
103    #[inline]
104    pub fn to_vec(&self) -> Vec<&T> {
105        self.nodes.iter().collect()
106    }
107}
108
109impl<T: HasSpan> TokenSeparatedSequence<T> {
110    #[inline]
111    #[must_use]
112    pub const fn new(inner: Vec<T>, tokens: Vec<Token>) -> Self {
113        Self { nodes: inner, tokens }
114    }
115
116    #[inline]
117    #[must_use]
118    pub const fn empty() -> Self {
119        Self { nodes: vec![], tokens: vec![] }
120    }
121
122    #[inline]
123    pub fn len(&self) -> usize {
124        self.nodes.len()
125    }
126
127    #[inline]
128    pub fn is_empty(&self) -> bool {
129        self.nodes.is_empty()
130    }
131
132    #[inline]
133    pub fn get(&self, index: usize) -> Option<&T> {
134        self.nodes.get(index)
135    }
136
137    #[inline]
138    #[must_use]
139    pub fn first(&self) -> Option<&T> {
140        self.nodes.first()
141    }
142
143    #[inline]
144    pub fn first_span(&self) -> Option<Span> {
145        match (self.tokens.first(), self.nodes.first()) {
146            (Some(token), Some(node)) => {
147                // check if the token comes before the node
148                if token.span.end <= node.span().start { Some(token.span) } else { Some(node.span()) }
149            }
150            (Some(token), None) => Some(token.span),
151            (None, Some(node)) => Some(node.span()),
152            (None, None) => None,
153        }
154    }
155
156    #[inline]
157    pub fn last(&self) -> Option<&T> {
158        self.nodes.last()
159    }
160
161    #[inline]
162    pub fn last_span(&self) -> Option<Span> {
163        match (self.tokens.last(), self.nodes.last()) {
164            (Some(token), Some(node)) => {
165                // check if the token comes after the node
166                if token.span.start >= node.span().end { Some(token.span) } else { Some(node.span()) }
167            }
168            (Some(token), None) => Some(token.span),
169            (None, Some(node)) => Some(node.span()),
170            (None, None) => None,
171        }
172    }
173
174    #[inline]
175    pub fn span(&self, from: Position) -> Span {
176        match (self.first_span(), self.last_span()) {
177            (Some(first), Some(last)) => Span::new(first.start, last.end),
178            _ => Span::new(from, from),
179        }
180    }
181
182    #[inline]
183    pub fn has_trailing_token(&self) -> bool {
184        self.tokens
185            .last()
186            .is_some_and(|token| token.span.start.offset >= self.nodes.last().map_or(0, |node| node.span().end.offset))
187    }
188
189    #[inline]
190    pub fn get_trailing_token(&self) -> Option<&Token> {
191        self.tokens
192            .last()
193            .filter(|token| token.span.start.offset >= self.nodes.last().map_or(0, |node| node.span().end.offset))
194    }
195
196    #[inline]
197    pub fn iter(&self) -> Iter<'_, T> {
198        self.nodes.iter()
199    }
200
201    /// Returns an iterator over the sequence, where each item includes
202    /// the index of the element, the element and the token following it.
203    /// The token is `None` only for the last element if it has no trailing token.
204    #[inline]
205    pub fn iter_with_tokens(&self) -> impl Iterator<Item = (usize, &T, Option<&Token>)> {
206        self.nodes.iter().enumerate().map(move |(i, item)| {
207            let token = self.tokens.get(i);
208
209            (i, item, token)
210        })
211    }
212
213    #[inline]
214    pub fn as_slice(&self) -> &[T] {
215        self.nodes.as_slice()
216    }
217
218    #[inline]
219    pub fn to_vec(&self) -> Vec<&T> {
220        self.nodes.iter().collect()
221    }
222}
223
224impl<T: HasSpan> FromIterator<T> for Sequence<T> {
225    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
226        Self { nodes: iter.into_iter().collect() }
227    }
228}
229
230impl<T: HasSpan> IntoIterator for Sequence<T> {
231    type Item = T;
232    type IntoIter = IntoIter<Self::Item>;
233
234    fn into_iter(self) -> Self::IntoIter {
235        self.nodes.into_iter()
236    }
237}
238
239impl<T: HasSpan> IntoIterator for TokenSeparatedSequence<T> {
240    type Item = T;
241    type IntoIter = IntoIter<Self::Item>;
242
243    fn into_iter(self) -> Self::IntoIter {
244        self.nodes.into_iter()
245    }
246}
247
248impl<T: HasSpan> std::default::Default for Sequence<T> {
249    fn default() -> Self {
250        Sequence::new(Default::default())
251    }
252}
253
254impl<T: HasSpan> std::default::Default for TokenSeparatedSequence<T> {
255    fn default() -> Self {
256        TokenSeparatedSequence::new(Default::default(), Default::default())
257    }
258}