compiler_tools/
tokenizer.rs1use std::marker::PhantomData;
2
3use crate::span::Spanned;
4
5pub trait TokenExt: Clone + Copy + PartialEq {
6 fn matches_class(&self, other: &Self) -> bool;
7}
8
9pub trait TokenParse<'a> {
10 type Token: TokenExt + 'a;
11
12 fn next(&mut self) -> Option<Spanned<Self::Token>>;
13}
14
15pub struct TokenizerWrap<'a, T: TokenParse<'a>> {
16 inner: T,
17 peeked: Option<Spanned<T::Token>>,
18 tokens_to_ignore: Vec<T::Token>,
19 _lifetime: PhantomData<&'a ()>,
20}
21
22impl<'a, T: TokenParse<'a>> TokenizerWrap<'a, T> {
23 pub fn new(inner: T, tokens_to_ignore: impl IntoIterator<Item = T::Token>) -> Self {
24 Self {
25 inner,
26 tokens_to_ignore: tokens_to_ignore.into_iter().collect(),
27 peeked: None,
28 _lifetime: PhantomData,
29 }
30 }
31
32 pub fn next(&mut self) -> Option<Spanned<T::Token>> {
33 if let Some(peeked) = self.peeked.take() {
34 Some(peeked)
35 } else {
36 loop {
37 let next = self.inner.next()?;
38 if self.tokens_to_ignore.iter().all(|x| !x.matches_class(&*next)) {
39 break Some(next);
40 }
41 }
42 }
43 }
44
45 pub fn peek(&mut self) -> Option<&Spanned<T::Token>> {
46 if self.peeked.is_none() {
47 self.peeked = self.next();
48 }
49 self.peeked.as_ref()
50 }
51
52 pub fn eat(&mut self, token: T::Token) -> Option<Spanned<T::Token>> {
53 let next = self.next()?;
54 if next.matches_class(&token) {
55 Some(next)
56 } else {
57 self.peeked = Some(next);
58 None
59 }
60 }
61
62 pub fn eat_any(&mut self, tokens: &[T::Token]) -> Option<Spanned<T::Token>> {
63 let next = self.next()?;
64 for token in tokens {
65 if next.matches_class(token) {
66 return Some(next);
67 }
68 }
69 self.peeked = Some(next);
70 None
71 }
72}