1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//! Module with the compiled lookahead type and functions.
use crate::{Lookahead, Result};
use super::{
compiled_dfa::CompiledDfa, parse_regex_syntax, CharClassID, CharacterClassRegistry, Nfa,
};
#[derive(Debug, Clone)]
pub(crate) struct CompiledLookahead {
/// The compiled DFA for the lookahead.
/// We need a box to break the cycle between CompiledDfa and CompiledLookahead.
pub(crate) nfa: Box<CompiledDfa>,
/// If the lookahead is positive or negative.
pub(crate) is_positive: bool,
}
impl CompiledLookahead {
/// Create a new compiled lookahead from a lookahead.
pub(crate) fn try_from_lookahead(
lookahead: &Lookahead,
character_class_registry: &mut CharacterClassRegistry,
) -> Result<Self> {
let Lookahead {
is_positive,
pattern,
} = lookahead;
let ast = parse_regex_syntax(pattern)?;
let nfa: Nfa = Nfa::try_from_ast(ast, character_class_registry)?;
let nfa = Box::new(nfa.into());
Ok(Self {
nfa,
is_positive: *is_positive,
})
}
/// Check if the lookahead constraints are met.
///
/// If the lookahead is positive, the function returns true if the input matches the lookahead.
/// Otherwise if the lookahead is negative, the function returns true if the input does not
/// match the lookahead.
pub(crate) fn satisfies_lookahead(
&mut self,
input: &str,
char_indices: std::str::CharIndices,
match_char_class: &(dyn Fn(CharClassID, char) -> bool + 'static),
) -> bool {
if self
.nfa
.find_from(input, char_indices, match_char_class)
.is_some()
{
self.is_positive
} else {
!self.is_positive
}
}
}
impl std::fmt::Display for CompiledLookahead {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} lookahead: {}",
if self.is_positive {
"Positive"
} else {
"Negative"
},
self.nfa
)
}
}