From 9a317e56f8a6126583f7d0c431bf878d9b1fe7b1 Mon Sep 17 00:00:00 2001
From: JSDurand <mmemmew@gmail.com>
Date: Sat, 8 Jul 2023 12:30:21 +0800
Subject: Finished the Emacs binding.

Now the binding part is finished.

What remains is a bug encountered when planting a fragment to the
forest which intersects a packed node, which would lead to invalid
forests.  This will also cause problem when planting a packed
fragment, but until now my testing grammars do not produce packed
fragments, so this problem is not encountered yet.

I am still figuring out efficient ways to solve this problem.
---
 nfa/src/default/regex.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 65 insertions(+), 5 deletions(-)

(limited to 'nfa/src')

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> {
-- 
cgit v1.2.3-18-g5258