mago_syntax/ast/
sequence.rs

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