mago_syntax/ast/
sequence.rs1use std::slice::Iter;
2
3use bumpalo::Bump;
4use bumpalo::collections::Vec;
5use bumpalo::collections::vec::IntoIter;
6use bumpalo::vec;
7use mago_database::file::FileId;
8use serde::Serialize;
9
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 pub const fn new(inner: Vec<'arena, T>) -> Self {
41 Self { nodes: inner }
42 }
43
44 #[inline]
45 pub fn empty(arena: &'arena Bump) -> Self {
46 Self { nodes: vec![in arena] }
47 }
48
49 #[inline]
50 pub fn len(&self) -> usize {
51 self.nodes.len()
52 }
53
54 #[inline]
55 pub fn is_empty(&self) -> bool {
56 self.nodes.is_empty()
57 }
58
59 #[inline]
60 #[must_use]
61 pub fn get(&self, index: usize) -> Option<&T> {
62 self.nodes.get(index)
63 }
64
65 #[inline]
66 #[must_use]
67 pub fn first(&self) -> Option<&T> {
68 self.nodes.first()
69 }
70
71 #[inline]
72 #[must_use]
73 pub fn first_span(&self) -> Option<Span> {
74 self.nodes.first().map(|node| node.span())
75 }
76
77 #[inline]
78 #[must_use]
79 pub fn last(&self) -> Option<&T> {
80 self.nodes.last()
81 }
82
83 #[inline]
84 #[must_use]
85 pub fn last_span(&self) -> Option<Span> {
86 self.nodes.last().map(|node| node.span())
87 }
88
89 #[inline]
90 #[must_use]
91 pub fn span(&self, file_id: FileId, from: Position) -> Span {
92 self.last_span().map_or(Span::new(file_id, from, from), |span| Span::new(file_id, from, span.end))
93 }
94
95 #[inline]
96 pub fn iter(&self) -> Iter<'_, T> {
97 self.nodes.iter()
98 }
99
100 #[inline]
101 #[must_use]
102 pub fn as_slice(&self) -> &[T] {
103 self.nodes.as_slice()
104 }
105}
106
107impl<'arena, T: HasSpan> TokenSeparatedSequence<'arena, T> {
108 #[inline]
109 #[must_use]
110 pub const fn new(inner: Vec<'arena, T>, tokens: Vec<'arena, Token>) -> Self {
111 Self { nodes: inner, tokens }
112 }
113
114 #[inline]
115 #[must_use]
116 pub fn empty(arena: &'arena Bump) -> Self {
117 Self { nodes: vec![in arena], tokens: vec![in arena] }
118 }
119
120 #[inline]
121 pub fn len(&self) -> usize {
122 self.nodes.len()
123 }
124
125 #[inline]
126 pub fn is_empty(&self) -> bool {
127 self.nodes.is_empty()
128 }
129
130 #[inline]
131 pub fn get(&self, index: usize) -> Option<&T> {
132 self.nodes.get(index)
133 }
134
135 #[inline]
136 #[must_use]
137 pub fn first(&self) -> Option<&T> {
138 self.nodes.first()
139 }
140
141 #[inline]
142 pub fn first_span(&self) -> Option<Span> {
143 match (self.tokens.first(), self.nodes.first()) {
144 (Some(token), Some(node)) => {
145 if token.span.end <= node.span().start { Some(token.span) } else { Some(node.span()) }
147 }
148 (Some(token), None) => Some(token.span),
149 (None, Some(node)) => Some(node.span()),
150 (None, None) => None,
151 }
152 }
153
154 #[inline]
155 pub fn last(&self) -> Option<&T> {
156 self.nodes.last()
157 }
158
159 #[inline]
160 pub fn last_span(&self) -> Option<Span> {
161 match (self.tokens.last(), self.nodes.last()) {
162 (Some(token), Some(node)) => {
163 if token.span.start >= node.span().end { Some(token.span) } else { Some(node.span()) }
165 }
166 (Some(token), None) => Some(token.span),
167 (None, Some(node)) => Some(node.span()),
168 (None, None) => None,
169 }
170 }
171
172 #[inline]
173 pub fn span(&self, file_id: FileId, from: Position) -> Span {
174 match (self.first_span(), self.last_span()) {
175 (Some(first), Some(last)) => Span::new(file_id, first.start, last.end),
176 _ => Span::new(file_id, from, from),
177 }
178 }
179
180 #[inline]
181 pub fn has_trailing_token(&self) -> bool {
182 self.tokens
183 .last()
184 .is_some_and(|token| token.span.start.offset >= self.nodes.last().map_or(0, |node| node.span().end.offset))
185 }
186
187 #[inline]
188 pub fn get_trailing_token(&self) -> Option<&Token<'arena>> {
189 self.tokens
190 .last()
191 .filter(|token| token.span.start.offset >= self.nodes.last().map_or(0, |node| node.span().end.offset))
192 }
193
194 #[inline]
195 pub fn iter<'ast>(&'ast self) -> Iter<'ast, T> {
196 self.nodes.iter()
197 }
198
199 #[inline]
203 pub fn iter_with_tokens(&self) -> impl Iterator<Item = (usize, &T, Option<&Token<'arena>>)> {
204 self.nodes.iter().enumerate().map(move |(i, item)| {
205 let token = self.tokens.get(i);
206
207 (i, item, token)
208 })
209 }
210
211 #[inline]
212 pub fn as_slice(&self) -> &[T] {
213 self.nodes.as_slice()
214 }
215}
216
217impl<'arena, T: HasSpan> IntoIterator for Sequence<'arena, T> {
218 type Item = T;
219 type IntoIter = IntoIter<'arena, Self::Item>;
220
221 fn into_iter(self) -> Self::IntoIter {
222 self.nodes.into_iter()
223 }
224}
225
226impl<'arena, T: HasSpan> IntoIterator for TokenSeparatedSequence<'arena, T> {
227 type Item = T;
228 type IntoIter = IntoIter<'arena, Self::Item>;
229
230 fn into_iter(self) -> Self::IntoIter {
231 self.nodes.into_iter()
232 }
233}