use std::hash::{Hash, Hasher};
use fxhash::{hash64, FxHasher64};
use crate::atn_config_set::ConfigSet;
use crate::char_stream::CharStream;
use crate::dfa::DFAStateStore;
use crate::lexer::Lexer;
use crate::lexer_action::{LexerAction, LexerIndexedCustomAction};
use crate::token_factory::TokenFactory;
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct LexerActionExecutor<'ephemeral> {
cached_hash: u64,
lexer_actions: &'ephemeral [LexerAction<'ephemeral>],
}
impl Hash for LexerActionExecutor<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.cached_hash)
}
}
impl<'ephemeral> LexerActionExecutor<'ephemeral> {
pub(crate) fn new_copy_append(
scratch: &'ephemeral bumpalo::Bump,
old: Option<&Self>,
lexer_action: LexerAction<'ephemeral>,
) -> LexerActionExecutor<'ephemeral> {
if let Some(LexerActionExecutor {
lexer_actions,
cached_hash,
}) = old
{
let new_hash = {
let mut hasher = FxHasher64::default();
hasher.write_u64(*cached_hash);
lexer_action.hash(&mut hasher);
hasher.finish()
};
let new_actions = scratch.alloc_slice_fill_with(lexer_actions.len() + 1, |i| {
if i < lexer_actions.len() {
lexer_actions[i].clone()
} else {
lexer_action.clone()
}
});
LexerActionExecutor {
lexer_actions: new_actions,
cached_hash: new_hash,
}
} else {
LexerActionExecutor {
cached_hash: { hash64(&lexer_action) },
lexer_actions: scratch.alloc_slice_fill_iter(std::iter::once(lexer_action)),
}
}
}
pub fn fix_offset_before_match(
&self,
arena: &'ephemeral bumpalo::Bump,
offset: isize,
) -> LexerActionExecutor<'ephemeral> {
let fixed_actions = arena.alloc_slice_fill_with(self.lexer_actions.len(), |i| {
let action = self.lexer_actions[i].clone();
if let LexerAction::IndexedCustom(..) = action {
action
} else if action.is_position_dependent() {
LexerAction::IndexedCustom(arena.alloc(LexerIndexedCustomAction { offset, action }))
} else {
action
}
});
LexerActionExecutor {
lexer_actions: fixed_actions,
cached_hash: self.cached_hash,
}
}
pub fn execute<'input, 'arena, Input, TF>(
&self,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
start_index: isize,
) where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let mut requires_seek = false;
let stop_index = lexer.input().index();
for action in self.lexer_actions.iter() {
if let LexerAction::IndexedCustom(LexerIndexedCustomAction { offset, .. }) = action {
lexer.input().seek(start_index + offset);
requires_seek = start_index + offset != stop_index;
} else if action.is_position_dependent() {
lexer.input().seek(stop_index);
requires_seek = false
}
action.execute(lexer);
}
if requires_seek {
lexer.input().seek(stop_index);
}
}
pub(crate) fn promote<'sim, CS>(
&self,
dfa: &DFAStateStore<'sim, CS>,
) -> LexerActionExecutor<'sim>
where
CS: ConfigSet<'sim> + 'sim,
{
if dfa.contains_lexer_action_slice(self.lexer_actions) {
return unsafe { std::mem::transmute::<Self, LexerActionExecutor<'sim>>(self.clone()) };
}
let promoted_actions = dfa.alloc_lexer_action_slice(self.lexer_actions.len(), |i| {
self.lexer_actions[i].promote(dfa)
});
LexerActionExecutor {
lexer_actions: promoted_actions,
cached_hash: self.cached_hash,
}
}
}