1use std::{ops::Range, sync::Arc};
2
3use crate::TokenKind;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct TokenSpan {
8 pub start: usize,
10 pub end: usize,
12}
13
14impl TokenSpan {
15 pub const fn new(start: usize, end: usize) -> Self {
17 Self { start, end }
18 }
19
20 pub fn try_new(start: usize, end: usize) -> Result<Self, TokenSpanError> {
22 if end < start {
23 return Err(TokenSpanError::EndBeforeStart { start, end });
24 }
25
26 Ok(Self { start, end })
27 }
28
29 pub const fn len(self) -> usize {
31 self.end.saturating_sub(self.start)
32 }
33
34 pub const fn is_empty(self) -> bool {
36 self.len() == 0
37 }
38
39 pub const fn range(self) -> Range<usize> {
41 self.start..self.end
42 }
43
44 pub const fn contains(self, offset: usize) -> bool {
49 self.start <= offset && offset < self.end
50 }
51
52 pub const fn touches(self, offset: usize) -> bool {
58 self.start <= offset && offset <= self.end
59 }
60
61 pub const fn overlaps(self, other: Self) -> bool {
66 !self.is_empty() && !other.is_empty() && self.start < other.end && other.start < self.end
67 }
68
69 pub const fn cover(self, other: Self) -> Self {
71 Self { start: min_usize(self.start, other.start), end: max_usize(self.end, other.end) }
72 }
73}
74
75const fn min_usize(left: usize, right: usize) -> usize {
76 if left <= right { left } else { right }
77}
78
79const fn max_usize(left: usize, right: usize) -> usize {
80 if left >= right { left } else { right }
81}
82
83#[derive(Debug, Clone, PartialEq, Eq)]
85pub enum TokenSpanError {
86 EndBeforeStart {
88 start: usize,
90 end: usize,
92 },
93 EmptySpanNotAllowed {
95 kind: TokenKind,
97 at: usize,
99 },
100}
101
102impl std::fmt::Display for TokenSpanError {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 match self {
105 Self::EndBeforeStart { start, end } => {
106 write!(f, "token span invariant violated: end ({end}) < start ({start})")
107 }
108 Self::EmptySpanNotAllowed { kind, at } => {
109 write!(f, "empty span not allowed for token kind {kind:?} at byte {at}")
110 }
111 }
112 }
113}
114
115impl std::error::Error for TokenSpanError {}
116
117#[inline]
118const fn allows_empty_span(kind: TokenKind) -> bool {
119 matches!(kind, TokenKind::Eof | TokenKind::Unknown)
120}
121
122#[inline]
123fn validate_non_empty_span(
124 kind: TokenKind,
125 start: usize,
126 is_empty: bool,
127) -> Result<(), TokenSpanError> {
128 if is_empty && !allows_empty_span(kind) {
129 return Err(TokenSpanError::EmptySpanNotAllowed { kind, at: start });
130 }
131
132 Ok(())
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub struct TokenRef<'src> {
141 pub kind: TokenKind,
143 pub text: &'src str,
145 pub start: usize,
147 pub end: usize,
149}
150
151impl<'src> TokenRef<'src> {
152 pub fn new(kind: TokenKind, text: &'src str, start: usize, end: usize) -> Self {
154 Self { kind, text, start, end }
155 }
156
157 pub fn try_new(
161 kind: TokenKind,
162 text: &'src str,
163 start: usize,
164 end: usize,
165 ) -> Result<Self, TokenSpanError> {
166 let span = TokenSpan::try_new(start, end)?;
167 Ok(Self { kind, text, start: span.start, end: span.end })
168 }
169
170 pub fn new_checked(
176 kind: TokenKind,
177 text: &'src str,
178 start: usize,
179 end: usize,
180 ) -> Result<Self, TokenSpanError> {
181 let token = Self::try_new(kind, text, start, end)?;
182 validate_non_empty_span(token.kind, token.start, token.is_empty())?;
183
184 Ok(token)
185 }
186
187 pub fn len(self) -> usize {
189 TokenSpan::new(self.start, self.end).len()
190 }
191
192 pub fn is_empty(self) -> bool {
194 self.len() == 0
195 }
196
197 pub fn span(self) -> (usize, usize) {
199 (self.start, self.end)
200 }
201
202 pub fn display_name(self) -> &'static str {
204 self.kind.display_name()
205 }
206
207 pub fn to_owned_token(self) -> Token {
209 Token::new(self.kind, self.text, self.start, self.end)
210 }
211}
212
213#[derive(Debug, Clone, PartialEq)]
218pub struct Token {
219 pub kind: TokenKind,
221 pub text: Arc<str>,
223 pub start: usize,
225 pub end: usize,
227}
228
229impl Token {
230 pub fn new(kind: TokenKind, text: impl Into<Arc<str>>, start: usize, end: usize) -> Self {
242 Token { kind, text: text.into(), start, end }
243 }
244
245 pub fn try_new(
249 kind: TokenKind,
250 text: impl Into<Arc<str>>,
251 start: usize,
252 end: usize,
253 ) -> Result<Self, TokenSpanError> {
254 let span = TokenSpan::try_new(start, end)?;
255 Ok(Self { kind, text: text.into(), start: span.start, end: span.end })
256 }
257
258 pub fn new_checked(
264 kind: TokenKind,
265 text: impl Into<Arc<str>>,
266 start: usize,
267 end: usize,
268 ) -> Result<Self, TokenSpanError> {
269 let token = Self::try_new(kind, text, start, end)?;
270 validate_non_empty_span(token.kind, token.start, token.is_empty())?;
271
272 Ok(token)
273 }
274
275 pub fn eof_at(pos: usize) -> Self {
277 Self::new(TokenKind::Eof, "", pos, pos)
278 }
279
280 pub fn unknown_at(text: impl Into<Arc<str>>, start: usize, end: usize) -> Self {
282 let bounded_end = end.max(start);
283 Self::new(TokenKind::Unknown, text, start, bounded_end)
284 }
285
286 pub fn span(&self) -> TokenSpan {
288 TokenSpan::new(self.start, self.end)
289 }
290
291 pub fn range(&self) -> Range<usize> {
293 self.span().range()
294 }
295
296 pub fn with_span(&self, start: usize, end: usize) -> Result<Self, TokenSpanError> {
298 Self::new_checked(self.kind, self.text.clone(), start, end)
299 }
300
301 pub fn with_kind(&self, kind: TokenKind) -> Self {
303 Self::new(kind, self.text.clone(), self.start, self.end)
304 }
305
306 pub fn len(&self) -> usize {
320 self.span().len()
321 }
322
323 pub fn is_empty(&self) -> bool {
334 self.len() == 0
335 }
336
337 pub fn display_name(&self) -> &'static str {
339 self.kind.display_name()
340 }
341
342 pub fn as_ref_token(&self) -> TokenRef<'_> {
344 TokenRef { kind: self.kind, text: self.text.as_ref(), start: self.start, end: self.end }
345 }
346}
347
348impl From<TokenRef<'_>> for Token {
349 fn from(value: TokenRef<'_>) -> Self {
350 value.to_owned_token()
351 }
352}