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 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#[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; 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()); }
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 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 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 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 }
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 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 let mut ret = false;
701 let mut visited_nodes = HashSet::new();
702 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 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 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}