use super::lexer::RantyToken;
use crate::InternalString;
use logos::*;
use std::ops::Range;
#[derive(Clone)]
pub struct RantyTokenReader<'source> {
lexer: Lexer<'source, RantyToken>,
peeked: Option<(RantyToken, Range<usize>)>,
}
impl<'source> RantyTokenReader<'source> {
pub fn new(src: &'source str) -> Self {
Self {
lexer: RantyToken::lexer(src),
peeked: None,
}
}
pub fn next(&mut self) -> Option<(RantyToken, Range<usize>)> {
self.peeked
.take()
.or_else(|| self.lexer.next().map(|token| (token, self.lexer.span())))
}
pub fn skip_one(&mut self) {
self.next();
}
pub fn eat_where<F: FnOnce(Option<&(RantyToken, Range<usize>)>) -> bool>(
&mut self,
predicate: F,
) -> bool {
if predicate(self.peek()) {
self.skip_one();
return true;
}
false
}
pub fn eat(&mut self, token: RantyToken) -> bool {
if let Some((peeked, _span)) = self.peek() {
if peeked.eq(&token) {
self.skip_one();
return true;
}
}
false
}
pub fn eat_kw(&mut self, kwname: &str) -> bool {
self.eat_where(|t| {
if let Some((RantyToken::Keyword(kw), _)) = t.as_ref() {
return kw.name.as_str() == kwname;
}
false
})
}
pub fn take_where<F: FnOnce(Option<&(RantyToken, Range<usize>)>) -> bool>(
&mut self,
predicate: F,
) -> Option<(RantyToken, Range<usize>)> {
if predicate(self.peek()) {
self.next()
} else {
None
}
}
pub fn last_token_string(&self) -> InternalString {
InternalString::from(self.lexer.slice())
}
pub fn next_solid(&mut self) -> Option<(RantyToken, Range<usize>)> {
loop {
match self.next() {
Some((RantyToken::Whitespace, _)) => continue,
Some((token, span)) => return Some((token, span)),
None => return None,
}
}
}
pub fn skip_ws(&mut self) {
while let Some((RantyToken::Whitespace, _)) = self.peek() {
self.next();
}
}
pub fn last_token_pos(&self) -> usize {
self.lexer.span().start
}
pub fn last_token_span(&self) -> Range<usize> {
self.lexer.span()
}
pub fn peek(&mut self) -> Option<&(RantyToken, Range<usize>)> {
if self.peeked.is_some() {
return self.peeked.as_ref();
}
let token = self.next();
self.peeked = token;
self.peeked.as_ref()
}
}