1use std::collections::HashMap;
2
3use debug_print::debug_println;
4use ebnf::{Expression, Grammar, Node, RegexExtKind, SymbolKind};
5use regex::Regex;
6
7use super::FSMLock;
8use super::FSMRc;
9use crate::FSMNode;
10
11pub fn print_parsed_ebnf(syntax: &str) {
12 let grammar = ebnf::get_grammar(&syntax).unwrap();
13 for node in grammar.expressions {
14 println!("{:?}", node);
15 }
16}
17
18enum TerminalState {
19 Stub,
20 Created,
21}
22
23fn handle_node(
24 grammar: &Grammar,
25 cur_node: &Node,
26 cur_root: &FSMRc<FSMLock<FSMNode>>,
27 terminals: &mut HashMap<String, (FSMRc<FSMLock<FSMNode>>, TerminalState)>,
28) -> FSMRc<FSMLock<FSMNode>> {
29 debug_println!("handle_node got {:?}", cur_node);
30 let ret = match &cur_node {
31 Node::String(str) => {
32 FSMNode::new_keyword_with_parent(str.to_string(), FSMRc::clone(cur_root))
33 }
34 Node::RegexString(r) => FSMNode::new_userdef(Regex::new(r).unwrap(), cur_root),
35 Node::Terminal(name) => {
36 if terminals.contains_key(name) {
37 debug_println!("Found {name} in cache!");
38 let term = terminals.get(name).unwrap();
39 let term_clone = match term.1 {
40 TerminalState::Stub => term.0.clone(),
41 TerminalState::Created => term.0.borrow().deep_clone(),
42 };
43 println!("linking back to {}", term_clone.borrow().short_id());
44 FSMNode::add_child_cycle_safe(cur_root, &term_clone);
45 println!("after add:");
46 cur_root.borrow().dbg();
47 term_clone
48 } else {
49 debug_println!("Creating terminal {name}...");
50 let terminal = find_terminal(&grammar, &name);
51 if terminal.is_none() {
52 panic!("Terminal reference '{name}' not found!");
53 }
54 let terminal = terminal.unwrap();
55 let term_root = FSMNode::new_null(None);
56 debug_println!("term_root: {}", term_root.borrow().short_id());
57 terminals.insert(
58 name.to_string(),
59 (FSMRc::clone(&term_root), TerminalState::Stub),
60 );
61 handle_node(grammar, &terminal.rhs, &term_root, terminals);
62 terminals.insert(
63 name.to_string(),
64 (FSMRc::clone(&term_root), TerminalState::Created),
65 );
66 debug_println!("Finish terminal");
67 debug_println!("young {}:", name);
68 term_root.borrow().dbg();
69 let ret = term_root.borrow().deep_clone();
70 FSMNode::add_child_cycle_safe(cur_root, &ret);
71 ret
72 }
73 }
74 Node::Multiple(nodes) => {
75 let mut cur_treenode = cur_root.clone();
76 nodes.iter().for_each(|node| {
77 debug_println!("Multiple at {node:?}");
78 let tree_bit = handle_node(grammar, &node, &cur_treenode, terminals);
79 debug_println!("Multiple got back:");
80 tree_bit.borrow().dbg();
81 cur_treenode = tree_bit.borrow().race_to_leaf().unwrap_or(tree_bit.clone());
84 debug_println!("cur_treenode now at: {}", cur_treenode.borrow().short_id());
85 });
86 cur_treenode
87 }
88 Node::RegexExt(node, RegexExtKind::Optional) | Node::Optional(node) => {
89 let tree_bit = handle_node(grammar, &node, cur_root, terminals);
90 let dummy = FSMNode::new_null(None);
91 FSMNode::add_child_to_all_leaves(&tree_bit, &dummy);
92 FSMNode::add_child_cycle_safe(&cur_root, &dummy);
93 tree_bit
94 }
95 Node::Symbol(n1, SymbolKind::Concatenation, n2) => {
96 let t1 = handle_node(grammar, &n1.to_owned(), &cur_root, terminals);
97 let t2 = handle_node(grammar, &n2.to_owned(), &t1, terminals);
98 t1
99 }
100 Node::Symbol(n1, SymbolKind::Alternation, n2) => {
101 let root = FSMNode::new_null(Some(cur_root));
102 let t1 = handle_node(grammar, &n1.to_owned(), &root, terminals);
103 let t2 = handle_node(grammar, &n2.to_owned(), &root, terminals);
104 let child = FSMNode::new_null(None);
105 debug_println!("Alternation dummy child: {}", child.borrow().short_id());
106 FSMNode::add_child_to_all_leaves(&root, &child);
107 debug_println!("Finished alternation:");
108 root.borrow().dbg();
109 root
110 }
111 Node::Group(node) => handle_node(grammar, node, cur_root, terminals),
112 Node::Repeat(node) => {
113 let dummy_parent = FSMNode::new_null(Some(&cur_root));
116 let subroot = handle_node(grammar, &node, &dummy_parent, terminals);
117
118 let dummy = FSMNode::new_null(None);
119 debug_println!("Repeat dummy child: {}", dummy.borrow().short_id());
120 FSMNode::add_child_to_all_leaves(&subroot, &dummy);
121 FSMNode::add_child_cycle_safe(&cur_root, &dummy);
123
124 FSMNode::add_child_to_all_leaves(&subroot, &dummy_parent);
125 dummy_parent
126 }
127 _ => {
128 eprintln!("Unimplemented: {cur_node:?}");
129 todo!()
130 }
131 };
132 ret
133}
134
135fn find_terminal<'a>(grammer: &'a Grammar, name: &'a str) -> Option<&'a Expression> {
136 grammer.expressions.iter().find(|expr| expr.lhs == name)
137}
138
139pub fn create_graph_from_ebnf(ebnf: &str) -> Result<FSMRc<FSMLock<FSMNode>>, String> {
140 match ebnf::get_grammar(ebnf) {
141 Ok(grammar) => {
142 let root = FSMNode::new_null(None);
143 let root_node = grammar.expressions.get(0).expect("Empty BNF!");
144 let mut terminals = HashMap::new();
145 handle_node(
146 &grammar,
147 &Node::Terminal(root_node.lhs.to_owned()),
148 &root,
149 &mut terminals,
150 );
151 FSMNode::add_child_to_all_leaves(&root, &FSMNode::new_null(None));
153 FSMNode::minify(&root);
154 FSMNode::set_userdef_links(&root);
155 debug_println!("Total node cnt: {}", FSMNode::node_cnt(&root));
156 Ok(root)
161 }
162 Err(err) => Err(err.to_string()),
163 }
164}