Skip to content

Commit

Permalink
Fix expression quantification in NFA compilation
Browse files Browse the repository at this point in the history
Expression quantification is now implemented with a quantification
"guard" state. This decides whether or not to (re)parse the expression
and/or continue to the next expresssion.
  • Loading branch information
exellentcoin26 committed Jul 19, 2023
1 parent 057ea19 commit e78bb6c
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 22 deletions.
48 changes: 33 additions & 15 deletions src/fsm/nfa/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ impl Nfa {
NfaBuilder::new(start_state_final)
}

pub(super) fn get_state(&self, id: StateId) -> &State {
self.states
.iter()
.find(|s| s.id == id)
.expect("requested state does not exist")
}

fn get_final_states(&self) -> impl Iterator<Item = &State> + '_ {
self.states.iter().filter(|s| s.fin)
}
Expand Down Expand Up @@ -309,6 +316,22 @@ impl Compiler {
self.nfa.build()
}

fn insert_quantifier_state(
&mut self,
quantifier: QuantifierKind,
start_state: StateId,
end_state: StateId,
) -> StateId {
let quantifier_state = self
.nfa
.add_state_with_quantifier(false, (quantifier, end_state));

self.nfa
.add_transition(start_state, quantifier_state, Input::Eps);

quantifier_state
}

#[allow(clippy::only_used_in_recursion)]
fn expr(&mut self, expr: &ExprKind, start: StateId, end: StateId) {
match expr {
Expand Down Expand Up @@ -346,15 +369,13 @@ impl Compiler {
//
// Quantification can be implemented using an extra gateway state and a

let start = match quantifier {
let (start, end) = match quantifier {
Some(quantifier) => {
let new_start = self
.nfa
.add_state_with_quantifier(false, (*quantifier, end));
self.nfa.add_transition(start, new_start, Input::Eps);
new_start
let quantifier_state =
self.insert_quantifier_state(*quantifier, start, end);
(quantifier_state, quantifier_state)
}
None => start,
None => (start, end),
};

self.nfa
Expand All @@ -367,16 +388,13 @@ impl Compiler {
// wrapper and redo the expression when the quantification is still or not yet
// valid.

let start = match quantifier {
let (start, end) = match quantifier {
Some(quantifier) => {
let new_start = self
.nfa
.add_state_with_quantifier(false, (*quantifier, end));
// Transition from the expression start state to the quantifier state
self.nfa.add_transition(start, new_start, Input::Eps);
new_start
let quantifier_state =
self.insert_quantifier_state(*quantifier, start, end);
(quantifier_state, quantifier_state)
}
None => start,
None => (start, end),
};

self.expr(expr, start, end);
Expand Down
8 changes: 1 addition & 7 deletions src/fsm/nfa/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,7 @@ impl Simulateable for NfaSimulator<'_> {
.iter()
.filter_map(|(expected, states)| {
if expected.can_take(input) {
Some(states.iter().map(|state_id| {
self.nfa
.states
.iter()
.find(|state| state.id == *state_id)
.expect("state should always exist, otherwise the NFA is invalid")
}))
Some(states.iter().map(|state_id| self.nfa.get_state(*state_id)))
} else {
None
}
Expand Down

0 comments on commit e78bb6c

Please sign in to comment.