use crate::{
TokenNumber,
lexer::{Token, location},
};
use location::LocationBuilder;
use log::trace;
use scnr2::{FindMatchesWithPosition, Match};
use std::{path::PathBuf, sync::Arc};
pub struct TokenIter<'t, F>
where
F: Fn(char) -> Option<usize> + 'static + Clone,
{
pub(crate) find_iter: FindMatchesWithPosition<'t, F>,
pub(crate) input: &'t str,
k: usize,
pub file_name: Arc<PathBuf>,
token_number: TokenNumber,
}
impl<'t, F> TokenIter<'t, F>
where
F: Fn(char) -> Option<usize> + 'static + Clone,
{
pub fn new(
find_iter: FindMatchesWithPosition<'t, F>,
input: &'t str,
file_name: Arc<PathBuf>,
k: usize,
) -> Self {
Self {
find_iter,
input,
k,
file_name: file_name.clone(),
token_number: 0,
}
}
pub(crate) fn scanner_mode_name(&self, index: usize) -> Option<&'static str> {
self.find_iter.mode_name(index)
}
pub(crate) fn current_mode(&self) -> usize {
self.find_iter.current_mode()
}
#[inline(always)]
pub(crate) fn token_from_match(&mut self, matched: Match) -> Option<Token<'t>> {
let positions = matched.positions?;
let location = LocationBuilder::default()
.start_line(positions.start_position.line as u32)
.start_column(positions.start_position.column as u32)
.end_line(positions.end_position.line as u32)
.end_column(positions.end_position.column as u32)
.start(matched.span.start as u32)
.end(matched.span.end as u32)
.file_name(Arc::clone(&self.file_name))
.build()
.ok()?;
let text = &self.input[matched.span];
let token = Token::with(text, matched.token_type as u16, location, self.token_number);
if !token.is_skip_token() || token.is_comment_token() {
self.token_number += 1;
}
Some(token)
}
#[inline]
pub(crate) fn next_token_number(&mut self) -> TokenNumber {
self.token_number += 1;
self.token_number
}
}
impl<'t, F> Iterator for TokenIter<'t, F>
where
F: Fn(char) -> Option<usize> + 'static + Clone,
{
type Item = Token<'t>;
fn next(&mut self) -> Option<Token<'t>> {
if let Some(matched) = self.find_iter.next() {
self.token_from_match(matched)
} else if self.k > 0 {
self.k -= 1;
trace!("EOI");
Some(
Token::eoi(self.next_token_number()).with_location(
LocationBuilder::default()
.start(self.input.len() as u32)
.end(self.input.len() as u32)
.file_name(Arc::clone(&self.file_name))
.build()
.ok()?,
),
)
} else {
trace!("Normal end of iteration");
None
}
}
}