use std::borrow::{Borrow, Cow};
use std::cell::Cell;
use std::hash::Hasher;
use std::marker::PhantomData;
use bit_set::BitSet;
use hashbrown::{DefaultHashBuilder, HashMap, HashSet};
use crate::atn::{ATN, INVALID_ALT};
use crate::atn_config::ATNConfig;
use crate::atn_config_set::{ATNConfigSet, MutableATNConfigSet};
use crate::atn_simulator::{BaseATNSimulator, IATNSimulator};
use crate::atn_state::{
ATNState, ATNStateRef, ATNStateType, StarLoopEntryState, ATNSTATE_BLOCK_END,
};
use crate::dfa::{DFAState, PredPrediction, ProposedDFAState, ScopeExt, DFA};
use crate::errors::ANTLRError;
use crate::int_stream::EOF;
use crate::parser::Parser;
use crate::prediction_context::{
NoopHasherBuilder, PredictionContext, PredictionContextCache, PredictionContextRef,
};
use crate::prediction_mode::*;
use crate::semantic_context::SemanticContext;
use crate::token::{OwningToken, Token, TOKEN_EOF, TOKEN_EPSILON};
use crate::token_factory::TokenFactory;
use crate::token_stream::TokenStream;
use crate::transition::{
ActionTransition, PrecedencePredicateTransition, PredicateTransition, RuleTransition,
Transition, TransitionType,
};
use crate::tree::TreeNode;
#[derive(Debug)]
pub struct ParserATNSimulator<'sim> {
base: BaseATNSimulator<'sim, ATNConfigSet<'sim>>,
prediction_mode: Cell<PredictionMode>,
start_index: Cell<isize>,
}
struct Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
outer_context: &'arena TreeNode<'input, 'arena, P::Node>,
dfa_ref: &'sim DFA<'sim, ATNConfigSet<'sim>>,
merge_cache: &'cache mut MergeCache<'scratch>,
precedence: i32,
parser: &'cache mut P,
pd: PhantomData<Box<dyn TokenStream<'input, 'arena, TF>>>,
}
impl<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>
Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
fn input(&mut self) -> &mut dyn TokenStream<'input, 'arena, TF> {
self.parser.get_input_stream_mut()
}
fn outer_context(&self) -> &'arena TreeNode<'input, 'arena, P::Node> {
self.outer_context
}
fn scratch(&self) -> &'scratch bumpalo::Bump {
self.merge_cache.scratch
}
}
impl<'sim> ParserATNSimulator<'sim> {
pub fn new(base: BaseATNSimulator<'sim, ATNConfigSet<'sim>>) -> Self {
ParserATNSimulator {
base,
prediction_mode: Cell::new(PredictionMode::LL),
start_index: Cell::new(0),
}
}
pub fn get_prediction_mode(&self) -> PredictionMode {
self.prediction_mode.get()
}
pub fn set_prediction_mode(&self, v: PredictionMode) {
self.prediction_mode.set(v)
}
pub fn adaptive_predict<'input, 'arena, TF, P>(
&self,
decision: i32,
parser: &mut P,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
'arena: 'sim,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
self.start_index.set(parser.get_input_stream_mut().index());
let scratch = bumpalo::Bump::new();
let mut merge_cache = MergeCache::new(&scratch);
let mut local = Local {
outer_context: parser.get_current_context(),
dfa_ref: self
.decision_to_dfa(decision as usize)
.expect("decision is valid"),
merge_cache: &mut merge_cache,
precedence: parser.get_precedence(),
parser,
pd: PhantomData,
};
let m = local.input().mark();
let result = {
let s0 = {
let dfa = local.dfa_ref;
if dfa.is_precedence_dfa() {
dfa.get_precedence_start_state(
local.precedence,
)
} else {
dfa.s0()
}
};
let s0 = if let Some(s) = s0 {
s
} else {
let s0_closure = self.compute_start_state(
local.dfa_ref.borrow().atn_start_state,
PredictionContextRef::new_empty(),
false,
&mut local,
);
if local.dfa_ref.is_precedence_dfa() {
let dfa_ref = local.dfa_ref;
let s0_closure_updated = self.apply_precedence_filter(&s0_closure, &mut local);
let new_s0 =
self.add_dfastate(dfa_ref, ProposedDFAState::new(s0_closure_updated))?;
dfa_ref.set_precedence_start_state(local.precedence, new_s0);
new_s0
} else {
let dfa_ref = local.dfa_ref;
let s0 = self.add_dfastate(dfa_ref, ProposedDFAState::new(s0_closure))?;
dfa_ref.set_s0(s0);
s0
}
};
self.exec_atn(&mut local, s0)?
};
local.input().seek(self.start_index.get());
local.input().release(m);
Ok(result)
}
#[allow(non_snake_case)]
fn exec_atn<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
s0: &'sim DFAState<'sim, ATNConfigSet<'sim>>,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
'sim: 'scratch,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let mut previousD = s0;
let mut token = local.input().la(1);
loop {
let D = if let Some(s) = { local.dfa_ref.get_edge(previousD, (token + 1) as usize) } {
s
} else {
self.compute_target_state(previousD, token, local)?
};
if D.is_error_state() {
let err = self.no_viable_alt(local, self.start_index.get());
local.input().seek(self.start_index.get());
let alt = self.get_syn_valid_or_sem_invalid_alt_that_finished_decision_entry_rule(
previousD.configs().get_items(),
previousD.configs().full_context(),
local,
);
if alt != INVALID_ALT {
return Ok(alt);
}
return Err(err);
}
let dfa = local.dfa_ref;
let Dstate = D;
if Dstate.requires_full_context() && self.prediction_mode.get() != PredictionMode::SLL {
let mut conflicting_alts = Cow::Borrowed(Dstate.configs().conflicting_alts());
if !Dstate.predicates().is_empty() {
let conflict_index = local.input().index();
if conflict_index != self.start_index.get() {
local.input().seek(self.start_index.get())
}
conflicting_alts =
Cow::Owned(self.eval_semantic_context(local, Dstate.predicates(), true));
if conflicting_alts.len() == 1 {
return Ok(conflicting_alts.iter().next().unwrap() as i32);
}
if conflict_index != self.start_index.get() {
local.input().seek(conflict_index)
}
}
self.report_attempting_full_context(
dfa,
&conflicting_alts,
Dstate.configs(),
self.start_index.get(),
local.input().index(),
local.parser,
);
let atn_start_state = dfa.atn_start_state;
let s0_closure = self.compute_start_state(
atn_start_state,
PredictionContext::from_rule_context(
self.atn(),
local.outer_context(),
local.merge_cache.scratch,
),
true,
local,
);
return self.exec_atn_with_full_context(local, s0_closure);
}
if Dstate.is_accept_state() {
if Dstate.predicates().is_empty() {
return Ok(Dstate.prediction());
}
let stop_index = local.input().index();
local.input().seek(self.start_index.get());
let alts = self.eval_semantic_context(local, Dstate.predicates(), true);
match alts.len() {
0 => return Err(self.no_viable_alt(local, self.start_index.get())),
1 => return Ok(alts.iter().next().unwrap() as i32),
_ => {
let ecs =
MutableATNConfigSet::from_config_set(local.scratch(), Dstate.configs());
self.report_ambiguity(
dfa,
self.start_index.get(),
stop_index,
false,
&alts,
&ecs,
local.parser,
);
return Ok(alts.iter().next().unwrap() as i32);
}
}
}
previousD = D;
if token != EOF {
local.input().consume();
token = local.input().la(1);
}
}
}
#[allow(non_snake_case)]
fn compute_target_state<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
previousD: &'sim DFAState<'sim, ATNConfigSet<'sim>>,
t: i32,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> Result<&'sim DFAState<'sim, ATNConfigSet<'sim>>, ANTLRError>
where
'input: 'arena,
'sim: 'scratch,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let reach = {
let closure = previousD.configs();
self.compute_reach_set(closure.get_items(), t, false, local)
};
let reach = match reach {
None => {
self.add_dfaedge(local.dfa_ref, previousD, t, local.dfa_ref.get_error_state());
return Ok(local.dfa_ref.get_error_state());
}
Some(x) => x,
};
let predicted_alt = self.get_unique_alt(&reach);
let mut D = ProposedDFAState::new(reach);
if predicted_alt != INVALID_ALT {
D.is_accept_state = true;
D.configs.set_unique_alt(predicted_alt);
D.prediction = predicted_alt
} else if Self::all_configs_in_rule_stop_state(&D.configs)
|| has_sll_conflict_terminating_prediction(
local.scratch(),
self.prediction_mode.get(),
&D.configs,
)
{
let alts = self.get_conflicting_alts(local.scratch(), &D.configs);
D.prediction = alts.iter().next().unwrap() as i32;
D.configs.set_conflicting_alts(alts);
D.requires_full_context = true;
D.is_accept_state = true;
}
if D.is_accept_state && D.configs.has_semantic_context() {
let decision_state = self.atn().decision_to_state[local.dfa_ref.decision as usize];
self.predicate_dfa_state(local.scratch(), &mut D, &decision_state);
if !D.predicates.is_empty() {
D.prediction = INVALID_ALT
}
}
let dfa_ref = local.dfa_ref;
let D = self.add_dfastate(dfa_ref, D)?;
self.add_dfaedge(dfa_ref, previousD, t, D);
Ok(D)
}
fn predicate_dfa_state<'scratch>(
&self,
scratch: &'scratch bumpalo::Bump,
proposed_state: &mut ProposedDFAState<'scratch, MutableATNConfigSet<'scratch>>,
decision_state: &ATNState,
) {
let nalts = decision_state.get_transitions().len();
let alts_to_collect_preds_from =
self.get_conflicting_alts_or_unique_alt(&proposed_state.configs);
let alt_to_pred = self.get_preds_for_ambig_alts(
scratch,
&alts_to_collect_preds_from,
&proposed_state.configs,
nalts,
);
if let Some(alt_to_pred) = alt_to_pred {
proposed_state.predicates =
self.get_predicate_predictions(scratch, &alts_to_collect_preds_from, alt_to_pred);
proposed_state.prediction = INVALID_ALT;
} else {
proposed_state.prediction = alts_to_collect_preds_from
.iter()
.next()
.unwrap_or(0 )
as i32;
}
}
fn exec_atn_with_full_context<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
s0: MutableATNConfigSet<'scratch>,
) -> Result<i32, ANTLRError>
where
'input: 'arena,
'sim: 'scratch,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let full_ctx = true;
let mut found_exact_ambig = false;
let mut prev = s0;
local.input().seek(self.start_index.get());
let mut t = local.input().la(1);
let mut predicted_alt;
loop {
let reach = self.compute_reach_set(prev.get_items(), t, full_ctx, local);
prev = match reach {
None => {
local.input().seek(self.start_index.get());
let alt = self
.get_syn_valid_or_sem_invalid_alt_that_finished_decision_entry_rule(
prev.get_items(),
prev.full_context(),
local,
);
if alt != INVALID_ALT {
return Ok(alt);
}
return Err(self.no_viable_alt(local, self.start_index.get()));
}
Some(x) => x,
};
let alt_sub_sets = get_conflicting_alt_subsets(local.scratch(), &prev);
prev.set_unique_alt(self.get_unique_alt(&prev));
if prev.get_unique_alt() != INVALID_ALT {
predicted_alt = prev.get_unique_alt();
break;
}
if self.prediction_mode.get() != PredictionMode::LL_EXACT_AMBIG_DETECTION {
predicted_alt = resolves_to_just_one_viable_alt(alt_sub_sets.values());
if predicted_alt != INVALID_ALT {
break;
}
} else if all_subsets_conflict(alt_sub_sets.values())
&& all_subsets_equal(alt_sub_sets.values())
{
found_exact_ambig = true;
predicted_alt = get_single_viable_alt(alt_sub_sets.values());
break;
}
if t != TOKEN_EOF {
local.input().consume();
t = local.input().la(1);
}
}
let dfa = local.dfa_ref;
if prev.get_unique_alt() != INVALID_ALT {
self.report_context_sensitivity(
dfa,
predicted_alt,
&prev,
self.start_index.get(),
local.input().index(),
local.parser,
);
return Ok(predicted_alt);
}
self.report_ambiguity(
dfa,
self.start_index.get(),
local.input().index(),
found_exact_ambig,
&prev.get_alts(),
&prev,
local.parser,
);
Ok(predicted_alt)
}
fn compute_reach_set<'a, 'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
closure: impl Iterator<Item = &'a ATNConfig<'scratch>>,
t: i32,
full_ctx: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> Option<MutableATNConfigSet<'scratch>>
where
'scratch: 'a,
'input: 'arena,
'sim: 'scratch,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let mut intermediate = MutableATNConfigSet::new(local.scratch(), full_ctx);
let mut skipped_stop_states = bumpalo::collections::Vec::new_in(local.scratch());
for c in closure {
let state = c.get_state();
if state.state_type() == ATNStateType::RuleStop {
assert!(c.get_context().unwrap().is_empty());
if full_ctx || t == TOKEN_EOF {
skipped_stop_states.push(c);
}
continue;
}
for tr in state.get_transitions() {
self.get_reachable_target(tr, t).map(|target| {
let added = c.clone().with_state(target);
intermediate.add_cached(added, local.merge_cache)
});
}
}
let mut look_to_end_of_rule = false;
let mut reach = if skipped_stop_states.is_empty()
&& t != TOKEN_EOF
&& (intermediate.length() == 1 || self.get_unique_alt(&intermediate) != INVALID_ALT)
{
look_to_end_of_rule = true;
intermediate
} else {
let mut reach = MutableATNConfigSet::new(local.scratch(), full_ctx);
let mut closure_busy = HashSet::new_in(local.scratch());
for c in intermediate.into_iter() {
let treat_eofas_epsilon = t == TOKEN_EOF;
self.closure(
c,
&mut reach,
&mut closure_busy,
false,
full_ctx,
treat_eofas_epsilon,
local,
);
}
reach
};
if t == TOKEN_EOF {
reach = self.remove_all_configs_not_in_rule_stop_state(
reach,
look_to_end_of_rule,
local.merge_cache,
);
}
if !skipped_stop_states.is_empty()
&& (!full_ctx || !Self::has_config_in_rule_stop_state(&reach))
{
for c in skipped_stop_states {
reach.add_cached(c.clone(), local.merge_cache);
}
}
if reach.is_empty() {
return None;
}
Some(reach)
}
fn has_config_in_rule_stop_state(configs: &MutableATNConfigSet) -> bool {
configs
.get_items()
.any(|c| c.get_state().state_type() == ATNStateType::RuleStop)
}
fn all_configs_in_rule_stop_state(configs: &MutableATNConfigSet) -> bool {
configs
.get_items()
.all(|c| c.get_state().state_type() == ATNStateType::RuleStop)
}
fn remove_all_configs_not_in_rule_stop_state<'a>(
&self,
configs: MutableATNConfigSet<'a>,
look_to_end_of_rule: bool,
merge_cache: &mut MergeCache<'a>,
) -> MutableATNConfigSet<'a> {
if Self::all_configs_in_rule_stop_state(&configs) {
return configs;
}
let mut result = MutableATNConfigSet::new(merge_cache.scratch, configs.full_context());
for c in configs.into_iter() {
let state = c.get_state();
if state.state_type() == ATNStateType::RuleStop {
result.add_cached(c, merge_cache);
continue;
}
if look_to_end_of_rule && state.has_epsilon_only_transitions() {
let next_tokens = self.atn().next_tokens(&state);
if next_tokens.contains(TOKEN_EPSILON) {
let end_of_rule_state =
self.atn().rule_to_stop_state[state.get_rule_index() as usize];
result.add_cached(c.clone().with_state(end_of_rule_state), merge_cache);
}
}
}
result
}
fn compute_start_state<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
a: ATNStateRef,
initial_ctx: PredictionContextRef<'scratch>,
full_ctx: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> MutableATNConfigSet<'scratch>
where
'input: 'arena,
'sim: 'scratch,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let mut configs = MutableATNConfigSet::new(local.scratch(), full_ctx);
for (i, tr) in a.get_transitions().iter().enumerate() {
let target = tr.get_target();
let c = ATNConfig::new(target, (i + 1) as i32, Some(initial_ctx));
let mut closure_busy = HashSet::new_in(local.scratch());
self.closure(
c,
&mut configs,
&mut closure_busy,
true,
full_ctx,
false,
local,
);
}
configs
}
fn apply_precedence_filter<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
configs: &MutableATNConfigSet<'scratch>,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> MutableATNConfigSet<'scratch>
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let mut states_from_alt1 = HashMap::new_in(local.scratch());
let mut config_set = MutableATNConfigSet::new(local.scratch(), configs.full_context());
for config in configs.get_items() {
if config.get_alt() != 1 {
continue;
}
let updated_sem_ctx = config.semantic_context().eval_precedence(
local.scratch(),
local.parser,
local.outer_context(),
);
if let Some(updated_sem_ctx) = updated_sem_ctx {
states_from_alt1.insert(config.get_state(), config.get_context());
if updated_sem_ctx != config.semantic_context() {
config_set.add_cached(
ATNConfig::new(config.get_state(), config.get_alt(), config.get_context())
.with_semantic_context(
local.merge_cache.alloc(updated_sem_ctx.clone()),
),
local.merge_cache,
);
} else {
config_set.add_cached(config.clone(), local.merge_cache);
}
}
}
for config in configs.get_items() {
if config.get_alt() == 1 {
continue;
}
if !config.is_precedence_filter_suppressed() {
if let Some(context) = states_from_alt1.get(&config.get_state()) {
if *context == config.get_context() {
continue;
}
}
}
config_set.add(config.clone());
}
config_set
}
fn get_reachable_target(&self, trans: &Transition, ttype: i32) -> Option<ATNStateRef> {
if trans.matches(ttype, 0, self.atn().max_token_type) {
return Some(trans.get_target());
}
None
}
fn get_preds_for_ambig_alts<'scratch>(
&self,
scratch: &'scratch bumpalo::Bump,
ambig_alts: &BitSet,
configs: &MutableATNConfigSet<'scratch>,
nalts: usize,
) -> Option<Vec<SemanticContext<'scratch>>> {
let mut alt_to_pred = bumpalo::collections::Vec::with_capacity_in(nalts + 1, scratch);
alt_to_pred.resize(nalts + 1, None);
for c in configs.get_items() {
let alt = c.get_alt() as usize;
if ambig_alts.contains(alt) {
alt_to_pred[alt] = Some(SemanticContext::or(
scratch,
alt_to_pred[alt].as_ref(),
Some(c.semantic_context()),
));
}
}
let alt_to_pred: Vec<SemanticContext> = alt_to_pred
.into_iter()
.map(|it| {
if let Some(inner) = it {
inner
} else {
SemanticContext::NONE
}
})
.collect();
let npred_alts = alt_to_pred
.iter()
.filter(|it| **it != SemanticContext::NONE)
.count();
if npred_alts == 0 {
return None;
}
Some(alt_to_pred)
}
fn get_predicate_predictions<'scratch>(
&self,
scratch: &'scratch bumpalo::Bump,
ambig_alts: &BitSet,
alt_to_pred: Vec<SemanticContext<'scratch>>,
) -> &'scratch [PredPrediction<'scratch>] {
let mut pairs = bumpalo::collections::Vec::with_capacity_in(alt_to_pred.len(), scratch);
let mut contains_predicate = false;
for (i, pred) in alt_to_pred.into_iter().enumerate().skip(1) {
if pred != SemanticContext::NONE {
contains_predicate = true
}
if ambig_alts.contains(i) {
pairs.push(PredPrediction {
alt: i as i32,
pred,
})
}
}
if !contains_predicate {
return &[];
}
pairs.into_bump_slice()
}
fn get_syn_valid_or_sem_invalid_alt_that_finished_decision_entry_rule<
'a,
'input,
'arena,
'scratch,
'cache,
TF,
P,
>(
&self,
configs: impl Iterator<Item = &'a ATNConfig<'scratch>>,
full_context: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> i32
where
'scratch: 'a,
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let (sem_valid_configs, sem_invalid_configs) =
self.split_according_to_semantic_validity(configs, full_context, local);
let alt = self.get_alt_that_finished_decision_entry_rule(&sem_valid_configs);
if alt != INVALID_ALT {
return alt;
}
if !sem_invalid_configs.is_empty() {
let alt = self.get_alt_that_finished_decision_entry_rule(&sem_invalid_configs);
if alt != INVALID_ALT {
return alt;
}
}
INVALID_ALT
}
fn split_according_to_semantic_validity<'a, 'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
configs: impl Iterator<Item = &'a ATNConfig<'scratch>>,
full_context: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> (MutableATNConfigSet<'scratch>, MutableATNConfigSet<'scratch>)
where
'scratch: 'a,
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let mut succeeded = MutableATNConfigSet::new(local.scratch(), full_context);
let mut failed = MutableATNConfigSet::new(local.scratch(), full_context);
for c in configs {
let clone = c.clone();
if c.semantic_context() != &SemanticContext::NONE {
let predicate_eval_result =
self.eval_predicate(local, c.semantic_context(), c.get_alt(), full_context);
if predicate_eval_result {
succeeded.add(clone);
} else {
failed.add(clone);
}
} else {
succeeded.add(clone);
}
}
(succeeded, failed)
}
fn get_alt_that_finished_decision_entry_rule(&self, configs: &MutableATNConfigSet) -> i32 {
let mut min_alt = i32::MAX;
for c in configs.get_items() {
let has_empty_path = c.get_context().map(|x| x.has_empty_path()) == Some(true);
let is_stop = c.get_state().state_type() == ATNStateType::RuleStop;
if c.get_reaches_into_outer_context() > 0 || (is_stop && has_empty_path) {
min_alt = min_alt.min(c.get_alt());
}
}
if min_alt == i32::MAX {
INVALID_ALT
} else {
min_alt
}
}
fn eval_semantic_context<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
pred_predictions: &'sim [PredPrediction<'sim>],
complete: bool,
) -> BitSet
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let mut predictions = BitSet::new();
for pred in pred_predictions {
if pred.pred == SemanticContext::NONE {
predictions.insert(pred.alt as usize);
if !complete {
break;
}
continue;
}
let full_ctx = false;
let predicate_evaluation_result =
self.eval_predicate(local, &pred.pred, pred.alt, full_ctx);
if predicate_evaluation_result {
predictions.insert(pred.alt as usize);
if !complete {
break;
}
}
}
predictions
}
fn eval_predicate<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
pred: &SemanticContext,
_alt: i32,
_full_ctx: bool,
) -> bool
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
pred.evaluate(local.parser, local.outer_context)
}
#[allow(clippy::too_many_arguments)]
fn closure<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
config: ATNConfig<'scratch>,
configs: &mut MutableATNConfigSet<'scratch>,
closure_busy: &mut HashSet<ATNConfig<'scratch>, DefaultHashBuilder, &bumpalo::Bump>,
collect_predicates: bool,
full_ctx: bool,
treat_eofas_epsilon: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let initial_depth = 0;
self.closure_checking_stop_state(
config,
configs,
closure_busy,
collect_predicates,
full_ctx,
initial_depth,
treat_eofas_epsilon,
local,
);
assert!(!full_ctx || !configs.get_dips_into_outer_context())
}
#[allow(clippy::too_many_arguments)]
fn closure_checking_stop_state<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
mut config: ATNConfig<'scratch>,
configs: &mut MutableATNConfigSet<'scratch>,
closure_busy: &mut HashSet<ATNConfig<'scratch>, DefaultHashBuilder, &bumpalo::Bump>,
collect_predicates: bool,
full_ctx: bool,
depth: i32,
treat_eofas_epsilon: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
if config.get_state().state_type() == ATNStateType::RuleStop {
if !config.get_context().unwrap().is_empty() {
config.get_context().unwrap().run(|temp| {
if temp.get_return_state(temp.length() - 1) == ATNStateRef::invalid() {
if full_ctx {
let new_config = config
.clone()
.with_state(config.get_state())
.with_prediction_context(Some(PredictionContextRef::new_empty()));
configs.add_cached(new_config, local.merge_cache);
} else {
self.closure_work(
config.clone(),
configs,
closure_busy,
collect_predicates,
full_ctx,
depth,
treat_eofas_epsilon,
local,
)
}
}
});
let context = config.take_context();
for i in 0..context.length() {
if context.get_return_state(i) == ATNStateRef::invalid() {
if i != context.length() - 1 {
panic!("EMPTY_RETURN_STATE is not last for some reason, please report error")
}
continue;
}
let return_state = context.get_return_state(i) as ATNStateRef;
let new_ctx = context.get_parent(i);
let mut c = ATNConfig::new(return_state, config.get_alt(), new_ctx)
.with_semantic_context(config.semantic_context());
c.set_reaches_into_outer_context(config.get_reaches_into_outer_context());
assert!(depth > i32::MIN);
self.closure_checking_stop_state(
c,
configs,
closure_busy,
collect_predicates,
full_ctx,
depth - 1,
treat_eofas_epsilon,
local,
)
}
return;
} else if full_ctx {
configs.add_cached(config, local.merge_cache);
return;
}
}
self.closure_work(
config,
configs,
closure_busy,
collect_predicates,
full_ctx,
depth,
treat_eofas_epsilon,
local,
)
}
#[allow(clippy::too_many_arguments)]
fn closure_work<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
config: ATNConfig<'scratch>,
configs: &mut MutableATNConfigSet<'scratch>,
closure_busy: &mut HashSet<ATNConfig<'scratch>, DefaultHashBuilder, &bumpalo::Bump>,
collect_predicates: bool,
full_ctx: bool,
depth: i32,
treat_eofas_epsilon: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let p = config.get_state();
if !p.has_epsilon_only_transitions() {
configs.add_cached(config.clone(), local.merge_cache);
}
for (i, tr) in p.get_transitions().iter().enumerate() {
if i == 0 && self.can_drop_loop_entry_edge_in_left_recursive_rule(&config) {
continue;
}
let continue_collecting =
!matches!(tr.transition_type(), TransitionType::Action) && collect_predicates;
let c = self.get_epsilon_target(
&config,
tr,
continue_collecting,
depth == 0,
full_ctx,
treat_eofas_epsilon,
local,
);
if let Some(mut c) = c {
let mut new_depth = depth;
if config.get_state().state_type() == ATNStateType::RuleStop {
assert!(!full_ctx);
let dfa = local.dfa_ref;
if dfa.is_precedence_dfa() {
let outermost_precedence_return = tr
.try_as::<crate::transition::EpsilonTransition>()
.unwrap()
.outermost_precedence_return();
if outermost_precedence_return == dfa.atn_start_state.get_rule_index() {
c.set_precedence_filter_suppressed(true);
}
}
c.reaches_into_outer_context += 1;
if !closure_busy.insert(c.clone()) {
continue;
}
configs.set_dips_into_outer_context(true);
assert!(new_depth > i32::MIN);
new_depth -= 1;
} else {
if !tr.is_epsilon() && !closure_busy.insert(c.clone()) {
continue;
}
if matches!(tr.transition_type(), TransitionType::Rule) && new_depth >= 0 {
new_depth += 1
}
}
self.closure_checking_stop_state(
c,
configs,
closure_busy,
continue_collecting,
full_ctx,
new_depth,
treat_eofas_epsilon,
local,
)
};
}
}
fn can_drop_loop_entry_edge_in_left_recursive_rule(&self, _config: &ATNConfig) -> bool {
let state = _config.get_state();
if let Some(StarLoopEntryState { is_precedence, .. }) = state.try_as() {
if !is_precedence
|| _config.get_context().unwrap().is_empty()
|| _config.get_context().unwrap().has_empty_path()
{
return false;
}
} else {
return false;
}
let pred_ctx = _config.get_context().unwrap();
let ctx_len = pred_ctx.length();
for i in 0..ctx_len {
let return_state = pred_ctx.get_return_state(i);
if return_state.get_rule_index() != state.get_rule_index() {
return false;
}
}
let decision_start_state = state.get_transitions()[0].get_target();
let block_end_state = decision_start_state
.get_decision_end_state()
.expect("should be decision state");
for i in 0..ctx_len {
let return_state = pred_ctx.get_return_state(i);
if return_state.get_transitions().len() != 1
|| !return_state.get_transitions()[0].is_epsilon()
{
return false;
}
let return_state_target = return_state.get_transitions()[0].get_target();
if return_state.get_state_type_id() == ATNSTATE_BLOCK_END
&& return_state_target == state
{
continue;
}
if return_state == block_end_state {
continue;
}
if return_state_target == block_end_state {
continue;
}
if return_state_target.get_state_type_id() == ATNSTATE_BLOCK_END
&& return_state_target.get_transitions().len() == 1
&& return_state_target.get_transitions()[0].is_epsilon()
&& return_state_target.get_transitions()[0].get_target() == state
{
continue;
}
return false;
}
true
}
#[allow(clippy::too_many_arguments)]
fn get_epsilon_target<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
config: &ATNConfig<'scratch>,
t: &Transition,
collect_predicates: bool,
in_context: bool,
full_ctx: bool,
treat_eofas_epsilon: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> Option<ATNConfig<'scratch>>
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
match t.transition_type() {
TransitionType::Epsilon => Some(config.clone().with_state(t.get_target())),
TransitionType::Rule => Some(self.rule_transition(
config,
t.try_as::<RuleTransition>().unwrap(),
local.merge_cache,
)),
TransitionType::Predicate => self.pred_transition(
config,
t.try_as::<PredicateTransition>().unwrap(),
collect_predicates,
in_context,
full_ctx,
local,
),
TransitionType::Action => {
Some(self.action_transition(config, t.try_as::<ActionTransition>().unwrap()))
}
TransitionType::PrecedencePredicate => self.precedence_transition(
config,
t.try_as::<PrecedencePredicateTransition>().unwrap(),
collect_predicates,
in_context,
full_ctx,
local,
),
TransitionType::Atom | TransitionType::Set | TransitionType::Range => {
if treat_eofas_epsilon && t.matches(TOKEN_EOF, 0, 1) {
Some(config.clone().with_state(t.get_target()))
} else {
None
}
}
TransitionType::NotSet | TransitionType::Wildcard => None,
}
}
fn action_transition<'a>(&self, config: &ATNConfig<'a>, t: &ActionTransition) -> ATNConfig<'a> {
config.clone().with_state(t.get_target())
}
fn precedence_transition<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
config: &ATNConfig<'scratch>,
pt: &PrecedencePredicateTransition,
collect_predicates: bool,
in_context: bool,
full_ctx: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> Option<ATNConfig<'scratch>>
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
if collect_predicates && in_context {
if full_ctx {
let curr_pos = local.input().index();
local.input().seek(self.start_index.get());
let prec_succeeds = self.eval_predicate(
local,
local.scratch().alloc(pt.get_predicate().unwrap()) as &_,
config.get_alt(),
full_ctx,
);
local.input().seek(curr_pos);
if prec_succeeds {
return Some(config.clone().with_state(pt.get_target()));
}
} else {
let new_sem_ctx = SemanticContext::and(
local.scratch(),
Some(config.semantic_context()),
pt.get_predicate()
.map(|pred| local.scratch().alloc(pred) as &_),
);
return Some(
config
.clone()
.with_state(pt.get_target())
.with_semantic_context(local.scratch().alloc(new_sem_ctx)),
);
}
} else {
return Some(config.clone().with_state(pt.get_target()));
}
None
}
fn pred_transition<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
config: &ATNConfig<'scratch>,
pt: &PredicateTransition,
collect_predicates: bool,
in_context: bool,
full_ctx: bool,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
) -> Option<ATNConfig<'scratch>>
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
#[allow(clippy::nonminimal_bool)]
if collect_predicates && (!pt.is_ctx_dependent() || (pt.is_ctx_dependent() && in_context)) {
if full_ctx {
let curr_pos = local.input().index();
local.input().seek(self.start_index.get());
let prec_succeeds = self.eval_predicate(
local,
local.scratch().alloc(pt.get_predicate().unwrap()) as &_,
config.get_alt(),
full_ctx,
);
local.input().seek(curr_pos);
if prec_succeeds {
return Some(config.clone().with_state(pt.get_target()));
}
} else {
let new_sem_ctx = SemanticContext::and(
local.scratch(),
Some(config.semantic_context()),
pt.get_predicate()
.map(|pred| local.scratch().alloc(pred) as &_),
);
return Some(
config
.clone()
.with_state(pt.get_target())
.with_semantic_context(local.scratch().alloc(new_sem_ctx)),
);
}
} else {
return Some(config.clone().with_state(pt.get_target()));
}
None
}
fn rule_transition<'scratch>(
&self,
config: &ATNConfig<'scratch>,
t: &RuleTransition,
merge_cache: &mut MergeCache<'scratch>,
) -> ATNConfig<'scratch> {
assert!(config.get_context().is_some());
let new_ctx = PredictionContext::new_singleton(config.get_context(), t.follow_state);
config
.clone()
.with_state(t.get_target())
.with_prediction_context(Some(merge_cache.alloc(new_ctx)))
}
fn get_conflicting_alts<'scratch>(
&self,
scratch: &'scratch bumpalo::Bump,
configs: &MutableATNConfigSet<'scratch>,
) -> BitSet {
let altsets = get_conflicting_alt_subsets(scratch, configs);
get_alts(altsets.into_values())
}
fn get_conflicting_alts_or_unique_alt<'scratch>(
&self,
configs: &'scratch MutableATNConfigSet<'scratch>,
) -> Cow<'scratch, BitSet> {
if configs.get_unique_alt() != INVALID_ALT {
let mut bitset = BitSet::new();
bitset.insert(configs.get_unique_alt() as usize);
Cow::Owned(bitset)
} else {
Cow::Borrowed(configs.conflicting_alts())
}
}
fn no_viable_alt<'input, 'arena, 'scratch, 'cache, TF, P>(
&self,
local: &mut Local<'input, 'arena, 'sim, 'scratch, 'cache, TF, P>,
start_index: isize,
) -> ANTLRError
where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
let start_token = local.parser.get_input_stream().get(start_index);
let start_token = OwningToken::from(start_token as &dyn Token);
let offending_token = local.input().lt(1).unwrap();
let offending_token = OwningToken::from(offending_token as &dyn Token);
ANTLRError::no_alt_full(local.parser, start_token, offending_token)
}
fn get_unique_alt(&self, configs: &MutableATNConfigSet) -> i32 {
let mut alt = INVALID_ALT;
for c in configs.get_items() {
if alt == INVALID_ALT {
alt = c.get_alt()
} else if c.get_alt() != alt {
return INVALID_ALT;
}
}
alt
}
fn add_dfaedge(
&self,
dfa: &'sim DFA<'sim, ATNConfigSet<'sim>>,
from: &'sim DFAState<'sim, ATNConfigSet<'sim>>,
t: i32,
to: &'sim DFAState<'sim, ATNConfigSet<'sim>>,
) -> &'sim DFAState<'sim, ATNConfigSet<'sim>> {
if t < -1 || t > self.atn().max_token_type {
return to;
}
dfa.set_edge(from, (t + 1) as usize, to);
to
}
fn add_dfastate<'scratch>(
&self,
dfa: &'sim DFA<'sim, ATNConfigSet<'sim>>,
state: ProposedDFAState<'scratch, MutableATNConfigSet<'scratch>>,
) -> Result<&'sim DFAState<'sim, ATNConfigSet<'sim>>, ANTLRError> {
self.base.check_allocation_limit()?;
Ok(dfa.add_state(state, self))
}
fn report_attempting_full_context<'input, 'arena, TF, P>(
&self,
dfa: &DFA<'sim, ATNConfigSet<'sim>>,
conflicting_alts: &BitSet,
configs: &ATNConfigSet<'sim>,
start_index: isize,
stop_index: isize,
parser: &mut P,
) where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
parser
.get_error_lister_dispatch()
.report_attempting_full_context(
parser,
dfa,
start_index,
stop_index,
conflicting_alts,
configs,
)
}
fn report_context_sensitivity<'input, 'arena, 'scratch, TF, P>(
&self,
dfa: &DFA<'sim, ATNConfigSet<'sim>>,
prediction: i32,
configs: &MutableATNConfigSet<'scratch>,
start_index: isize,
stop_index: isize,
parser: &mut P,
) where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
parser
.get_error_lister_dispatch()
.report_context_sensitivity(parser, dfa, start_index, stop_index, prediction, configs)
}
#[allow(clippy::too_many_arguments)]
fn report_ambiguity<'input, 'arena, 'scratch, TF, P>(
&self,
dfa: &DFA<'sim, ATNConfigSet<'sim>>,
start_index: isize,
stop_index: isize,
exact: bool,
ambig_alts: &BitSet,
configs: &MutableATNConfigSet<'scratch>,
parser: &mut P,
) where
'input: 'arena,
TF: TokenFactory<'input, 'arena> + 'arena,
P: Parser<'input, 'arena, TF>,
{
parser.get_error_lister_dispatch().report_ambiguity(
parser,
dfa,
start_index,
stop_index,
exact,
ambig_alts,
configs,
)
}
}
impl<'sim> IATNSimulator<'sim, ATNConfigSet<'sim>> for ParserATNSimulator<'sim> {
fn shared_context_cache(&self) -> &'sim PredictionContextCache<'sim> {
self.base.shared_context_cache()
}
fn atn(&self) -> &'static ATN {
self.base.atn()
}
fn decision_to_dfa(&self, decision: usize) -> Option<&'sim DFA<'sim, ATNConfigSet<'sim>>> {
self.base.decision_to_dfa(decision)
}
}
pub(crate) struct MergeCache<'scratch> {
map: HashMap<
MergeKey<'scratch>,
PredictionContextRef<'scratch>,
NoopHasherBuilder,
&'scratch bumpalo::Bump,
>,
scratch: &'scratch bumpalo::Bump,
}
impl<'scratch> MergeCache<'scratch> {
pub fn new(scratch: &'scratch bumpalo::Bump) -> Self {
Self {
map: HashMap::with_hasher_in(NoopHasherBuilder {}, scratch),
scratch,
}
}
pub fn scratch(&self) -> &'scratch bumpalo::Bump {
self.scratch
}
pub fn alloc_vec<T>(&self, capacity: usize) -> bumpalo::collections::Vec<'scratch, T> {
bumpalo::collections::Vec::with_capacity_in(capacity, self.scratch)
}
pub fn alloc<T>(&self, value: T) -> &'scratch mut T {
self.scratch.alloc(value)
}
pub fn get(&self, key: &MergeKey) -> Option<PredictionContextRef<'scratch>> {
self.map.get(key).copied()
}
pub fn insert(&mut self, key: MergeKey<'scratch>, value: PredictionContextRef<'scratch>) {
self.map.insert(key, value);
}
}
#[derive(Eq)]
pub struct MergeKey<'scratch> {
pub left: PredictionContextRef<'scratch>,
pub right: PredictionContextRef<'scratch>,
}
impl PartialEq for MergeKey<'_> {
fn eq(&self, other: &Self) -> bool {
(self.left == other.left && self.right == other.right)
|| (self.left == other.right && self.right == other.left)
}
}
impl std::hash::Hash for MergeKey<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
let h1 = self.left.hash_code();
let h2 = self.right.hash_code();
let sum = (h1 as u64).wrapping_add(h2 as u64);
let product = (h1 as u64).wrapping_mul(h2 as u64);
let mut combined = sum ^ product.rotate_right(32);
combined = (combined ^ (combined >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
combined = (combined ^ (combined >> 27)).wrapping_mul(0x94d049bb133111eb);
state.write_u64(combined ^ (combined >> 31));
}
}
impl<'scratch> MergeKey<'scratch> {
pub fn new(
left: PredictionContextRef<'scratch>,
right: PredictionContextRef<'scratch>,
) -> Self {
Self { left, right }
}
pub fn reverse(self) -> Self {
Self {
left: self.right,
right: self.left,
}
}
}