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