use std::cell::Cell;
use std::rc::Rc;
use crate::atn::ATN;
use crate::atn_config::{ATNConfig, ATNConfigType};
use crate::atn_config_set::ATNConfigSet;
use crate::atn_simulator::{BaseATNSimulator, IATNSimulator};
use crate::atn_state::{ATNState, ATNStateRef};
use crate::char_stream::CharStream;
use crate::dfa::{DFAState, ProposedDFAState, DFA};
use crate::errors::ANTLRError;
use crate::int_stream::{IntStream, EOF};
use crate::lexer::{Lexer, LexerPosition, LEXER_MAX_CHAR_VALUE, LEXER_MIN_CHAR_VALUE};
use crate::lexer_action_executor::LexerActionExecutor;
use crate::prediction_context::EMPTY_PREDICTION_CONTEXT;
use crate::prediction_context::{PredictionContext, PredictionContextCache};
use crate::token::TOKEN_EOF;
use crate::token_factory::TokenFactory;
use crate::transition::{ActionTransition, Transition};
use crate::utils::cell_update;
#[doc(hidden)]
pub trait ILexerATNSimulator: IATNSimulator {
fn reset(&mut self);
fn match_token<'input, 'arena, Input, TF>(
&mut self,
mode: usize,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena;
fn get_char_position_in_line(&self) -> i32;
fn set_char_position_in_line(&mut self, column: i32);
fn get_line(&self) -> u32;
fn set_line(&mut self, line: u32);
fn consume<T: IntStream + ?Sized>(&self, input: &mut T);
#[cold]
fn recover(&mut self, _re: ANTLRError, input: &mut impl IntStream) {
if input.la(1) != EOF {
self.consume(input)
}
}
}
#[derive(Debug)]
pub struct LexerATNSimulator {
base: BaseATNSimulator,
start_index: isize,
pub(crate) current_pos: Rc<LexerPosition>,
mode: usize,
prev_accept: SimState<'static>,
}
impl ILexerATNSimulator for LexerATNSimulator {
fn reset(&mut self) {
self.prev_accept.reset()
}
fn match_token<'input, 'arena, Input, TF>(
&mut self,
mode: usize,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let arena = bumpalo::Bump::new();
self.mode = mode;
let mark = lexer.input().mark();
let result = (|| {
self.start_index = lexer.input().index();
self.prev_accept.reset();
let dfa = self
.base
.decision_to_dfa
.get(mode)
.ok_or_else(|| ANTLRError::illegal_state("invalid mode".into()))?;
match dfa.s0() {
None => self.match_atn(lexer, dfa, &arena),
Some(s0) => self.exec_atn(s0, lexer, dfa, &arena),
}
})();
lexer.input().release(mark);
result
}
fn get_char_position_in_line(&self) -> i32 {
self.current_pos.char_position_in_line.get()
}
fn set_char_position_in_line(&mut self, column: i32) {
self.current_pos.char_position_in_line.set(column)
}
fn get_line(&self) -> u32 {
self.current_pos.line.get()
}
fn set_line(&mut self, line: u32) {
self.current_pos.line.set(line)
}
fn consume<T: IntStream + ?Sized>(&self, _input: &mut T) {
let ch = _input.la(1);
if ch == '\n' as i32 {
cell_update(&self.current_pos.line, |x| x + 1);
self.current_pos.char_position_in_line.set(0);
} else {
cell_update(&self.current_pos.char_position_in_line, |x| x + 1);
}
_input.consume();
}
}
impl IATNSimulator for LexerATNSimulator {
fn shared_context_cache(&self) -> &PredictionContextCache {
self.base.shared_context_cache()
}
fn atn(&self) -> &ATN {
self.base.atn()
}
fn decision_to_dfa(&self) -> &Vec<DFA> {
self.base.decision_to_dfa()
}
}
#[allow(missing_docs)]
pub const MIN_DFA_EDGE: i32 = 0;
#[allow(missing_docs)]
pub const MAX_DFA_EDGE: i32 = 127;
pub const LEXER_DFA_EDGE_SET_SIZE: usize = (MAX_DFA_EDGE - MIN_DFA_EDGE + 1) as usize;
impl LexerATNSimulator {
pub fn new_lexer_atnsimulator(
atn: &'static ATN,
decision_to_dfa: &'static Vec<DFA>,
shared_context_cache: &'static PredictionContextCache,
) -> LexerATNSimulator {
LexerATNSimulator {
base: BaseATNSimulator::new_base_atnsimulator(
atn,
decision_to_dfa,
shared_context_cache,
),
start_index: 0,
current_pos: Rc::new(LexerPosition {
line: Cell::new(0),
char_position_in_line: Cell::new(0),
}),
mode: 0,
prev_accept: SimState::new(),
}
}
#[cold]
fn match_atn<'ephemeral, 'input, 'arena, Input, TF>(
&mut self,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
dfa: &DFA,
arena: &'ephemeral bumpalo::Bump,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let atn = self.atn();
let start_state = *atn
.mode_to_start_state
.get(self.mode)
.ok_or_else(|| ANTLRError::illegal_state("invalid mode".into()))?;
let _old_mode = self.mode;
let mut s0_closure = self.compute_start_state(start_state.as_ref(), lexer, arena);
let _supress_edge = s0_closure.has_semantic_context();
s0_closure.set_has_semantic_context(false);
let next_state = self.add_dfastate(dfa, s0_closure);
if !_supress_edge {
dfa.set_s0(next_state);
}
self.exec_atn(next_state, lexer, dfa, arena)
}
fn exec_atn<'ephemeral, 'input, 'arena, 'dfa, Input, TF>(
&mut self,
ds0: &'dfa DFAState<'dfa>,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
dfa: &'dfa DFA,
arena: &'ephemeral bumpalo::Bump,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
self.capture_sim_state(lexer.input(), ds0);
let mut symbol = lexer.input().la(1);
let mut s = ds0;
loop {
let target = Self::get_existing_target_state(s, symbol);
let target =
target.unwrap_or_else(|| self.compute_target_state(dfa, s, symbol, lexer, arena));
if target.is_error_state() {
break;
}
if symbol != EOF {
self.consume(lexer.input());
}
if self.capture_sim_state(lexer.input(), target) && symbol == EOF {
break;
}
symbol = lexer.input().la(1);
s = target;
}
self.fail_or_accept(symbol, lexer)
}
#[inline(always)]
fn get_existing_target_state<'dfa>(
s: &'dfa DFAState<'dfa>,
t: i32,
) -> Option<&'dfa DFAState<'dfa>> {
s.get_edge((t - MIN_DFA_EDGE) as usize)
}
#[cold]
fn compute_target_state<'ephemeral, 'input, 'arena, 'dfa, Input, TF>(
&self,
dfa: &'dfa DFA,
s: &DFAState<'dfa>,
_t: i32,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
arena: &'ephemeral bumpalo::Bump,
) -> &'dfa DFAState<'dfa>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let mut reach = ATNConfigSet::new_ordered(arena);
self.get_reachable_config_set(s.configs(), &mut reach, _t, lexer, arena);
if reach.is_empty() {
if !reach.has_semantic_context() {
self.add_dfaedge(s, _t, dfa.get_error_state());
}
return dfa.get_error_state();
}
let supress_edge = reach.has_semantic_context();
reach.set_has_semantic_context(false);
let to = self.add_dfastate(dfa, reach);
if !supress_edge {
let from = s;
self.add_dfaedge(from, _t, to);
}
to
}
fn get_reachable_config_set<'ephemeral, 'input, 'arena, Input, TF>(
&self,
_closure: &ATNConfigSet<'ephemeral>,
_reach: &mut ATNConfigSet<'ephemeral>,
_t: i32,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
ephemerals: &'ephemeral bumpalo::Bump,
) where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let mut skip_alt = 0;
for config in _closure.get_items() {
let current_alt_reached_accept_state = config.get_alt() == skip_alt;
if current_alt_reached_accept_state {
if let ATNConfigType::LexerATNConfig {
passed_through_non_greedy_decision: true,
..
} = config.get_type()
{
continue;
}
}
let atn_state = config.get_state();
for tr in atn_state.get_transitions() {
if let Some(target) = tr.get_reachable_target(_t) {
let exec = config.get_lexer_executor().map(|x| {
ephemerals.alloc(
x.clone()
.fix_offset_before_match(lexer.input().index() - self.start_index),
) as &'ephemeral LexerActionExecutor
});
let new = config.clone().with_state(target).with_lexer_executor(exec);
if self.closure(
new,
_reach,
current_alt_reached_accept_state,
true,
_t == EOF,
lexer,
ephemerals,
) {
skip_alt = config.get_alt();
break;
}
}
}
}
}
fn fail_or_accept<'input, 'arena, Input, TF>(
&mut self,
_t: i32,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
if let Some(state) = self.prev_accept.dfa_state {
self.accept(lexer.input());
let prediction = {
if let Some(x) = state.lexer_action_executor.as_ref() {
x.execute(lexer, self.start_index)
}
state.prediction
};
Ok(prediction)
} else {
if _t == EOF && lexer.input().index() == self.start_index {
return Ok(TOKEN_EOF);
}
Err(ANTLRError::lexer_no_alt(self.start_index))
}
}
fn accept(&mut self, input: &mut impl IntStream) {
input.seek(self.prev_accept.index);
self.current_pos.line.set(self.prev_accept.line);
self.current_pos
.char_position_in_line
.set(self.prev_accept.column);
}
fn compute_start_state<'ephemeral, 'input, 'arena, Input, TF>(
&self,
p: &ATNState,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
arena: &'ephemeral bumpalo::Bump,
) -> ATNConfigSet<'ephemeral>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let mut config_set = ATNConfigSet::new_ordered(arena);
for (i, tr) in p.get_transitions().iter().enumerate() {
let target = tr.get_target();
let atn_config =
ATNConfig::new_lexer(target, (i + 1) as i32, &EMPTY_PREDICTION_CONTEXT);
self.closure(
atn_config,
&mut config_set,
false,
false,
false,
lexer,
arena,
);
}
config_set
}
#[allow(clippy::too_many_arguments)]
fn closure<'ephemeral, 'input, 'arena, Input, TF>(
&self,
mut config: ATNConfig<'ephemeral>,
config_set: &mut ATNConfigSet<'ephemeral>,
mut _current_alt_reached_accept_state: bool,
speculative: bool,
treat_eofas_epsilon: bool,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
arena: &'ephemeral bumpalo::Bump,
) -> bool
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let state = config.get_state();
if let ATNState::RuleStop(_) = *state {
if config.get_context().map(|x| x.has_empty_path()) != Some(false) {
if config.get_context().map(|x| x.is_empty()) != Some(false) {
config_set.add(config);
return true;
} else {
config_set.add(
config
.clone()
.with_state(state)
.with_prediction_context(Some(&EMPTY_PREDICTION_CONTEXT)),
);
_current_alt_reached_accept_state = true
}
}
if config.get_context().map(|x| x.is_empty()) == Some(false) {
let ctx = config.take_context();
for i in 0..ctx.length() {
if ctx.get_return_state(i) != ATNStateRef::invalid() {
let new_ctx = ctx.get_parent(i);
let return_state = ctx.get_return_state(i);
let next_config = config
.clone()
.with_state(return_state)
.with_prediction_context(new_ctx);
_current_alt_reached_accept_state = self.closure(
next_config,
config_set,
_current_alt_reached_accept_state,
speculative,
treat_eofas_epsilon,
lexer,
arena,
)
}
}
}
return _current_alt_reached_accept_state;
}
if !state.has_epsilon_only_transitions() {
if let ATNConfigType::LexerATNConfig {
passed_through_non_greedy_decision,
..
} = config.config_type
{
if !_current_alt_reached_accept_state || !passed_through_non_greedy_decision {
config_set.add(config.clone());
}
}
}
let state = config.get_state();
for tr in state.get_transitions() {
let c = self.get_epsilon_target(
&mut config,
tr,
config_set,
speculative,
treat_eofas_epsilon,
lexer,
arena,
);
if let Some(c) = c {
_current_alt_reached_accept_state = self.closure(
c,
config_set,
_current_alt_reached_accept_state,
speculative,
treat_eofas_epsilon,
lexer,
arena,
);
}
}
_current_alt_reached_accept_state
}
#[allow(clippy::too_many_arguments)]
fn get_epsilon_target<'ephemeral, 'input, 'arena, Input, TF>(
&self,
_config: &mut ATNConfig<'ephemeral>,
_trans: &Transition,
_configs: &mut ATNConfigSet<'ephemeral>,
_speculative: bool,
_treat_eofas_epsilon: bool,
lexer: &mut impl Lexer<'input, 'arena, Input, TF>,
ephemerals: &'ephemeral bumpalo::Bump,
) -> Option<ATNConfig<'ephemeral>>
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
let mut result = None;
let target = _trans.get_target();
match _trans {
Transition::Epsilon(_) => {
result = Some(_config.clone().with_state(target));
}
Transition::Rule(rt) => {
let pred_ctx = PredictionContext::new_singleton(
Some(_config.get_context().unwrap()),
rt.follow_state,
);
result = Some(
_config
.clone()
.with_state(target)
.with_prediction_context(Some(ephemerals.alloc(pred_ctx))),
);
}
Transition::Predicate(tr) => {
_configs.set_has_semantic_context(true);
if self.evaluate_predicate(tr.rule_index, tr.pred_index, _speculative, lexer) {
result = Some(_config.clone().with_state(target));
}
}
Transition::Action(_) => {
if _config.get_context().map(|x| x.has_empty_path()) != Some(false) {
if let ATNConfigType::LexerATNConfig {
lexer_action_executor,
..
} = _config.get_type()
{
let tr = _trans.try_as::<ActionTransition>().unwrap();
let lexer_action =
self.atn().lexer_actions[tr.action_index as usize].clone();
let lexer_action_executor = LexerActionExecutor::new_copy_append(
lexer_action_executor.as_deref(),
lexer_action,
);
result = Some(
_config
.clone()
.with_state(target)
.with_lexer_executor(Some(ephemerals.alloc(lexer_action_executor))),
)
}
} else {
result = Some(_config.clone().with_state(target));
}
}
Transition::Range(_) | Transition::Set(_) | Transition::Atom(_) => {
if _treat_eofas_epsilon
&& _trans.matches(EOF, LEXER_MIN_CHAR_VALUE, LEXER_MAX_CHAR_VALUE)
{
let target = _trans.get_target();
result = Some(_config.clone().with_state(target));
}
}
Transition::Wildcard(_) => {}
Transition::NotSet(_) => {}
Transition::PrecedencePredicate(_) => {
panic!("precedence predicates are not supposed to be in lexer");
}
}
result
}
fn evaluate_predicate<'input, 'arena, Input, TF, T: Lexer<'input, 'arena, Input, TF>>(
&self,
rule_index: i32,
pred_index: i32,
speculative: bool,
lexer: &mut T,
) -> bool
where
'input: 'arena,
Input: CharStream<'input>,
TF: TokenFactory<'input, 'arena> + 'arena,
{
if !speculative {
return lexer.sempred(None, rule_index, pred_index);
}
let saved_column = self.current_pos.char_position_in_line.get();
let saved_line = self.current_pos.line.get();
let index = lexer.input().index();
let marker = lexer.input().mark();
self.consume(lexer.input());
let result = lexer.sempred(None, rule_index, pred_index);
self.current_pos.char_position_in_line.set(saved_column);
self.current_pos.line.set(saved_line);
lexer.input().seek(index);
lexer.input().release(marker);
result
}
fn capture_sim_state<'dfa>(
&mut self,
input: &impl IntStream,
dfa_state: &'dfa DFAState<'dfa>,
) -> bool {
if dfa_state.is_accept_state {
self.set_prev_accept(SimState {
index: input.index(),
line: self.current_pos.line.get(),
column: self.current_pos.char_position_in_line.get(),
dfa_state: Some(dfa_state),
});
return true;
}
false
}
fn set_prev_accept<'dfa>(&mut self, s: SimState<'dfa>) {
self.prev_accept = unsafe { std::mem::transmute::<SimState<'dfa>, SimState<'static>>(s) };
}
fn add_dfaedge<'dfa>(&self, from: &DFAState<'dfa>, t: i32, _to: &DFAState<'dfa>) {
if !(MIN_DFA_EDGE..=MAX_DFA_EDGE).contains(&t) {
return;
}
from.set_edge((t - MIN_DFA_EDGE) as usize, _to);
}
fn add_dfastate<'dfa>(&self, dfa: &'dfa DFA, configs: ATNConfigSet) -> &'dfa DFAState<'dfa> {
assert!(!configs.has_semantic_context());
let mut state = ProposedDFAState::new(configs);
let rule_index = state
.configs
.get_items()
.find(|c| matches!(*c.get_state(), ATNState::RuleStop(_)))
.map(|c| {
let rule_index = c.get_state().get_rule_index();
(
self.atn().rule_to_token_type[rule_index as usize],
c.get_lexer_executor().cloned().map(Box::new),
)
});
if let Some((prediction, exec)) = rule_index {
state.prediction = prediction;
state.lexer_action_executor = exec;
state.is_accept_state = true;
}
dfa.add_state(state, self)
}
pub fn get_dfa(&self) -> &DFA {
&self.decision_to_dfa()[self.mode]
}
pub fn get_dfa_for_mode(&self, mode: usize) -> &DFA {
&self.decision_to_dfa()[mode]
}
}
#[derive(Debug)]
pub(crate) struct SimState<'dfa> {
index: isize,
line: u32,
column: i32,
dfa_state: Option<&'dfa DFAState<'dfa>>,
}
impl<'dfa> SimState<'dfa> {
pub(crate) fn new() -> SimState<'dfa> {
SimState {
index: -1,
line: 0,
column: -1,
dfa_state: None,
}
}
pub(crate) fn reset(&mut self) {
self.dfa_state = None;
}
}