use crate::test_grammar_helper::*; use crate::*; 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(()) } // We ignore this test by default as it is possibly involved with // printing to a graphviz file. #[ignore] #[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)?; // writeln!(lock, "Not printing nfa to nfa.gv")?; // nfa.print_viz("nfa.gv").map_err(Into::into) // Ok(()) } #[test] #[ignore] 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)?; nfa.print_viz("nfa_orig.gv")?; nfa.remove_epsilon(|label| label.is_none())?; nfa.print_viz("nfa_no_epsilon.gv")?; Ok(()) } #[test] #[ignore] 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)?; nfa.print_viz("nfa_orig.gv")?; nfa.remove_epsilon(|label| label.is_none())?; let accumulators: HashSet = accumulators.into_iter().collect(); println!("accumulators = {accumulators:?}"); let grammar_reserve_node = |node| accumulators.contains(&node); nfa.remove_dead(grammar_reserve_node)?; nfa.print_viz("nfa_no_dead.gv")?; Ok(()) } #[test] #[ignore] fn test_nulling() -> Result<(), Box> { let mut grammar = new_left_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)?; nfa.nulling(|label| { if let Some(label) = *label { match label { TNT::Ter(_) => false, // Panics if a non-terminal references an invalid node // here. TNT::Non(n) => grammar.is_nullable(n).unwrap(), } } else { true } })?; let grammar_reserve_nodes = |node| accumulators.contains(&node); writeln!(lock, "accumulators are {accumulators:?}")?; nfa.remove_epsilon(|label| label.is_none())?; nfa.remove_dead(grammar_reserve_nodes)?; writeln!(lock, "Printing nfa to nfa.gv")?; nfa.print_viz("nfa.gv")?; Ok(()) }