summaryrefslogtreecommitdiff
path: root/src/nfa.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/nfa.rs')
-rw-r--r--src/nfa.rs151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/nfa.rs b/src/nfa.rs
new file mode 100644
index 0000000..953e823
--- /dev/null
+++ b/src/nfa.rs
@@ -0,0 +1,151 @@
+use std::collections::HashMap;
+
+enum RegexParseError {
+
+}
+
+/// guaranteed to have at least 2 states
+/// state 0 is always the start state
+/// state 1 is always the accept state
+struct Nfa {
+ num_states: usize,
+ transitions: HashMap<(usize, char), Vec<usize>>
+}
+
+/// Nfa builder using Thompson's construction
+/// Invariant: state 0 is always the start state
+/// Invariant: state 1 is always the end state
+/// Invariant: start state has no incoming edges
+/// Invariant: end state has no outgoing edges
+impl Nfa {
+
+ fn from_regex(pattern: &str) -> Result<Self, RegexParseError> {
+ todo!();
+ }
+
+ fn empty() -> Self {
+ Self {
+ num_states: 2,
+ transitions: HashMap::from_iter([ ((0, '\0'), vec![1]) ])
+ }
+ }
+
+ fn from_literals(cs: impl IntoIterator<Item=char>) -> Self {
+ Self {
+ num_states: 2,
+ transitions: HashMap::from_iter(
+ cs.into_iter().map(|c| ((0, c), vec![1]))
+ )
+ }
+ }
+
+ fn from_union(lhs: Self, rhs: Self) -> Self {
+ let offset_lhs = 2;
+ let offset_rhs = 2 + lhs.num_states;
+
+ let new_transitions = [
+ ((0, '\0'), vec![offset_lhs, offset_rhs]),
+ ((offset_lhs + 1, '\0'), vec![1]),
+ ((offset_rhs + 1, '\0'), vec![1])
+ ].into_iter();
+
+ let lhs_transitions = lhs.transitions.into_iter()
+ .map(|((q_old, c), qs_new)| {
+ let new_input = (q_old + offset_lhs, c);
+ let new_output = qs_new.into_iter().map(|q| q + offset_lhs).collect();
+ (new_input, new_output)
+ });
+
+ let rhs_transitions = rhs.transitions.into_iter()
+ .map(|((q_old, c), qs_new)| {
+ let new_input = (q_old + offset_rhs, c);
+ let new_output = qs_new.into_iter().map(|q| q + offset_rhs).collect();
+ (new_input, new_output)
+ });
+
+ Self {
+ num_states: lhs.num_states + rhs.num_states + 2,
+ transitions: HashMap::from_iter(
+ new_transitions.chain(lhs_transitions).chain(rhs_transitions)
+ )
+ }
+ }
+
+ fn from_concat(lhs: Self, rhs: Self) -> Self {
+ let offset_lhs = 2;
+ let offset_rhs = 2 + lhs.num_states;
+
+ let new_transitions = [
+ ((0, '\0'), vec![offset_lhs]),
+ ((offset_lhs + 1, '\0'), vec![offset_rhs]),
+ ((offset_rhs + 1, '\0'), vec![1]),
+ ].into_iter();
+
+ let lhs_transitions = lhs.transitions.into_iter()
+ .map(|((q_old, c), qs_new)| {
+ let new_input = (q_old + offset_lhs, c);
+ let new_output = qs_new.into_iter().map(|q| q + offset_lhs).collect();
+ (new_input, new_output)
+ });
+
+ let rhs_transitions = rhs.transitions.into_iter()
+ .map(|((q_old, c), qs_new)| {
+ let new_input = (q_old + offset_rhs, c);
+ let new_output = qs_new.into_iter().map(|q| q + offset_rhs).collect();
+ (new_input, new_output)
+ });
+
+ Self {
+ num_states: lhs.num_states + rhs.num_states + 2,
+ transitions: HashMap::from_iter(
+ new_transitions.chain(lhs_transitions).chain(rhs_transitions)
+ )
+ }
+ }
+
+ fn from_star(inner: Self) -> Self {
+ const INNER_OFFSET: usize = 2;
+
+ let new_transitions = [
+ ((0, '\0'), vec![1, INNER_OFFSET]),
+ ((INNER_OFFSET + 1, '\0'), vec![INNER_OFFSET, 1]),
+ ].into_iter();
+
+ let inner_transitions = inner.transitions.into_iter()
+ .map(|((q_old, c), qs_new)| {
+ let new_input = (q_old + INNER_OFFSET, c);
+ let new_output = qs_new.into_iter().map(|q| q + INNER_OFFSET).collect();
+ (new_input, new_output)
+ });
+
+ Self {
+ num_states: inner.num_states + 2,
+ transitions: HashMap::from_iter(
+ new_transitions.chain(inner_transitions)
+ )
+ }
+ }
+
+ fn from_plus(inner: Self) -> Self {
+ const INNER_OFFSET: usize = 2;
+
+ let new_transitions = [
+ ((0, '\0'), vec![INNER_OFFSET]),
+ ((INNER_OFFSET + 1, '\0'), vec![INNER_OFFSET, 1]),
+ ].into_iter();
+
+ let inner_transitions = inner.transitions.into_iter()
+ .map(|((q_old, c), qs_new)| {
+ let new_input = (q_old + INNER_OFFSET, c);
+ let new_output = qs_new.into_iter().map(|q| q + INNER_OFFSET).collect();
+ (new_input, new_output)
+ });
+
+ Self {
+ num_states: inner.num_states + 2,
+ transitions: HashMap::from_iter(
+ new_transitions.chain(inner_transitions)
+ )
+ }
+ }
+}