lib/
lib.rs

1#![feature(let_chains)]
2#![feature(if_let_guard)]
3#![feature(trait_alias)]
4#![feature(impl_trait_in_bindings)]
5#![feature(lock_value_accessors)]
6#![feature(pattern)]
7
8use debug_print::debug_println;
9use fsm::NodeType::{self, *};
10use fsm::{CycleAwareOp, Keyword};
11pub use fsm::{FSMNode, ToCSV};
12use regex::Regex;
13use std::cell::RefCell;
14#[cfg(not(feature = "thread-safe"))]
15use std::cell::{Ref, RefMut};
16#[cfg(feature = "thread-safe")]
17use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
18
19pub mod frontend;
20
21mod fsm;
22pub use fsm::FSMNodeWrapper;
23
24pub mod protocol;
25
26thread_local! {
27    static CNT: RefCell<usize> = RefCell::new(0);
28}
29
30fn get_id() -> usize {
31    let mut ret = 0;
32    CNT.with_borrow(|cnt| ret = *cnt);
33    CNT.with_borrow_mut(|cnt| *cnt += 1);
34    return ret;
35}
36fn dbg_id() {
37    debug_println!("{:?}", CNT);
38}
39
40trait PartialMatch {
41    fn partial_match(&self, hay: &str) -> bool;
42}
43
44impl PartialMatch for Regex {
45    /**
46    not a perfect solution and should therefore be never used
47    **/
48    fn partial_match(&self, hay: &str) -> bool {
49        let orig = self.as_str();
50        for i in 1..orig.len() {
51            if let Ok(regex) = Regex::new(&orig[0..=i])
52                && regex.is_match(hay)
53            {
54                return true;
55            }
56        }
57        false
58    }
59}
60
61pub fn get_test_fsm() -> FSMNodeWrapper {
62    let root = FSMNode::new_null(None);
63    let mut sign_token = NodeType::Keyword(Keyword::new("unsigned".to_string(), None));
64    let child = FSMNode::new(sign_token.clone(), &root);
65    sign_token = NodeType::Keyword(Keyword::new("signed".to_string(), None));
66
67    let child2 = FSMNode::new(sign_token, &root);
68    let types = FSMNode::new_required(NodeType::Null, &child);
69
70    let int = FSMNode::new_keyword_with_parent("int".to_string(), types.clone());
71    let float = FSMNode::new_keyword_with_parent("short".to_string(), types.clone());
72    child.borrow_mut().add_child(&types);
73    child2.borrow_mut().add_child(&types);
74    root
75}
76
77// ironic that this only expands names
78struct NameShortener;
79impl NameShortener {
80    fn expand(old: Option<&str>, full: &str) -> String {
81        if full.is_empty() {
82            panic!("Cannot expand the void!")
83        }
84        let ret = if let Some(old) = old {
85            if old == full {
86                return old.to_string(); // FIXME: this can't be a good handling
87                // well screw you past me! It's actually vital for collisions between s1 and s2
88                // where s2.starts_with(s1) applies
89            }
90            if full.len() < old.len() {
91                panic!("NS: There is nothing left...")
92            }
93            let mut ret = old.to_string();
94            ret.push_str(&full[old.len()..old.len() + 1]);
95            ret
96        } else {
97            full[0..1].to_string()
98        };
99        debug_println!("Got {} instead of {old:?}", ret);
100        ret
101    }
102}
103
104#[cfg(not(feature = "thread-safe"))]
105type FSMRc<T> = std::rc::Rc<T>;
106#[cfg(not(feature = "thread-safe"))]
107type FSMWeak<T> = std::rc::Weak<T>;
108#[cfg(not(feature = "thread-safe"))]
109#[derive(Debug, PartialEq)]
110pub struct FSMLock<T>(RefCell<T>);
111#[cfg(not(feature = "thread-safe"))]
112impl<T> FSMLock<T> {
113    fn new(val: T) -> Self {
114        Self(RefCell::new(val))
115    }
116    pub fn borrow(&self) -> Ref<'_, T> {
117        self.0.borrow()
118    }
119    fn borrow_mut(&self) -> RefMut<'_, T> {
120        self.0.borrow_mut()
121    }
122    fn replace_with(&self, op: impl FnOnce(&mut T) -> T) {
123        self.0.replace_with(op);
124    }
125}
126
127#[cfg(feature = "thread-safe")]
128type FSMRc<T> = std::sync::Arc<T>;
129#[cfg(feature = "thread-safe")]
130type FSMWeak<T> = std::sync::Weak<T>;
131#[cfg(feature = "thread-safe")]
132#[derive(Debug)]
133pub struct FSMLock<T>(RwLock<T>);
134#[cfg(feature = "thread-safe")]
135impl<T> FSMLock<T> {
136    pub fn borrow(&self) -> RwLockReadGuard<'_, T> {
137        self.0.read().expect("FSMLock borrow()")
138    }
139    fn borrow_mut(&self) -> RwLockWriteGuard<'_, T> {
140        self.0.write().expect("FSMLock borrow()")
141    }
142    fn new(val: T) -> Self {
143        Self(RwLock::new(val))
144    }
145    fn replace_with(&self, op: impl FnOnce(&mut T) -> T) {
146        let new = op(&mut self.0.write().unwrap());
147        self.0.set(new).unwrap();
148    }
149}
150#[cfg(feature = "thread-safe")]
151impl<T: PartialEq> PartialEq for FSMLock<T> {
152    fn eq(&self, other: &Self) -> bool {
153        self.0.read().unwrap().eq(&other.0.read().unwrap())
154    }
155}
156type InternalCursor = FSMWeak<FSMLock<FSMNode>>;
157#[derive(Clone, Debug)]
158pub struct FSMCursor {
159    root: InternalCursor,
160    cur_ast_pos: InternalCursor,
161    input_buf: String,
162    unfinished_nodes: Vec<InternalCursor>,
163}
164
165impl FSMCursor {
166    pub fn new(fsm_root: &FSMRc<FSMLock<FSMNode>>) -> Self {
167        Self {
168            root: FSMRc::downgrade(fsm_root),
169            cur_ast_pos: FSMRc::downgrade(fsm_root),
170            input_buf: String::new(),
171            unfinished_nodes: Vec::new(),
172        }
173    }
174    pub fn reset(&mut self) {
175        self.cur_ast_pos = FSMWeak::clone(&self.root);
176        self.input_buf.clear();
177    }
178    fn handle_userdefined_combo(&mut self, input: char, final_chars: &Vec<char>) -> Option<String> {
179        let child_idx = final_chars.iter().position(|char| *char == input);
180        if let Some(_) = child_idx {
181            let strong_ref = self.get_cur_ast_binding();
182            // let borrow = strong_ref.borrow();
183            // let next_node = FSMRc::clone(&borrow.children[child_idx]);
184            let mut ret = None;
185            strong_ref.walk_fsm_depth(
186                &mut |_, _, c, _| {
187                    if let Keyword(Keyword {
188                        short, expanded, ..
189                    }) = &c.borrow().value
190                        && short.starts_with(input)
191                    {
192                        self.update_cursor(&c);
193                        self.input_buf.clear();
194                        ret = Some(expanded.clone());
195                        true
196                    } else {
197                        false
198                    }
199                },
200                false,
201            );
202            ret
203        } else {
204            None
205        }
206    }
207    fn handle_userdefined(&mut self, input: char, final_chars: &Vec<char>) -> Option<String> {
208        let child_idx = final_chars.iter().position(|char| *char == input);
209        if let Some(child_idx) = child_idx {
210            let strong_ref = self.get_cur_ast_binding();
211            let borrow = strong_ref.borrow();
212            let next_node = FSMRc::clone(&borrow.children[child_idx]);
213            self.update_cursor(&next_node);
214            let ret = if let NodeType::Keyword(Keyword {
215                short,
216                expanded,
217                closing_token: None,
218                ..
219            }) = &next_node.borrow().value
220                && *short == String::from(input)
221            {
222                Some(expanded.clone())
223            } else {
224                Some(String::from(final_chars[child_idx]))
225            };
226            self.input_buf.clear();
227            ret
228        } else {
229            None
230        }
231    }
232    pub fn clear_inputbuf(&mut self) {
233        self.input_buf.clear();
234    }
235    fn search_for_userdefs(
236        &self,
237        treenode: &FSMRc<FSMLock<FSMNode>>,
238    ) -> Option<FSMRc<FSMLock<FSMNode>>> {
239        treenode.borrow().walk_fsm_breadth(
240            &mut |_, _, child, _| match &child.value {
241                UserDefined { .. } => true,
242                UserDefinedRegex(regex) | UserDefinedCombo(regex, _)
243                    if regex.partial_match(&self.input_buf) =>
244                {
245                    true
246                }
247                _ => false,
248            },
249            false,
250        )
251    }
252    pub fn search_rec(
253        &self,
254        treenode: &FSMRc<FSMLock<FSMNode>>,
255    ) -> Option<FSMRc<FSMLock<FSMNode>>> {
256        self.search_rec_internal(treenode, false)
257    }
258    pub fn search_rec_internal(
259        &self,
260        treenode: &FSMRc<FSMLock<FSMNode>>,
261        best_effort: bool,
262    ) -> Option<FSMRc<FSMLock<FSMNode>>> {
263        debug_println!(
264            "search_rec at {:?} {}",
265            treenode.borrow().value,
266            treenode.borrow().short_id()
267        );
268        debug_println!("search_rec input buf: {}", self.input_buf);
269        let mut keyword_match = None;
270        let mut potential_matches = 0;
271        let mut visited_keywords = 0;
272        let mut last_keyword = None;
273        // TODO: this one relies on buggy behavior from the old function!
274        treenode.walk_fsm_allow_cycle_to_self(
275            &mut |_, _, child, _| {
276                let node_val = &child.borrow().value;
277                debug_println!(
278                    "search_rec closure at {:?} {}",
279                    child.borrow().value,
280                    child.borrow().short_id()
281                );
282                match node_val {
283                    NodeType::Keyword(Keyword { short, .. }) => {
284                        if short.starts_with(&self.input_buf) {
285                            debug_println!("{:?}", child.borrow().value);
286                            debug_println!("{short} == {}", self.input_buf);
287                            keyword_match = Some(child.clone());
288                            potential_matches += 1;
289                            potential_matches > 1
290                        } else {
291                            // bandaid logic
292                            visited_keywords += 1;
293                            if visited_keywords == 1 {
294                                last_keyword = Some(child.clone());
295                            }
296                            false
297                        }
298                    }
299                    _ => false,
300                }
301            },
302            false,
303            false,
304        );
305        debug_println!("pm: {potential_matches}");
306        if keyword_match.is_some() && potential_matches == 1 {
307            return keyword_match;
308        }
309
310        debug_println!("vk: {visited_keywords}");
311        if visited_keywords == 1 && best_effort {
312            // probably what the user wants
313            return last_keyword;
314        }
315
316        let userdef_match = self.search_for_userdefs(treenode);
317        if userdef_match.is_some() {
318            return userdef_match;
319        }
320        None
321    }
322    pub fn advance(&mut self, input: char) -> Option<String> {
323        let binding = self.get_cur_ast_binding();
324        let borrow = binding.borrow();
325        debug_println!(
326            "advance with cursor {:?} {}",
327            borrow.value,
328            borrow.short_id()
329        );
330        self.input_buf.push(input);
331        // TODO: refactor
332        if borrow.is_done() {
333            let res = self.search_rec(&binding);
334            if let Some(node) = res {
335                self.update_cursor(&node);
336                return match &node.borrow().value {
337                    NodeType::Keyword(Keyword { expanded, .. }) => {
338                        self.input_buf.clear();
339                        Some(expanded.clone())
340                    }
341                    NodeType::UserDefined { final_chars } => {
342                        let res = self.handle_userdefined(input, &final_chars);
343                        res
344                    }
345                    NodeType::UserDefinedRegex(_) => None,
346                    _ => unreachable!(),
347                };
348            }
349        }
350        match &borrow.value {
351            NodeType::UserDefined { final_chars, .. } => {
352                let res = self.handle_userdefined(input, final_chars);
353                if res.is_some() {
354                    return res;
355                }
356            }
357            NodeType::UserDefinedRegex(r) => {
358                debug_println!("Checking regex against '{}'", &self.input_buf);
359                if r.is_match(&self.input_buf) {
360                    drop(borrow);
361                    binding.borrow_mut().set_is_done(true);
362                    self.input_buf.clear();
363                    self.input_buf.push(input);
364                    let next_node = self.search_rec_internal(&binding, true);
365                    if next_node.is_none() {
366                        debug_println!("No node found");
367                        self.input_buf.clear();
368                        return Some(input.to_string());
369                    }
370                    let next_node = next_node.unwrap();
371                    self.update_cursor(&next_node);
372                    let ret = if let NodeType::Keyword(Keyword {
373                        short,
374                        expanded,
375                        closing_token: None,
376                        ..
377                    }) = &next_node.borrow().value
378                    {
379                        if short.starts_with(input) {
380                            Some(expanded.clone())
381                        } else {
382                            // FIXME: this is terrible logic
383                            if let Some(next_node) = self.search_rec_internal(&next_node, true) {
384                                self.update_cursor(&next_node);
385                                if let Keyword(Keyword {
386                                    expanded,
387                                    closing_token: None,
388                                    ..
389                                }) = &next_node.borrow().value
390                                // && short.starts_with(input)
391                                {
392                                    Some(expanded.clone())
393                                } else {
394                                    Some(input.to_string())
395                                }
396                            } else {
397                                Some(input.to_string())
398                            }
399                        }
400                    } else {
401                        Some(input.to_string())
402                    };
403                    self.input_buf.clear();
404                    return ret;
405                }
406            }
407            UserDefinedCombo(_, f) => {
408                let ret = self.handle_userdefined_combo(input, f);
409                if ret.is_some() {
410                    return ret;
411                }
412            }
413            _ => {
414                let res = self.search_rec(&binding);
415                if let Some(node) = res {
416                    self.update_cursor(&node);
417                    return match &node.borrow().value {
418                        NodeType::Keyword(Keyword { expanded, .. }) => {
419                            self.input_buf.clear();
420                            Some(expanded.clone())
421                        }
422                        NodeType::UserDefined { final_chars } => {
423                            let res = self.handle_userdefined(input, &final_chars);
424                            res
425                        }
426                        NodeType::UserDefinedRegex(_) => None,
427                        NodeType::UserDefinedCombo(r, f) => {
428                            let res = self.handle_userdefined_combo(input, f);
429                            res
430                        }
431                        _ => unreachable!(),
432                    };
433                }
434            }
435        }
436        None
437    }
438
439    fn update_cursor(&mut self, node: &FSMRc<FSMLock<FSMNode>>) {
440        self.cur_ast_pos = FSMRc::downgrade(&FSMRc::clone(&node));
441        if let NodeType::Keyword(Keyword {
442            closing_token: Some(_),
443            ..
444        }) = &node.borrow().value
445        {
446            self.unfinished_nodes.push(FSMRc::downgrade(&node));
447        } else if node.borrow().children.is_empty() && self.unfinished_nodes.len() > 1 {
448            // we don't need to jump back if only one remains
449            self.cur_ast_pos = self.unfinished_nodes.pop().unwrap();
450        }
451        debug_println!(
452            "uc: {:?} {}",
453            self.get_cur_ast_binding().borrow().value,
454            self.get_cur_ast_binding().borrow().id()
455        );
456    }
457    fn dump(&self) {
458        println!(
459            "Last matched node: {:?}",
460            self.cur_ast_pos.upgrade().unwrap().borrow().value
461        );
462        println!("Input buf: {}", self.input_buf);
463    }
464
465    pub fn is_done(&self) -> bool {
466        let ast_ref = self.cur_ast_pos.upgrade().unwrap();
467        let binding = ast_ref.borrow();
468        match binding.value {
469            UserDefinedRegex(..) | UserDefined { .. } if !binding.is_done() => false,
470            _ => binding.children.is_empty() || !binding.has_useful_children(),
471        }
472    }
473
474    fn get_cur_ast_binding(&self) -> FSMRc<FSMLock<FSMNode>> {
475        self.cur_ast_pos.upgrade().unwrap()
476    }
477    pub fn is_in_userdefined_stage(&self) -> bool {
478        match self.get_cur_ast_binding().borrow().value {
479            NodeType::UserDefined { .. }
480            | NodeType::UserDefinedRegex(..)
481            | NodeType::UserDefinedCombo(_, _) => true,
482            _ => false,
483        }
484    }
485
486    fn get_current_nodeval(&self) -> NodeType {
487        println!("{}", self.get_cur_ast_binding().borrow().id());
488        self.get_cur_ast_binding().borrow().value.clone()
489    }
490    fn find_node_with_code(&self, short: &str) -> Option<FSMRc<FSMLock<FSMNode>>> {
491        let binding = self.get_cur_ast_binding();
492        let binding = binding.borrow();
493        binding.find_node_with_code(short)
494    }
495}
496
497#[cfg(test)]
498mod tests {
499    use crate::frontend::create_graph_from_ebnf;
500
501    use super::*;
502
503    #[test]
504    fn simple_tree() {
505        let root = FSMNode::new_keyword("int".to_string());
506        let _other = FSMNode::new_keyword_with_parent("asdf".to_string(), root.clone());
507        assert_eq!(root.borrow().children.len(), 1);
508    }
509
510    #[test]
511    fn simple_cursor_steps() {
512        let root = FSMNode::new_null(None);
513        let second = FSMNode::new_keyword_with_parent("int".to_string(), root.clone());
514        FSMNode::new_keyword_with_parent("asdf".to_string(), second.clone());
515        let mut cursor = FSMCursor::new(&root);
516        assert_eq!(cursor.get_current_nodeval(), Null);
517        cursor.advance('i').unwrap();
518        assert_eq!(
519            cursor.get_current_nodeval(),
520            NodeType::Keyword(Keyword::new("int".to_string(), None)),
521        );
522        cursor.advance('a').unwrap();
523        assert_eq!(
524            cursor.get_current_nodeval(),
525            NodeType::Keyword(Keyword::new("asdf".to_string(), None)),
526        );
527    }
528
529    #[test]
530    fn test_conflict_check() {
531        let root = FSMNode::new_null(None);
532        let mut sign_token = NodeType::Keyword(Keyword::new("unsigned".to_string(), None));
533        let child = FSMNode::new(sign_token.clone(), &root);
534        sign_token = NodeType::Keyword(Keyword::new("signed".to_string(), None));
535
536        let child2 = FSMNode::new(sign_token, &root);
537        let types = FSMNode::new_required(NodeType::Null, &child);
538
539        let int = FSMNode::new_keyword_with_parent("int".to_string(), types.clone());
540        let float = FSMNode::new_keyword_with_parent("short".to_string(), types.clone());
541        child.borrow_mut().add_child(&types);
542        child2.borrow_mut().add_child(&types);
543
544        assert!(root.borrow().check_for_conflicts("s"));
545        assert!(child2.borrow().check_for_conflicts("s"));
546        assert!(types.borrow().check_for_conflicts("s"));
547        assert!(!int.borrow().check_for_conflicts("s"));
548    }
549
550    #[test]
551    fn test_keyword_matching() {
552        let root = FSMNode::new_null(None);
553        let mut sign_token = NodeType::Keyword(Keyword::new("unsigned".to_string(), None));
554        let child = FSMNode::new(sign_token.clone(), &root);
555        sign_token = NodeType::Keyword(Keyword::new("signed".to_string(), None));
556
557        let child2 = FSMNode::new(sign_token, &root);
558        let types = FSMNode::new_required(NodeType::Null, &child);
559
560        let int = FSMNode::new_keyword_with_parent("int".to_string(), types.clone());
561        let float = FSMNode::new_keyword_with_parent("short".to_string(), types.clone());
562        root.borrow_mut().add_child(&types);
563        child2.borrow_mut().add_child(&types);
564
565        let mut cursor = FSMCursor::new(&root);
566        assert!(cursor.advance('s').is_none());
567        assert!(cursor.advance('h').is_some());
568        let mut cursor = FSMCursor::new(&root);
569        assert!(cursor.advance('u').is_some());
570        assert!(cursor.advance('s').is_some());
571    }
572
573    #[test]
574    fn test_deep_clone() {
575        let root = FSMNode::new_null(None);
576        let mut sign_token = NodeType::Keyword(Keyword::new("unsigned".to_string(), None));
577        let child = FSMNode::new(sign_token.clone(), &root);
578        sign_token = NodeType::Keyword(Keyword::new("signed".to_string(), None));
579
580        let child2 = FSMNode::new(sign_token, &root);
581        let types = FSMNode::new_required(NodeType::Null, &child);
582        println!("hi?");
583        FSMNode::add_child_cycle_safe(&types, &root);
584        let cloned_root = root.borrow().deep_clone();
585        let root = root.borrow();
586        let cloned_root = cloned_root.borrow();
587        assert_eq!(root.value, cloned_root.value);
588        // TODO: make this go all the way through the tree
589        for (i, child) in root.children.iter().enumerate() {
590            assert_eq!(child.borrow().value, cloned_root.children[i].borrow().value);
591        }
592    }
593
594    #[test]
595    fn simple_full() {
596        let bnf = r"
597        t1 ::= t2 | t3;
598        t2 ::= 'r' t3;
599        t3 ::= 'a';
600        ";
601        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
602        let mut cursor = FSMCursor::new(&root);
603        assert_eq!("r", cursor.advance('r').unwrap());
604        assert_eq!("a", cursor.advance('a').unwrap());
605        assert!(cursor.is_done());
606    }
607
608    #[test]
609    fn test_optional() {
610        let bnf = r"
611        t1 ::= 't' ( 'e' t2 )? 't';
612        t2 ::= 's' ( t3 )?;
613        t3 ::= 'a';
614        ";
615        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
616        let mut cursor = FSMCursor::new(&root);
617        assert_eq!("t", cursor.advance('t').unwrap());
618        assert_eq!("t", cursor.advance('t').unwrap());
619        assert!(cursor.is_done());
620
621        let mut cursor = FSMCursor::new(&root);
622        assert_eq!("t", cursor.advance('t').unwrap());
623        assert_eq!("e", cursor.advance('e').unwrap());
624        assert_eq!("s", cursor.advance('s').unwrap());
625        assert_eq!("a", cursor.advance('a').unwrap());
626        assert_eq!("t", cursor.advance('t').unwrap());
627        assert!(cursor.is_done());
628
629        let mut cursor = FSMCursor::new(&root);
630        assert_eq!("t", cursor.advance('t').unwrap());
631        assert_eq!("e", cursor.advance('e').unwrap());
632        assert_eq!("s", cursor.advance('s').unwrap());
633        assert_eq!("t", cursor.advance('t').unwrap());
634        assert!(cursor.is_done());
635    }
636
637    #[test]
638    fn test_optional2() {
639        let bnf = r"
640        t1 ::= 'te' t2 't';
641        t2 ::= ( 's' )?; 
642        ";
643        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
644        let mut cursor = FSMCursor::new(&root);
645        assert_eq!("te", cursor.advance('t').unwrap());
646        assert_eq!("t", cursor.advance('t').unwrap());
647        assert!(cursor.is_done());
648        let mut cursor = FSMCursor::new(&root);
649        assert_eq!("te", cursor.advance('t').unwrap());
650        assert_eq!("s", cursor.advance('s').unwrap());
651        assert_eq!("t", cursor.advance('t').unwrap());
652        assert!(cursor.is_done());
653    }
654
655    // you are the bane of my existence. If I ever had the chance to erase
656    // something from the universe permanently, I would erase recursive bnf terminal definitions.
657    // There is no reason this is so incredibly hard to parse.
658    #[test]
659    fn test_sql() {
660        let bnf = r"
661        query ::= select | insert;
662        select ::= 'SELECT' '*' | collist 'FROM' #'^.*$' ';';
663        insert ::= 'INSERT INTO' #'^.*$' ' ' 'VALUES' '(' collist ')';
664        collist ::= col ( ',' collist )?;
665        col ::= #'^.*[, ]$';
666    ";
667        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
668        root.borrow().dbg();
669        let mut cursor = FSMCursor::new(&root);
670        assert_eq!("SELECT", cursor.advance('S').unwrap());
671        assert_eq!(None, cursor.advance('a'));
672        assert_eq!(",", cursor.advance(',').unwrap());
673        assert_eq!(None, cursor.advance('b'));
674        cursor.advance(' ');
675        assert_eq!("FROM", cursor.advance('F').unwrap());
676        cursor.advance('a');
677        assert_eq!(";", cursor.advance(';').unwrap());
678        assert!(cursor.is_done());
679    }
680
681    #[test]
682    fn test_repeat() {
683        let bnf = r"
684        t1 ::= 't' { 'e' } 'st';
685    ";
686        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
687        // >:3
688        for i in 0..=30 {
689            let mut cursor = FSMCursor::new(&root);
690            assert_eq!("t", cursor.advance('t').unwrap());
691            for _ in 0..i {
692                assert_eq!("e", cursor.advance('e').unwrap());
693            }
694            assert_eq!("st", cursor.advance('s').unwrap());
695            assert!(cursor.is_done());
696        }
697    }
698
699    #[test]
700    fn test_terminal() {
701        let terms: usize = 100;
702        let mut bnf = String::with_capacity(terms * 14);
703        for i in 1..terms {
704            bnf.push_str(&format!("t{i:0>3} ::= t{:0>3};\n", i + 1));
705        }
706        bnf.push_str(&format!("t{terms:0>3} ::= 't' 'st';"));
707        println!("{bnf}");
708        let root = frontend::create_graph_from_ebnf(&bnf).unwrap();
709        let mut cursor = FSMCursor::new(&root);
710        assert_eq!("t", cursor.advance('t').unwrap());
711        assert_eq!("st", cursor.advance('s').unwrap());
712        assert!(cursor.is_done());
713    }
714
715    fn util_check_str(root: &FSMRc<FSMLock<FSMNode>>, str: &str) {
716        let mut cursor = FSMCursor::new(root);
717        for char in str.chars() {
718            cursor.advance(char);
719        }
720        assert!(cursor.is_done())
721    }
722
723    #[test]
724    fn test_combi() {
725        let bnf = r"
726        t1 ::= ( 'u' | 'a' | 'o' ) { 'w' | 'v' } ( 'u' | 'a' | 'o' );
727    ";
728        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
729        util_check_str(&root, "uwu");
730        util_check_str(&root, "owo");
731        util_check_str(&root, "owwwwwo");
732        util_check_str(&root, "owwwwwu");
733    }
734
735    #[test]
736    fn test_repeat_multiple() {
737        let bnf = r"
738        t1 ::= 't' t2 't';
739        t2 ::= 'oas' | ( 'e' { 'a' 's' } );
740    ";
741        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
742        let mut cursor = FSMCursor::new(&root);
743        assert_eq!("t", cursor.advance('t').unwrap());
744        assert_eq!("oas", cursor.advance('o').unwrap());
745        assert_eq!("t", cursor.advance('t').unwrap());
746        assert!(cursor.is_done());
747
748        let mut cursor = FSMCursor::new(&root);
749        assert_eq!("t", cursor.advance('t').unwrap());
750        assert_eq!("e", cursor.advance('e').unwrap());
751        assert_eq!("a", cursor.advance('a').unwrap());
752        assert_eq!("s", cursor.advance('s').unwrap());
753        assert_eq!("a", cursor.advance('a').unwrap());
754        assert_eq!("s", cursor.advance('s').unwrap());
755        assert_eq!("t", cursor.advance('t').unwrap());
756        assert!(cursor.is_done());
757    }
758
759    #[test]
760    fn test_userdefs() {
761        let bnf = r"
762        t1 ::= ( #'[0-9]' 't' ) | ( #'[a-z]' 'e' );
763    ";
764        let root = frontend::create_graph_from_ebnf(bnf).unwrap();
765        let mut cursor = FSMCursor::new(&root);
766        assert_eq!(None, cursor.advance('1'));
767        assert_eq!("t", cursor.advance('t').unwrap());
768        assert!(cursor.is_done());
769
770        let mut cursor = FSMCursor::new(&root);
771        assert_eq!(None, cursor.advance('a'));
772        assert_eq!("e", cursor.advance('e').unwrap());
773        assert!(cursor.is_done());
774    }
775    fn test_minify() {
776        let root = FSMNode::new_null(None);
777        let child = FSMNode::new_null(Some(&root));
778        let child = FSMNode::new_keyword_with_parent("asdf".to_string(), child);
779        // minify
780        root.borrow().dbg();
781        FSMNode::minify(&root);
782        root.borrow().dbg();
783        assert_eq!(Null, root.borrow().value);
784        assert_eq!(
785            Keyword(Keyword::new("asdf".to_string(), None)),
786            root.borrow().children[0].borrow().value
787        );
788        assert_eq!(1, root.borrow().children.len())
789    }
790
791    #[test]
792    fn test_minify_multiple() {
793        let root = FSMNode::new_null(None);
794        let child = FSMNode::new_null(Some(&root));
795        let child = FSMNode::new_null(Some(&child));
796        let child = FSMNode::new_keyword_with_parent("asdf".to_string(), child);
797        // minify
798        root.borrow().dbg();
799        FSMNode::minify(&root);
800        root.borrow().dbg();
801        assert_eq!(Null, root.borrow().value);
802        assert_eq!(
803            Keyword(Keyword::new("asdf".to_string(), None)),
804            root.borrow().children[0].borrow().value
805        );
806        assert_eq!(1, root.borrow().children.len())
807    }
808
809    #[test]
810    fn test_minify_cycles() {
811        let root = FSMNode::new_null(None);
812        let child = FSMNode::new_null(Some(&root));
813        let child2 = FSMNode::new_null(Some(&child));
814        let child = FSMNode::new_keyword_with_parent("asdf".to_string(), child2.clone());
815        FSMNode::add_child_cycle_safe(&child, &child2);
816        FSMNode::minify(&root);
817
818        assert_eq!(Null, root.borrow().value);
819        assert_eq!(
820            Keyword(Keyword::new("asdf".to_string(), None)),
821            root.borrow().children[0].borrow().value
822        );
823        assert_eq!(1, root.borrow().children.len());
824        assert_eq!(1, root.borrow().children[0].borrow().children.len());
825    }
826
827    #[test]
828    fn test_userdef_links() {
829        let root = create_graph_from_ebnf(
830            r"
831     main ::= #'[0-9]+' ( ('-' 'test') | (';' 'uwu') );
832",
833        )
834        .unwrap();
835        let mut cursor = FSMCursor::new(&root);
836        for i in 0..=9 {
837            assert_eq!(None, cursor.advance(i.to_string().chars().nth(0).unwrap()));
838        }
839        let mut cursor2 = cursor.clone();
840        assert_eq!("-", cursor.advance('-').unwrap());
841        assert_eq!("test", cursor.advance('t').unwrap());
842        assert_eq!(";", cursor2.advance(';').unwrap());
843        assert_eq!("uwu", cursor2.advance('u').unwrap());
844        root.borrow().dbg();
845    }
846
847    #[test]
848    fn test_fancy_regex_usecase() {
849        let root = create_graph_from_ebnf(
850            r"
851     main ::= (#'[0-9]+' 'uwu') | (#'[a-z]' 'awa');
852",
853        )
854        .unwrap();
855        let mut cursor = FSMCursor::new(&root);
856        let mut cursor2 = cursor.clone();
857        assert_eq!(None, cursor.advance('0'));
858        assert_eq!("uwu", cursor.advance('u').unwrap());
859        assert_eq!(None, cursor2.advance('b'));
860        assert_eq!("awa", cursor2.advance('a').unwrap());
861        root.borrow().dbg();
862    }
863
864    #[test]
865    fn test_reset() {
866        let root = FSMNode::new_null(None);
867        let other = FSMNode::new_keyword_with_parent("int".to_string(), root.clone());
868        let _other = FSMNode::new_keyword_with_parent("asdf".to_string(), other.clone());
869        assert_eq!(root.borrow().children.len(), 1);
870        let mut cursor = FSMCursor::new(&root);
871        assert_eq!("int", cursor.advance('i').unwrap());
872        assert_eq!(None, cursor.advance('i'));
873        cursor.reset();
874        assert_eq!("int", cursor.advance('i').unwrap());
875    }
876}