1use super::internal::LexerInternal;
2use super::Logos;
3use crate::source::{self, Source};
4
5use core::fmt::{self, Debug};
6use core::mem::ManuallyDrop;
7
8pub type Span = core::ops::Range<usize>;
10
11pub struct Lexer<'source, Token: Logos<'source>> {
14 source: &'source Token::Source,
15 token: ManuallyDrop<Option<Token>>,
16 token_start: usize,
17 token_end: usize,
18
19 pub extras: Token::Extras,
21}
22
23impl<'source, Token> Debug for Lexer<'source, Token>
24where
25 Token: Logos<'source>,
26 Token::Source: Debug,
27 Token::Extras: Debug,
28{
29 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
30 fmt.debug_map()
31 .entry(&"source", &self.source)
32 .entry(&"extras", &self.extras)
33 .finish()
34 }
35}
36
37impl<'source, Token: Logos<'source>> Lexer<'source, Token> {
38 pub fn new(source: &'source Token::Source) -> Self
43 where
44 Token::Extras: Default,
45 {
46 Self::with_extras(source, Default::default())
47 }
48
49 pub fn with_extras(source: &'source Token::Source, extras: Token::Extras) -> Self {
54 Lexer {
55 source,
56 token: ManuallyDrop::new(None),
57 extras,
58 token_start: 0,
59 token_end: 0,
60 }
61 }
62
63 #[inline]
65 pub fn source(&self) -> &'source Token::Source {
66 self.source
67 }
68
69 #[inline]
103 pub fn spanned(self) -> SpannedIter<'source, Token> {
104 SpannedIter { lexer: self }
105 }
106
107 #[inline]
108 #[doc(hidden)]
109 #[deprecated(since = "0.11.0", note = "please use `span` instead")]
110 pub fn range(&self) -> Span {
111 self.span()
112 }
113
114 #[inline]
116 pub fn span(&self) -> Span {
117 self.token_start..self.token_end
118 }
119
120 #[inline]
122 pub fn slice(&self) -> &'source <Token::Source as Source>::Slice {
123 unsafe { self.source.slice_unchecked(self.span()) }
124 }
125
126 #[inline]
128 pub fn remainder(&self) -> &'source <Token::Source as Source>::Slice {
129 unsafe {
130 self.source
131 .slice_unchecked(self.token_end..self.source.len())
132 }
133 }
134
135 pub fn morph<Token2>(self) -> Lexer<'source, Token2>
140 where
141 Token2: Logos<'source, Source = Token::Source>,
142 Token::Extras: Into<Token2::Extras>,
143 {
144 Lexer {
145 source: self.source,
146 token: ManuallyDrop::new(None),
147 extras: self.extras.into(),
148 token_start: self.token_start,
149 token_end: self.token_end,
150 }
151 }
152
153 pub fn bump(&mut self, n: usize) {
160 self.token_end += n;
161
162 assert!(
163 self.source.is_boundary(self.token_end),
164 "Invalid Lexer bump",
165 )
166 }
167}
168
169impl<'source, Token> Clone for Lexer<'source, Token>
170where
171 Token: Logos<'source> + Clone,
172 Token::Extras: Clone,
173{
174 fn clone(&self) -> Self {
175 Lexer {
176 extras: self.extras.clone(),
177 token: self.token.clone(),
178 ..*self
179 }
180 }
181}
182
183impl<'source, Token> Iterator for Lexer<'source, Token>
184where
185 Token: Logos<'source>,
186{
187 type Item = Token;
188
189 #[inline]
190 fn next(&mut self) -> Option<Token> {
191 self.token_start = self.token_end;
192
193 Token::lex(self);
194
195 unsafe { ManuallyDrop::take(&mut self.token) }
200 }
201}
202
203pub struct SpannedIter<'source, Token: Logos<'source>> {
207 lexer: Lexer<'source, Token>,
208}
209
210impl<'source, Token> Iterator for SpannedIter<'source, Token>
211where
212 Token: Logos<'source>,
213{
214 type Item = (Token, Span);
215
216 fn next(&mut self) -> Option<Self::Item> {
217 self.lexer.next().map(|token| (token, self.lexer.span()))
218 }
219}
220
221#[doc(hidden)]
222impl<'source, Token> LexerInternal<'source> for Lexer<'source, Token>
227where
228 Token: Logos<'source>,
229{
230 type Token = Token;
231
232 #[inline]
235 fn read<Chunk>(&self) -> Option<Chunk>
236 where
237 Chunk: source::Chunk<'source>,
238 {
239 self.source.read(self.token_end)
240 }
241
242 #[inline]
244 fn read_at<Chunk>(&self, n: usize) -> Option<Chunk>
245 where
246 Chunk: source::Chunk<'source>,
247 {
248 self.source.read(self.token_end + n)
249 }
250
251 #[inline]
252 unsafe fn read_unchecked<Chunk>(&self, n: usize) -> Chunk
253 where
254 Chunk: source::Chunk<'source>,
255 {
256 self.source.read_unchecked(self.token_end + n)
257 }
258
259 #[inline]
261 fn test<T, F>(&self, test: F) -> bool
262 where
263 T: source::Chunk<'source>,
264 F: FnOnce(T) -> bool,
265 {
266 match self.source.read::<T>(self.token_end) {
267 Some(chunk) => test(chunk),
268 None => false,
269 }
270 }
271
272 #[inline]
274 fn test_at<T, F>(&self, n: usize, test: F) -> bool
275 where
276 T: source::Chunk<'source>,
277 F: FnOnce(T) -> bool,
278 {
279 match self.source.read::<T>(self.token_end + n) {
280 Some(chunk) => test(chunk),
281 None => false,
282 }
283 }
284
285 #[inline]
287 fn bump_unchecked(&mut self, size: usize) {
288 debug_assert!(
289 self.token_end + size <= self.source.len(),
290 "Bumping out of bounds!"
291 );
292
293 self.token_end += size;
294 }
295
296 #[inline]
298 fn trivia(&mut self) {
299 self.token_start = self.token_end;
300 }
301
302 #[inline]
305 fn error(&mut self) {
306 self.token_end = self.source.find_boundary(self.token_end);
307 self.token = ManuallyDrop::new(Some(Token::ERROR));
308 }
309
310 #[inline]
311 fn end(&mut self) {
312 self.token = ManuallyDrop::new(None);
313 }
314
315 #[inline]
316 fn set(&mut self, token: Token) {
317 self.token = ManuallyDrop::new(Some(token));
318 }
319}