lib/
fsm.rs

1use super::FSMRc;
2use std::collections::{HashMap, HashSet};
3use std::str::pattern::Pattern;
4
5use super::FSMLock;
6use super::get_id;
7use crate::NameShortener;
8
9pub type FSMNodeWrapper = FSMRc<FSMLock<FSMNode>>;
10trait FSMOp = FnMut(&mut HashSet<NodeId>, &FSMNodeWrapper, &FSMNodeWrapper, &mut isize) -> bool;
11trait FSMUnsafe = Fn(&mut HashSet<NodeId>, &FSMNode, &FSMNode, &mut isize) -> bool;
12pub trait CycleAwareOp<T> {
13    fn walk_fsm(&self, op: &mut T, greedy: bool, depth_search: bool) -> Option<FSMNodeWrapper>;
14    fn walk_fsm_internal(
15        &self,
16        op: &mut T,
17        greedy: bool,
18        depth_search: bool,
19        visited_nodes: &mut HashSet<NodeId>,
20    ) -> Option<FSMNodeWrapper>;
21    fn walk_fsm_breadth(&self, op: &mut T, greedy: bool) -> Option<FSMNodeWrapper> {
22        self.walk_fsm(op, greedy, false)
23    }
24    fn walk_fsm_depth(&self, op: &mut T, greedy: bool) -> Option<FSMNodeWrapper> {
25        self.walk_fsm(op, greedy, true)
26    }
27    // no this is not a workaround I swear
28    // Good things *can* come out of having something like this as constructs like Repeats need
29    // to loop back
30    fn walk_fsm_allow_cycle_to_self(
31        &self,
32        op: &mut T,
33        greedy: bool,
34        depth_search: bool,
35    ) -> Option<FSMNodeWrapper> {
36        self.walk_fsm_internal(op, greedy, depth_search, &mut HashSet::new())
37    }
38}
39
40// TODO: refactor
41impl<T> CycleAwareOp<T> for FSMNode
42where
43    T: FSMUnsafe,
44{
45    fn walk_fsm_internal(
46        &self,
47        op: &mut T,
48        greedy: bool,
49        depth_search: bool,
50        visited_nodes: &mut HashSet<NodeId>,
51    ) -> Option<FSMNodeWrapper> {
52        let children = self.children.clone();
53        let mut c_idx = 0;
54        for child in children.iter() {
55            if !visited_nodes.contains(&child.borrow().id) {
56                visited_nodes.insert(child.borrow().id);
57                if depth_search {
58                    if (greedy || child.borrow().is_null())
59                        && let Some(child) = child.borrow().walk_fsm_internal(
60                            op,
61                            greedy,
62                            depth_search,
63                            visited_nodes,
64                        )
65                    {
66                        return Some(child);
67                    }
68                }
69                if op(visited_nodes, self, &child.borrow(), &mut c_idx) {
70                    return Some(child.clone());
71                }
72            }
73            c_idx += 1;
74        }
75        if !depth_search {
76            for child in children.iter() {
77                if (greedy || child.borrow().is_null())
78                    && let Some(child) =
79                        child
80                            .borrow()
81                            .walk_fsm_internal(op, greedy, depth_search, visited_nodes)
82                {
83                    return Some(child);
84                }
85            }
86        }
87        None
88    }
89    fn walk_fsm(&self, op: &mut T, greedy: bool, depth_search: bool) -> Option<FSMNodeWrapper> {
90        let mut visisted_nodes = HashSet::new();
91        visisted_nodes.insert(self.id);
92        self.walk_fsm_internal(op, greedy, depth_search, &mut visisted_nodes)
93    }
94}
95
96impl<T> CycleAwareOp<T> for FSMNodeWrapper
97where
98    T: FSMOp,
99{
100    fn walk_fsm_internal(
101        &self,
102        op: &mut T,
103        greedy: bool,
104        depth_search: bool,
105        visited_nodes: &mut HashSet<NodeId>,
106    ) -> Option<FSMNodeWrapper> {
107        let children = self.borrow().children.clone();
108        let mut c_idx = 0;
109        for child in children.iter() {
110            if !visited_nodes.contains(&child.borrow().id) {
111                if depth_search {
112                    visited_nodes.insert(child.borrow().id);
113                    if (greedy || child.borrow().is_null())
114                        && let Some(child) =
115                            child.walk_fsm_internal(op, greedy, depth_search, visited_nodes)
116                    {
117                        return Some(child);
118                    }
119                }
120                if op(visited_nodes, self, child, &mut c_idx) {
121                    return Some(child.clone());
122                }
123            }
124            c_idx += 1;
125        }
126        if !depth_search {
127            for child in children.iter() {
128                if !visited_nodes.contains(&child.borrow().id) {
129                    visited_nodes.insert(child.borrow().id);
130                    if (greedy || child.borrow().is_null())
131                        && let Some(child) =
132                            child.walk_fsm_internal(op, greedy, depth_search, visited_nodes)
133                    {
134                        return Some(child);
135                    }
136                }
137            }
138        }
139        None
140    }
141    fn walk_fsm(&self, op: &mut T, greedy: bool, depth_search: bool) -> Option<FSMNodeWrapper> {
142        let mut visisted_nodes = HashSet::new();
143        visisted_nodes.insert(self.borrow().id);
144        self.walk_fsm_internal(op, greedy, depth_search, &mut visisted_nodes)
145    }
146}
147
148#[derive(Debug, Clone, PartialEq)]
149pub struct Keyword {
150    pub short: String,
151    pub expanded: String,
152    pub closing_token: Option<String>,
153}
154
155impl Keyword {
156    pub fn new(expanded: String, closing_token: Option<String>) -> Self {
157        Self {
158            short: expanded.chars().nth(0).unwrap().to_string(),
159            expanded,
160            closing_token,
161        }
162    }
163}
164
165impl Default for Keyword {
166    fn default() -> Self {
167        Self {
168            short: String::new(),
169            expanded: String::new(),
170            closing_token: None,
171        }
172    }
173}
174
175// TODO: combine UserDefined and UserDefinedRegex into one variant
176#[derive(Debug, Clone)]
177pub enum NodeType {
178    Keyword(Keyword),
179    #[deprecated]
180    UserDefined {
181        final_chars: Vec<char>,
182    },
183    #[deprecated]
184    UserDefinedRegex(Regex),
185    UserDefinedCombo(Regex, Vec<char>),
186    Null,
187}
188
189impl PartialEq for NodeType {
190    fn eq(&self, other: &Self) -> bool {
191        match self {
192            Keyword(k) => match other {
193                Keyword(k2) => k.eq(k2),
194                _ => false,
195            },
196            UserDefined { final_chars: fc } => match other {
197                UserDefined { final_chars: fc2 } => fc.eq(fc2),
198                _ => false,
199            },
200            UserDefinedRegex(r) => match other {
201                UserDefinedRegex(r2) => r.as_str().eq(r2.as_str()),
202                _ => false,
203            },
204            UserDefinedCombo(r, f) => match other {
205                UserDefinedCombo(r2, f2) => r.as_str().eq(r2.as_str()) && f.eq(f2),
206                _ => false,
207            },
208            Null => match other {
209                Null => true,
210                _ => false,
211            },
212        }
213    }
214    fn ne(&self, other: &Self) -> bool {
215        !self.eq(other)
216    }
217}
218
219use NodeType::*;
220use debug_print::debug_println;
221use regex::Regex;
222
223type NodeId = usize;
224#[derive(Debug, Clone, PartialEq)]
225pub struct FSMNode {
226    id: NodeId,
227    is_done: bool,
228    pub value: NodeType,
229    pub children: Vec<FSMRc<FSMLock<FSMNode>>>,
230}
231
232impl Default for FSMNode {
233    fn default() -> Self {
234        Self {
235            id: get_id(),
236            is_done: false,
237            value: Null,
238            children: Vec::new(),
239        }
240    }
241}
242
243impl FSMNode {
244    pub fn id(&self) -> NodeId {
245        self.id
246    }
247    pub fn is_done(&self) -> bool {
248        self.is_done
249    }
250    pub fn set_is_done(&mut self, val: bool) {
251        self.is_done = val;
252    }
253    pub fn is_null(&self) -> bool {
254        if let Null = self.value { true } else { false }
255    }
256    fn deep_clone_internal(
257        stub: &FSMRc<FSMLock<Self>>,
258        old: &FSMNode,
259        visited_nodes: &mut HashMap<usize, FSMRc<FSMLock<FSMNode>>>,
260    ) -> FSMRc<FSMLock<Self>> {
261        for child in &old.children {
262            if !visited_nodes.contains_key(&child.borrow().id) {
263                let clone = FSMRc::new(FSMLock::new(Self {
264                    value: child.borrow().value.clone(),
265                    ..Default::default()
266                }));
267                visited_nodes.insert(child.borrow().id, clone.clone());
268                FSMNode::deep_clone_internal(&clone, &child.borrow(), visited_nodes);
269                stub.borrow_mut().children.push(clone);
270            } else {
271                stub.borrow_mut()
272                    .children
273                    .push(visited_nodes.get(&child.borrow().id).unwrap().clone());
274            }
275        }
276        stub.clone()
277    }
278    pub fn deep_clone(&self) -> FSMRc<FSMLock<Self>> {
279        debug_println!("Deep cloning node {}", self.short_id());
280        let ret = FSMRc::new(FSMLock::new(Self {
281            value: self.value.clone(),
282            ..Default::default()
283        }));
284        let mut visited_nodes = HashMap::new();
285        visited_nodes.insert(self.id, ret.clone());
286        let ret = FSMNode::deep_clone_internal(&ret, self, &mut visited_nodes);
287        debug_println!("Finish deep clone:");
288        ret.borrow().dbg();
289        ret
290    }
291    fn has_direct_child(&self, id: usize) -> bool {
292        self.children.iter().find(|c| c.borrow().id == id).is_some()
293    }
294    pub fn node_cnt(this: &FSMRc<FSMLock<FSMNode>>) -> usize {
295        let mut ret = 1; // one root node
296        this.walk_fsm_depth(
297            &mut |_, parent, _, _| {
298                ret += parent.borrow().children.len();
299                false
300            },
301            true,
302        );
303        ret
304    }
305    fn get_direct_child_dups(&self) -> Vec<usize> {
306        let mut ids = HashSet::new();
307        let mut ret = Vec::new();
308        self.children.iter().enumerate().for_each(|(i, c)| {
309            if ids.contains(&c.borrow().id) {
310                ret.push(i);
311            } else {
312                ids.insert(c.borrow().id);
313            }
314        });
315        ret
316    }
317    pub fn set_userdef_links(this: &FSMRc<FSMLock<FSMNode>>) {
318        let mut userdefs = Vec::new();
319        this.walk_fsm_breadth(
320            &mut |_, p, _, _| {
321                if let UserDefinedCombo(_, _) = p.borrow().value {
322                    userdefs.push(FSMRc::clone(&p));
323                }
324                false
325            },
326            true,
327        );
328        println!("{}", userdefs.len());
329        for userdef in userdefs {
330            println!(
331                "{:?} {}",
332                userdef.borrow().value,
333                userdef.borrow().short_id()
334            );
335            userdef.walk_fsm_depth(
336                &mut |_, _, c, _| {
337                    println!("{:?} {}", c.borrow().value, c.borrow().short_id());
338                    if let Keyword(Keyword { short, .. }) = &c.borrow().value {
339                        if let UserDefinedCombo(_, fcs) = &mut userdef.borrow_mut().value {
340                            fcs.push(short.chars().nth(0).unwrap()); // bad handling, only possible when
341                            // there aren't any conflicts
342                        }
343                    }
344                    false
345                },
346                false,
347            );
348        }
349    }
350    pub fn minify(this: &FSMRc<FSMLock<FSMNode>>) {
351        debug_println!("before minify:");
352        this.borrow().dbg();
353        let mut cycle_translation_table = HashMap::new();
354        this.walk_fsm_depth(
355            &mut |_, parent, child, childidx| {
356                // TODO: figure out why the parent check needs to be here
357                if parent.borrow().is_null()
358                    && child.borrow().is_null()
359                    && parent.borrow().children.len() == 1
360                {
361                    cycle_translation_table.insert(child.borrow().id, parent.clone());
362                    parent.borrow_mut().children.remove(*childidx as usize);
363                    for child in &child.borrow().children {
364                        debug_println!("CID: {}", child.borrow().short_id());
365                        if child.borrow().id == parent.borrow().id
366                            || parent.borrow().has_direct_child(child.borrow().id)
367                        {
368                            continue;
369                        }
370                        parent.borrow_mut().children.push(child.clone());
371                    }
372                    child.borrow_mut().children.clear();
373                    *childidx -= 1;
374                }
375                let pborrow = parent.borrow();
376                let dup_idxs = pborrow.get_direct_child_dups();
377                drop(pborrow);
378                dup_idxs.iter().for_each(|ci| {
379                    parent.borrow_mut().children.remove(*ci);
380                });
381                false
382            },
383            true,
384        );
385        // fix any broken pointers the last op may have created
386        this.walk_fsm_depth(
387            &mut |_, parent, child, childidx| {
388                if let Some(new_child) = cycle_translation_table.get(&child.borrow().id) {
389                    if new_child.borrow().id == parent.borrow().id
390                        || parent.borrow().has_direct_child(new_child.borrow().id)
391                    {
392                        parent.borrow_mut().children.remove(*childidx as usize);
393                        return false;
394                    }
395                    parent.borrow_mut().children[*childidx as usize] = new_child.clone();
396                }
397                false
398            },
399            true,
400        );
401        debug_println!("after minify:");
402        this.borrow().dbg();
403    }
404
405    pub fn has_useful_children(&self) -> bool {
406        self.walk_fsm_breadth(
407            &mut |_, _, c, _| match c.value {
408                Null => false,
409                _ => true,
410            },
411            false,
412        )
413        .is_some()
414    }
415
416    pub fn get_last_child(&self) -> Option<FSMRc<FSMLock<FSMNode>>> {
417        self.children.last().cloned()
418    }
419    /// adds child to the children vector of self without doing collision checks first
420    pub unsafe fn add_child_unsafe(&mut self, child: &FSMRc<FSMLock<FSMNode>>) {
421        self.children.push(FSMRc::clone(&child));
422    }
423    pub fn add_child(&mut self, child: &FSMRc<FSMLock<FSMNode>>) {
424        while self.handle_potential_conflict(child) {}
425        unsafe {
426            self.add_child_unsafe(child);
427        }
428    }
429    pub fn add_child_cycle_safe(this: &FSMRc<FSMLock<FSMNode>>, child: &FSMRc<FSMLock<FSMNode>>) {
430        while this.borrow().handle_potential_conflict(child) {}
431        this.borrow_mut().children.push(FSMRc::clone(&child));
432    }
433    pub fn new_null(parent: Option<&FSMRc<FSMLock<FSMNode>>>) -> FSMRc<FSMLock<Self>> {
434        let ret = FSMRc::new(FSMLock::new(Self {
435            value: Null,
436            children: Vec::new(),
437            ..Default::default()
438        }));
439        if let Some(parent) = parent {
440            parent.borrow_mut().add_child(&ret);
441        }
442        ret
443    }
444
445    pub fn short_id(&self) -> String {
446        format!("{:#x}", self.id)
447    }
448
449    fn dbg_internal(&self, indent: usize, visited_nodes: &mut HashSet<usize>) {
450        println!("{}{:?} {}", " ".repeat(indent), self.value, self.short_id());
451        visited_nodes.insert(self.id);
452        for child in self.children.iter() {
453            if !visited_nodes.contains(&child.borrow().id) {
454                child.borrow().dbg_internal(indent + 4, visited_nodes);
455            } else {
456                println!(
457                    "{}Cycle to {}",
458                    " ".repeat(indent + 4),
459                    child.borrow().short_id()
460                );
461            }
462        }
463    }
464    fn get_all_leaves(&self, discovered_leaves: &mut Vec<FSMRc<FSMLock<FSMNode>>>) {
465        FSMRc::new(FSMLock::new(self.clone())).walk_fsm(
466            &mut |visited_nodes, _, child, _| {
467                if discovered_leaves
468                    .iter()
469                    .find(|dl| dl.borrow().id == child.borrow().id)
470                    .is_some()
471                {
472                    return false;
473                }
474                if child.borrow().children.is_empty() {
475                    debug_println!(
476                        "adding node {:?} {}",
477                        child.borrow().value,
478                        child.borrow().short_id()
479                    );
480                    discovered_leaves.push(child.clone());
481                } else {
482                    let mut has_only_cycles = true;
483                    for child in &child.borrow().children {
484                        if !visited_nodes.contains(&child.borrow().id) {
485                            has_only_cycles = false;
486                            break;
487                        }
488                    }
489                    if has_only_cycles {
490                        debug_println!(
491                            "adding node {:?} {} (has_only_cycles case)",
492                            child.borrow().value,
493                            child.borrow().short_id()
494                        );
495                        discovered_leaves.push(child.clone());
496                    }
497                }
498                false
499            },
500            true,
501            false,
502        );
503    }
504    pub fn add_child_to_all_leaves(
505        this: &FSMRc<FSMLock<FSMNode>>,
506        child: &FSMRc<FSMLock<FSMNode>>,
507    ) {
508        let mut leaves = Vec::new();
509        this.borrow().get_all_leaves(&mut leaves);
510        while let Some(node) = leaves.pop() {
511            FSMNode::add_child_cycle_safe(&node, child);
512            // NOTE: hopefully this isn't needed anymore
513            // if node.borrow().children.is_empty() {
514            //     FSMNode::add_child_cycle_safe(&node, child);
515            // }
516        }
517        if this.borrow().children.is_empty() {
518            FSMNode::add_child_cycle_safe(&this, child);
519        }
520    }
521
522    pub fn race_to_leaf(&self) -> Option<FSMRc<FSMLock<FSMNode>>> {
523        self.walk_fsm_depth(
524            &mut |visited_nodes, _, child, _| {
525                let mut ret = true;
526                // avoid going back to a node previously visited so do_stuff_cycle_aware doesn't return
527                // a false negative
528                for child in &child.children {
529                    if !visited_nodes.contains(&child.borrow().id) {
530                        ret = false;
531                        break;
532                    }
533                }
534                ret
535            },
536            true,
537        )
538    }
539    pub fn dbg(&self) {
540        #[cfg(debug_assertions)]
541        self.dbg_internal(0, &mut HashSet::new());
542    }
543
544    pub fn new_id(value: NodeType, id: NodeId) -> FSMRc<FSMLock<Self>> {
545        let ret = FSMRc::new(FSMLock::new(Self {
546            value,
547            children: Vec::new(),
548            id,
549            ..Default::default()
550        }));
551        ret
552    }
553
554    pub fn new(value: NodeType, parent: &FSMRc<FSMLock<FSMNode>>) -> FSMRc<FSMLock<Self>> {
555        let ret = FSMRc::new(FSMLock::new(Self {
556            value,
557            children: Vec::new(),
558            ..Default::default()
559        }));
560        parent.borrow_mut().add_child(&ret);
561        ret
562    }
563
564    pub fn new_required(value: NodeType, parent: &FSMRc<FSMLock<FSMNode>>) -> FSMRc<FSMLock<Self>> {
565        let ret = FSMRc::new(FSMLock::new(Self {
566            value,
567            children: Vec::new(),
568            ..Default::default()
569        }));
570        parent.borrow_mut().add_child(&ret);
571        ret
572    }
573
574    pub fn new_userdef(r: Regex, parent: &FSMRc<FSMLock<FSMNode>>) -> FSMRc<FSMLock<Self>> {
575        let ret = FSMRc::new(FSMLock::new(Self {
576            value: UserDefinedCombo(r, Vec::new()),
577            children: Vec::new(),
578            ..Default::default()
579        }));
580        FSMNode::add_child_cycle_safe(parent, &ret);
581        ret
582    }
583
584    pub fn new_keyword(expanded_name: String) -> FSMRc<FSMLock<Self>> {
585        FSMRc::new(FSMLock::new(Self {
586            value: Keyword(Keyword {
587                short: expanded_name.chars().nth(0).unwrap().to_string(),
588                expanded: expanded_name,
589                ..Default::default()
590            }),
591            children: Vec::new(),
592            ..Default::default()
593        }))
594    }
595
596    pub fn new_keyword_with_parent(
597        expanded_name: String,
598        parent: FSMRc<FSMLock<FSMNode>>,
599    ) -> FSMRc<FSMLock<Self>> {
600        let ret = Self::new_keyword(expanded_name);
601        FSMNode::add_child_cycle_safe(&parent, &ret);
602        ret
603    }
604    pub fn find_node_with_code(&self, short: &str) -> Option<FSMRc<FSMLock<FSMNode>>> {
605        for child in &self.children {
606            if let Keyword(Keyword { short: nshort, .. }) = &child.borrow().value
607                && nshort == short
608            {
609                return Some(FSMRc::clone(&child));
610            }
611        }
612        for child in &self.children {
613            let rec_res = child.borrow().find_node_with_code(short);
614            if rec_res.is_some() {
615                return rec_res;
616            }
617        }
618        None
619    }
620
621    pub fn check_for_conflicts(&self, short: &str) -> bool {
622        for child in &self.children {
623            let borrow = child.borrow();
624            match &borrow.value {
625                Keyword(Keyword { short: nshort, .. }) if nshort == short => return true,
626                Null => {
627                    let rec_res = borrow.check_for_conflicts(short);
628                    if rec_res {
629                        return true;
630                    }
631                }
632                _ => {}
633            }
634        }
635        false
636    }
637
638    fn get_conflicting_node(&self, short: &str) -> Option<FSMRc<FSMLock<FSMNode>>> {
639        self.walk_fsm_breadth(
640            &mut |_, _, child, _| {
641                println!("awa?");
642                match &child.value {
643                    Keyword(Keyword { short: nshort, .. }) if short.starts_with(nshort) => {
644                        return true;
645                    }
646                    _ => false,
647                }
648            },
649            false,
650        )
651    }
652    fn handle_potential_conflict_internal(&self, child: &FSMRc<FSMLock<FSMNode>>) -> bool {
653        let child_borrow = child.borrow();
654        let mut ret = false;
655        if let Keyword(Keyword { short: cshort, .. }) = &child_borrow.value {
656            if let Some(node) = self.get_conflicting_node(cshort)
657                && node.borrow().value != child_borrow.value
658            {
659                node.replace_with(|node| {
660                    if let Keyword(keyword_struct) = &mut node.value {
661                        let new_short = NameShortener::expand(
662                            Some(&keyword_struct.short),
663                            &keyword_struct.expanded,
664                        );
665                        keyword_struct.short = new_short;
666                        debug_println!("conflict handler 2");
667                        ret = true;
668                        node.to_owned()
669                    } else {
670                        panic!(
671                            "What?! We got a non-keyword node from the get_conflicting_node fn! Anyways, I'm gonna snuggle some foxxos now..."
672                        )
673                    }
674                });
675            }
676        }
677        ret
678    }
679    pub fn handle_potential_conflict(&self, child: &FSMRc<FSMLock<FSMNode>>) -> bool {
680        let child_borrow = child.borrow();
681        if let Keyword(keyword_struct) = &child_borrow.value {
682            debug_println!("{:?}", self.value);
683            debug_println!("{:?}", child.borrow().value);
684            if self.handle_potential_conflict_internal(child) {
685                let short =
686                    NameShortener::expand(Some(&keyword_struct.short), &keyword_struct.expanded);
687                drop(child_borrow);
688                child.replace_with(|node| {
689                    if let Keyword(k) = &mut node.value {
690                        k.short = short;
691                    } else {
692                        unreachable!()
693                    }
694                    node.to_owned()
695                });
696                return true;
697            }
698        } else if let Null = &child_borrow.value {
699            // println!("awa?");
700            let mut ret = false;
701            let mut visited_nodes = HashSet::new();
702            // iterate over every child and return true if at least one had a conflict
703            for child in &child_borrow.children {
704                if !visited_nodes.contains(&child.borrow().id) {
705                    visited_nodes.insert(child.borrow().id);
706                    if self.handle_potential_conflict_internal(&child) {
707                        let mut mut_child = child.borrow_mut();
708                        if let Keyword(k) = &mut mut_child.value {
709                            k.short = NameShortener::expand(Some(&k.short), &k.expanded);
710                        }
711                        ret = true;
712                    }
713                }
714            }
715            if ret {
716                return true;
717            }
718        }
719        false
720    }
721    pub fn dump_children(&self) {
722        self.children
723            .iter()
724            .for_each(|child| println!("{:?}", child.borrow().value));
725    }
726}
727
728pub trait ToCSV {
729    fn to_csv(&self) -> String;
730    fn from_csv(csv: &str) -> Self;
731}
732
733impl ToCSV for NodeType {
734    fn to_csv(&self) -> String {
735        let mut ret = match self {
736            Null => "".to_owned(),
737            Keyword(Keyword {
738                short,
739                expanded,
740                closing_token,
741            }) => format!(
742                "{}\t{}{}",
743                short,
744                expanded,
745                if let Some(ct) = closing_token {
746                    "\t".to_owned() + ct
747                } else {
748                    "".to_owned()
749                }
750            ),
751            UserDefinedCombo(r, cts) => {
752                format!(
753                    "/{}{}",
754                    r.as_str(),
755                    cts.iter()
756                        .fold(String::new(), |acc, el| { format!("{}\t{}", acc, el) })
757                )
758            }
759            _ => panic!("FSMs with deprecated nodes will not be serialized!"),
760        };
761        ret.push('\n');
762        ret
763    }
764    fn from_csv(csv: &str) -> Self {
765        println!("csv: {csv}");
766        if csv.len() < 2 {
767            Null
768        } else if csv.chars().nth(0).unwrap() == '/' {
769            let mut iter = csv.split('\t');
770            let regex = Regex::new(&iter.next().expect("invalid NodeType format")[1..])
771                .expect("invalid Regex format");
772            let mut final_tokens = Vec::new();
773            iter.for_each(|ft| final_tokens.push(ft.chars().nth(0).unwrap()));
774            UserDefinedCombo(regex, final_tokens)
775        } else {
776            let parts: Vec<_> = csv.split('\t').collect();
777            if parts.len() < 3 {
778                Keyword(Keyword {
779                    short: parts[0].to_owned(),
780                    expanded: parts[1].to_owned(),
781                    closing_token: None,
782                })
783            } else {
784                Keyword(Keyword {
785                    short: parts[0].to_owned(),
786                    expanded: parts[1].to_owned(),
787                    closing_token: Some(parts[3].to_owned()),
788                })
789            }
790        }
791    }
792}
793
794impl ToCSV for FSMNodeWrapper {
795    fn to_csv(&self) -> String {
796        let mut nodes = HashMap::new();
797        self.walk_fsm_breadth(
798            &mut |_, _, c, _| {
799                nodes.insert(c.borrow().id, c.clone());
800                false
801            },
802            true,
803        );
804        let mut ret = format!("{}\t{}", self.borrow().id, self.borrow().value.to_csv());
805        nodes.keys().for_each(|id| {
806            ret.push_str(&id.to_string());
807            ret.push('\t');
808            ret.push_str(&nodes.get(id).unwrap().borrow().value.to_csv());
809        });
810        ret.push('\n');
811
812        ret.push_str(&self.borrow().id.to_string());
813        self.borrow().children.iter().for_each(|el| {
814            ret.push('\t');
815            ret.push_str(&el.borrow().id.to_string());
816        });
817        ret.push('\n');
818
819        nodes.keys().for_each(|id| {
820            ret.push_str(&id.to_string());
821            let node = nodes.get(id).unwrap();
822            node.borrow().children.iter().for_each(|el| {
823                ret.push('\t');
824                ret.push_str(&el.borrow().id.to_string());
825            });
826            ret.push('\n');
827        });
828        ret
829    }
830    fn from_csv(csv: &str) -> Self {
831        let mut iter = csv.split_indices('\n');
832        let mut nodes = HashMap::new();
833
834        // TODO: refactor
835        let line = iter.next().unwrap();
836        let mut line_iter = line.0.split_indices('\t');
837        let id: usize = line_iter.next().unwrap().0.parse().unwrap();
838        let ntype = NodeType::from_csv(&line.0[line_iter.next().unwrap().1..]);
839
840        let root = FSMNode::new_id(ntype, id);
841        nodes.insert(id, root.clone());
842        while let Some(part) = iter.next()
843            && !part.0.is_empty()
844        {
845            let mut line_iter = part.0.split_indices('\t');
846            let id: usize = line_iter.next().unwrap().0.parse().unwrap();
847            let ntype = NodeType::from_csv(&part.0[line_iter.next().unwrap().1..]);
848            nodes.insert(id, FSMNode::new_id(ntype, id));
849        }
850        // iter.next(); // consume separator line
851
852        // children logic
853        while let Some(part) = iter.next()
854            && !part.0.is_empty()
855        {
856            let mut iter = part.0.split('\t');
857            let id: usize = iter.next().unwrap().parse().unwrap();
858            let parent = nodes.get(&id).unwrap();
859            while let Some(part) = iter.next() {
860                let c_id: NodeId = part.parse().unwrap();
861                #[cfg(not(debug_assertions))]
862                unsafe {
863                    parent
864                        .borrow_mut()
865                        .add_child_unsafe(nodes.get(&c_id).unwrap());
866                }
867                #[cfg(debug_assertions)]
868                FSMNode::add_child_cycle_safe(parent, nodes.get(&c_id).unwrap());
869            }
870        }
871        root
872    }
873}
874
875trait SplitIndicesExt {
876    fn split_indices<P>(&self, pat: P) -> impl Iterator<Item = (&str, usize)>
877    where
878        P: Pattern;
879}
880
881impl SplitIndicesExt for &str {
882    fn split_indices<P>(&self, pat: P) -> impl Iterator<Item = (&str, usize)>
883    where
884        P: Pattern,
885    {
886        let mut start = 0;
887        self.match_indices(pat).map(move |(i, _)| {
888            let ret = (&self[start..i], start);
889            start = i + 1;
890            ret
891        })
892    }
893}
894
895#[cfg(test)]
896mod tests {
897    use crate::dbg_id;
898
899    use super::*;
900
901    #[test]
902    fn test_csv_simple() {
903        dbg_id();
904        let root = FSMNode::new_keyword("int".to_string());
905        let _other = FSMNode::new_keyword_with_parent("asdf".to_string(), root.clone());
906
907        let csv = root.to_csv();
908        assert_eq!("0\ti\tint\n1\ta\tasdf\n\n0\t1\n1\n", csv);
909        let new_root = FSMNodeWrapper::from_csv(&csv);
910        assert_eq!(root, new_root);
911    }
912}