use crate::test_grammar_helper::*; use crate::*; use graph::LabelGraph; use nfa::Nfa; use std::{ collections::HashSet, io::{stdout, Write}, }; #[test] fn test_regex() -> Result<(), Box> { let mut grammar = new_grammar()?; let vec_of_regexps = new_closure_regex(&mut grammar)?; let mut lock = stdout().lock(); writeln!(lock, "grammar firsts: {:?}", grammar.firsts)?; writeln!(lock, "grammar first nodes: {:?}", grammar.first_nodes)?; writeln!(lock, "grammar:")?; writeln!(lock, "{grammar}")?; for regex in vec_of_regexps.into_iter().skip(1) { writeln!( lock, "regex: {}", regex.to_string_with(|tnt| format!("{tnt}"))? )?; // println!("regex: {regex:?}",); writeln!(lock, "regex len = {}", regex.nodes_len())?; } Ok(()) } #[test] fn test_nfa() -> Result<(), Box> { let mut grammar = new_notes_grammar()?; let closure = new_closure_regex(&mut grammar)?; let mut lock = stdout().lock(); for regex in closure.iter() { writeln!( lock, "regex: {}", regex.to_string_with(|tnt| { match tnt { TNT::Ter(t) => { format!( "({})", grammar.name_of_tnt(grammar.unpack_tnt(t).unwrap()).unwrap() ) } TNT::Non(_) => { // hyper non-terminal format!("H({})", grammar.name_of_tnt(tnt).unwrap()) } } })? )?; // println!("regex: {regex:?}",); writeln!(lock, "regex len = {}", regex.nodes_len())?; } grammar .left_closure_to_nfa(&closure) .map(|_| ()) .map_err(Into::>::into)?; // let _nfa = grammar.left_closure_to_nfa(&closure)?; #[cfg(features = "test-print-viz")] { writeln!(lock, "Not printing nfa to nfa.gv")?; nfa.print_viz("nfa.gv") .map_err(Into::>::into)?; } Ok(()) } #[test] fn test_remove_epsilon() -> Result<(), Box> { let mut lock = stdout().lock(); let mut grammar = new_paren_grammar()?; writeln!(lock, "grammar:")?; writeln!(lock, "{grammar}")?; let closure = new_closure_regex(&mut grammar)?; let mut accumulator_value: usize = 0; for regex in closure.iter() { writeln!( lock, "regex: {}", regex.to_string_with(|tnt| { match tnt { TNT::Ter(t) => { format!( "({})", grammar.name_of_tnt(grammar.unpack_tnt(t).unwrap()).unwrap() ) } TNT::Non(_) => { // hyper non-terminal format!("({})", grammar.name_of_tnt(tnt).unwrap()) } } })? )?; writeln!(lock, "regex len = {}", regex.nodes_len())?; writeln!(lock, "offset = {accumulator_value}")?; accumulator_value += regex.nodes_len(); } writeln!(lock, "total = {accumulator_value}")?; let mut nfa = grammar.left_closure_to_nfa(&closure)?; #[cfg(features = "test-print-viz")] nfa.print_viz("nfa_orig.gv")?; nfa.remove_epsilon(|label| label.get_value().is_none())?; #[cfg(features = "test-print-viz")] nfa.print_viz("nfa_no_epsilon.gv")?; Ok(()) } #[test] fn test_remove_dead() -> Result<(), Box> { let mut grammar = new_paren_grammar()?; let closure = new_closure_regex(&mut grammar)?; let mut lock = stdout().lock(); let mut accumulator = 0usize; let mut accumulators = Vec::with_capacity(closure.len() + 1); accumulators.push(accumulator); for regex in closure.iter() { writeln!( lock, "regex: {}", regex.to_string_with(|tnt| { match tnt { TNT::Ter(t) => { format!( "({})", grammar.name_of_tnt(grammar.unpack_tnt(t).unwrap()).unwrap() ) } TNT::Non(_) => { // hyper non-terminal format!("({})", grammar.name_of_tnt(tnt).unwrap()) } } })? )?; // println!("regex: {regex:?}",); writeln!(lock, "regex len = {}", regex.nodes_len())?; accumulator += regex.nodes_len() * 2; accumulators.push(accumulator); } let mut nfa = grammar.left_closure_to_nfa(&closure)?; #[cfg(features = "test-print-viz")] nfa.print_viz("nfa_orig.gv")?; // nfa.remove_epsilon(|label| label.get_value().is_none())?; let accumulators: HashSet = accumulators.into_iter().collect(); println!("accumulators = {accumulators:?}"); let grammar_reserve_node = |node| accumulators.contains(&node); nfa.closure( |label| label.get_value().is_none(), true, |two_edges| two_edges.second_edge().2, |label| label.get_value().is_none(), )?; nfa.remove_dead(grammar_reserve_node)?; #[cfg(features = "test-print-viz")] nfa.print_viz("nfa_no_dead.gv")?; Ok(()) } #[test] fn test_nulling() -> Result<(), Box> { // TODO: Test more grammars. let mut grammar = new_right_recursive_grammar()?; let closure = new_closure_regex(&mut grammar)?; let mut lock = stdout().lock(); let mut accumulators = Vec::with_capacity(closure.len() + 1); accumulators.push(0); for regex in closure.iter() { writeln!( lock, "regex: {}", regex.to_string_with(|tnt| { match tnt { TNT::Ter(t) => { format!( "({})", grammar.name_of_tnt(grammar.unpack_tnt(t).unwrap()).unwrap() ) } TNT::Non(_) => { // hyper non-terminal format!("H({})", grammar.name_of_tnt(tnt).unwrap()) } } })? )?; // println!("regex: {regex:?}",); writeln!(lock, "regex len = {}", regex.nodes_len())?; accumulators.push(regex.nodes_len() * 2 + accumulators.last().unwrap()); } write!(lock, "nullables:")?; let mut first_time = true; for i in 0..(grammar.non_num()) { if grammar.is_nullable(i)? { if first_time { write!(lock, " ")?; } else { write!(lock, ", ")?; } write!(lock, " {i}")?; first_time = false; } } writeln!(lock)?; let accumulators: HashSet = accumulators.into_iter().collect(); let mut nfa = grammar.left_closure_to_nfa(&closure)?; let grammar_reserve_nodes = |node| accumulators.contains(&node); writeln!(lock, "accumulators are {accumulators:?}")?; let nullables: HashSet = (0..grammar.non_num()) .filter(|n| matches!(grammar.is_nullable(*n), Ok(true))) .collect(); nfa.closure( |label| { if let Some(label) = *label.get_value() { matches!(label, TNT::Non(n) if nullables.contains(&n)) } else { true } }, true, |two_edges| grammar.transform_label_null_epsilon(two_edges), |label| label.get_value().is_none(), )?; for (label, child_iter) in nfa.labels_of(18)? { writeln!(lock, "{label}: {child_iter:?}")?; } nfa.remove_dead(grammar_reserve_nodes)?; #[cfg(features = "test-print-viz")] { writeln!(lock, "Printing nfa to nfa.gv")?; nfa.print_viz("nfa.gv")?; } Ok(()) }