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) -> Option<Span> {
150 match (self.tokens.first(), self.nodes.first()) {
151 (Some(token), Some(node)) => {
152 if token.span.end <= node.span().start { Some(token.span) } else { Some(node.span()) }
154 }
155 (Some(token), None) => Some(token.span),
156 (None, Some(node)) => Some(node.span()),
157 (None, None) => None,
158 }
159 }
160
161 #[inline]
162 #[must_use]
163 pub fn last(&self) -> Option<&T> {
164 self.nodes.last()
165 }
166
167 #[inline]
168 #[must_use]
169 pub fn last_span(&self) -> Option<Span> {
170 match (self.tokens.last(), self.nodes.last()) {
171 (Some(token), Some(node)) => {
172 if token.span.start >= node.span().end { Some(token.span) } else { Some(node.span()) }
174 }
175 (Some(token), None) => Some(token.span),
176 (None, Some(node)) => Some(node.span()),
177 (None, None) => None,
178 }
179 }
180
181 #[inline]
182 #[must_use]
183 pub fn span(&self, file_id: FileId, from: Position) -> Span {
184 match (self.first_span(), self.last_span()) {
185 (Some(first), Some(last)) => Span::new(file_id, first.start, last.end),
186 _ => Span::new(file_id, from, from),
187 }
188 }
189
190 #[inline]
191 #[must_use]
192 pub fn has_trailing_token(&self) -> bool {
193 self.tokens
194 .last()
195 .is_some_and(|token| token.span.start.offset >= self.nodes.last().map_or(0, |node| node.span().end.offset))
196 }
197
198 #[inline]
199 #[must_use]
200 pub fn get_trailing_token(&self) -> Option<&Token<'arena>> {
201 self.tokens
202 .last()
203 .filter(|token| token.span.start.offset >= self.nodes.last().map_or(0, |node| node.span().end.offset))
204 }
205
206 #[inline]
207 pub fn iter(&self) -> Iter<'_, T> {
208 self.nodes.iter()
209 }
210
211 #[inline]
215 pub fn iter_with_tokens(&self) -> impl Iterator<Item = (usize, &T, Option<&Token<'arena>>)> {
216 self.nodes.iter().enumerate().map(move |(i, item)| {
217 let token = self.tokens.get(i);
218
219 (i, item, token)
220 })
221 }
222
223 #[inline]
224 #[must_use]
225 pub fn as_slice(&self) -> &[T] {
226 self.nodes.as_slice()
227 }
228}
229
230impl<'arena, T: HasSpan> IntoIterator for Sequence<'arena, T> {
231 type Item = T;
232 type IntoIter = IntoIter<'arena, Self::Item>;
233
234 fn into_iter(self) -> Self::IntoIter {
235 self.nodes.into_iter()
236 }
237}
238
239impl<'a, T: HasSpan> IntoIterator for &'a Sequence<'_, T> {
240 type Item = &'a T;
241 type IntoIter = Iter<'a, T>;
242
243 fn into_iter(self) -> Self::IntoIter {
244 self.iter()
245 }
246}
247
248impl<'arena, T: HasSpan> IntoIterator for TokenSeparatedSequence<'arena, T> {
249 type Item = T;
250 type IntoIter = IntoIter<'arena, Self::Item>;
251
252 fn into_iter(self) -> Self::IntoIter {
253 self.nodes.into_iter()
254 }
255}
256
257impl<'a, T: HasSpan> IntoIterator for &'a TokenSeparatedSequence<'_, T> {
258 type Item = &'a T;
259 type IntoIter = Iter<'a, T>;
260
261 fn into_iter(self) -> Self::IntoIter {
262 self.iter()
263 }
264}