summaryrefslogtreecommitdiff
path: root/nfa/src/default/regex.rs
diff options
context:
space:
mode:
Diffstat (limited to 'nfa/src/default/regex.rs')
-rw-r--r--nfa/src/default/regex.rs70
1 files changed, 65 insertions, 5 deletions
diff --git a/nfa/src/default/regex.rs b/nfa/src/default/regex.rs
index 1b1b325..9b5fab1 100644
--- a/nfa/src/default/regex.rs
+++ b/nfa/src/default/regex.rs
@@ -1,6 +1,9 @@
//! This file provides a default implementation of Regex.
-use graph::{error::Error as GError, ALGraph, ExtGraph, Graph, GraphLabel};
+use graph::{
+ adlist::ALGBuilderMut, builder::BuilderMut, error::Error as GError, ALGraph, ExtGraph, Graph,
+ GraphLabel,
+};
use crate::{desrec::DesRec, error::Error, Regex};
@@ -10,6 +13,7 @@ use graph_macro::Graph;
use receme::{algebra::Algebra, catana::Cata};
use std::{
+ borrow::BorrowMut,
collections::HashMap,
fmt::{Debug, Display, Write},
marker::PhantomData,
@@ -271,10 +275,8 @@ impl<T: GraphLabel> DefaultRegex<T> {
if !top.is_seen() {
stack.push(Seen(top.index()));
- if self.degree(top.index()).unwrap() > 1 {
- write!(result, "(")?;
- stack.push(Unseen(types.len() - 1));
- }
+ write!(result, "(")?;
+ stack.push(Unseen(types.len() - 1));
stack.extend(
self.graph
@@ -289,7 +291,11 @@ impl<T: GraphLabel> DefaultRegex<T> {
}
RegexType::Plus => {
if !top.is_seen() {
+ write!(result, "(")?;
+
stack.push(Seen(top.index()));
+ stack.push(Unseen(types.len() - 1));
+
stack.extend(
self.graph
.children_of(top.index())
@@ -303,7 +309,11 @@ impl<T: GraphLabel> DefaultRegex<T> {
}
RegexType::Optional => {
if !top.is_seen() {
+ write!(result, "(")?;
+
stack.push(Seen(top.index()));
+ stack.push(Unseen(types.len() - 1));
+
stack.extend(
self.graph
.children_of(top.index())
@@ -504,6 +514,56 @@ impl<T: GraphLabel> DefaultRegex<T> {
Ok(result)
}
+
+ /// Use a function transform the labels of a regular expression.
+ pub fn maps_to<S: GraphLabel, E>(
+ &self,
+ f: impl Fn(T) -> Result<S, E>,
+ ) -> Result<DefaultRegex<S>, E> {
+ let root = self.root();
+
+ let graph = self.internal_graph();
+
+ let types: Vec<RegexType<S>> = self
+ .types
+ .iter()
+ .map(|element| match element {
+ RegexType::Lit(value) => f(*value).map(RegexType::Lit),
+ RegexType::Kleene => Ok(RegexType::Kleene),
+ RegexType::Plus => Ok(RegexType::Plus),
+ RegexType::Optional => Ok(RegexType::Optional),
+ RegexType::Or => Ok(RegexType::Or),
+ RegexType::Paren => Ok(RegexType::Paren),
+ RegexType::Empty => Ok(RegexType::Empty),
+ })
+ .collect::<Result<_, E>>()?;
+
+ Ok(DefaultRegex { graph, types, root })
+ }
+
+ /// Append another regular expression to the end of this regular
+ /// expression.
+ pub fn append(&mut self, other: Self) {
+ if self.is_empty() {
+ // copy the other here
+ self.graph = other.graph;
+ self.types = other.types;
+ self.root = other.root;
+ } else if other.is_empty() {
+ // nothing to do
+ } else {
+ let mut builder_mut = ALGBuilderMut::from_graph_mut(self.graph.borrow_mut());
+
+ let old_len = builder_mut.nodes_len();
+
+ builder_mut.append(other.graph);
+
+ if let Some(root) = self.root {
+ // Deliberately ignore errors here.
+ let _ = builder_mut.add_edge(root, old_len, ());
+ }
+ }
+ }
}
impl<T: GraphLabel> Display for DefaultRegex<T> {