mago_syntax_core/ast/
mod.rs1use std::slice::Iter;
4
5use bumpalo::Bump;
6use bumpalo::collections::Vec as BVec;
7use bumpalo::collections::vec::IntoIter;
8use serde::Serialize;
9
10use mago_span::HasPosition;
11use mago_span::HasSpan;
12use mago_span::Span;
13
14#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
16#[repr(transparent)]
17pub struct Sequence<'arena, T> {
18 pub nodes: BVec<'arena, T>,
19}
20
21impl<'arena, T> Sequence<'arena, T> {
22 #[inline]
23 #[must_use]
24 pub const fn new(inner: BVec<'arena, T>) -> Self {
25 Self { nodes: inner }
26 }
27
28 #[inline]
29 pub fn empty(arena: &'arena Bump) -> Self {
30 Self { nodes: BVec::new_in(arena) }
31 }
32
33 #[inline]
34 #[must_use]
35 pub fn len(&self) -> usize {
36 self.nodes.len()
37 }
38
39 #[inline]
40 #[must_use]
41 pub fn is_empty(&self) -> bool {
42 self.nodes.is_empty()
43 }
44
45 #[inline]
46 #[must_use]
47 pub fn get(&self, index: usize) -> Option<&T> {
48 self.nodes.get(index)
49 }
50
51 #[inline]
52 #[must_use]
53 pub fn first(&self) -> Option<&T> {
54 self.nodes.first()
55 }
56
57 #[inline]
58 #[must_use]
59 pub fn last(&self) -> Option<&T> {
60 self.nodes.last()
61 }
62
63 #[inline]
64 pub fn iter(&self) -> Iter<'_, T> {
65 self.nodes.iter()
66 }
67
68 #[inline]
69 #[must_use]
70 pub fn as_slice(&self) -> &[T] {
71 self.nodes.as_slice()
72 }
73}
74
75impl<T: HasSpan> Sequence<'_, T> {
76 #[inline]
77 #[must_use]
78 pub fn first_span(&self) -> Option<Span> {
79 self.nodes.first().map(HasSpan::span)
80 }
81
82 #[inline]
83 #[must_use]
84 pub fn last_span(&self) -> Option<Span> {
85 self.nodes.last().map(HasSpan::span)
86 }
87
88 #[inline]
92 #[must_use]
93 pub fn span(&self, file_id: mago_database::file::FileId, from: mago_span::Position) -> Span {
94 self.last_span().map_or(Span::new(file_id, from, from), |span| Span::new(file_id, from, span.end))
95 }
96}
97
98impl<T> std::ops::Index<usize> for Sequence<'_, T> {
99 type Output = T;
100
101 #[inline]
102 fn index(&self, index: usize) -> &T {
103 &self.nodes[index]
104 }
105}
106
107impl<T, Tok> std::ops::Index<usize> for TokenSeparatedSequence<'_, T, Tok> {
108 type Output = T;
109
110 #[inline]
111 fn index(&self, index: usize) -> &T {
112 &self.nodes[index]
113 }
114}
115
116impl<'arena, T> IntoIterator for Sequence<'arena, T> {
117 type Item = T;
118 type IntoIter = IntoIter<'arena, Self::Item>;
119
120 fn into_iter(self) -> Self::IntoIter {
121 self.nodes.into_iter()
122 }
123}
124
125impl<'seq, T> IntoIterator for &'seq Sequence<'_, T> {
126 type Item = &'seq T;
127 type IntoIter = Iter<'seq, T>;
128
129 fn into_iter(self) -> Self::IntoIter {
130 self.iter()
131 }
132}
133
134#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
145pub struct TokenSeparatedSequence<'arena, T, Tok> {
146 pub nodes: BVec<'arena, T>,
147 pub tokens: BVec<'arena, Tok>,
148}
149
150impl<'arena, T, Tok> TokenSeparatedSequence<'arena, T, Tok> {
151 #[inline]
152 #[must_use]
153 pub const fn new(nodes: BVec<'arena, T>, tokens: BVec<'arena, Tok>) -> Self {
154 Self { nodes, tokens }
155 }
156
157 #[inline]
158 pub fn empty(arena: &'arena Bump) -> Self {
159 Self { nodes: BVec::new_in(arena), tokens: BVec::new_in(arena) }
160 }
161
162 #[inline]
163 #[must_use]
164 pub fn len(&self) -> usize {
165 self.nodes.len()
166 }
167
168 #[inline]
169 #[must_use]
170 pub fn is_empty(&self) -> bool {
171 self.nodes.is_empty()
172 }
173
174 #[inline]
175 #[must_use]
176 pub fn get(&self, index: usize) -> Option<&T> {
177 self.nodes.get(index)
178 }
179
180 #[inline]
181 #[must_use]
182 pub fn first(&self) -> Option<&T> {
183 self.nodes.first()
184 }
185
186 #[inline]
187 #[must_use]
188 pub fn last(&self) -> Option<&T> {
189 self.nodes.last()
190 }
191
192 #[inline]
193 pub fn iter(&self) -> Iter<'_, T> {
194 self.nodes.iter()
195 }
196
197 #[inline]
198 #[must_use]
199 pub fn as_slice(&self) -> &[T] {
200 self.nodes.as_slice()
201 }
202
203 #[inline]
208 pub fn iter_with_tokens(&self) -> impl Iterator<Item = (usize, &T, Option<&Tok>)> {
209 self.nodes.iter().enumerate().map(move |(i, item)| (i, item, self.tokens.get(i)))
210 }
211}
212
213impl<T, Tok> TokenSeparatedSequence<'_, T, Tok>
214where
215 T: HasSpan,
216 Tok: HasPosition,
217{
218 #[inline]
220 #[must_use]
221 pub fn has_trailing_token(&self) -> bool {
222 self.tokens.last().is_some_and(|t| t.offset() >= self.nodes.last().map_or(0, |n| n.span().end.offset))
223 }
224
225 #[inline]
227 #[must_use]
228 pub fn get_trailing_token(&self) -> Option<&Tok> {
229 self.tokens.last().filter(|t| t.offset() >= self.nodes.last().map_or(0, |n| n.span().end.offset))
230 }
231}
232
233impl<'arena, T, Tok> IntoIterator for TokenSeparatedSequence<'arena, T, Tok> {
234 type Item = T;
235 type IntoIter = IntoIter<'arena, Self::Item>;
236
237 fn into_iter(self) -> Self::IntoIter {
238 self.nodes.into_iter()
239 }
240}
241
242impl<'seq, T, Tok> IntoIterator for &'seq TokenSeparatedSequence<'_, T, Tok> {
243 type Item = &'seq T;
244 type IntoIter = Iter<'seq, T>;
245
246 fn into_iter(self) -> Self::IntoIter {
247 self.iter()
248 }
249}