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