diff --git a/docs/.configotron-whiteboard.autosave.xopp b/docs/.configotron-whiteboard.autosave.xopp new file mode 100644 index 0000000..b521613 Binary files /dev/null and b/docs/.configotron-whiteboard.autosave.xopp differ diff --git a/docs/configotron-whiteboard.xopp b/docs/configotron-whiteboard.xopp index 29556c8..45d33e2 100644 Binary files a/docs/configotron-whiteboard.xopp and b/docs/configotron-whiteboard.xopp differ diff --git a/src/configotron/fsm/builder/mod.rs b/src/configotron/fsm/builder/mod.rs new file mode 100644 index 0000000..6ecd7a0 --- /dev/null +++ b/src/configotron/fsm/builder/mod.rs @@ -0,0 +1,135 @@ +use std::{cell::RefCell, collections::HashSet, rc::{Rc, Weak}}; + +use crate::configotron::fsm::{FSMState, FSMStateRef, FSM}; + +pub mod numbers; + +pub fn elimate_unused_states(fsm: &mut FSM) { + let start = fsm.start.as_ref().unwrap(); + let mut used: HashSet = HashSet::new(); + + pub fn explore_states(s: Weak>, used: &mut HashSet) -> Option<()> { + + let s_rc = s.upgrade()?; + let s_borrow = s_rc.borrow(); + let t = s_borrow.transition.as_ref()?; + let name = s_borrow.name.clone(); + + if !used.contains(&name) { + used.insert(name); + + for i in 0..(128 as u8) { + explore_states(t.get_next(i), used); + } + } + Some(()) + } + + explore_states(Rc::downgrade(start), &mut used); + + let mut new_state_array: Vec = Vec::new(); + + fsm.states.drain(..).for_each(|s| { + let s_name = s.borrow().name.clone(); + if used.contains(&s_name) { + new_state_array.push(s); + } + }); + + fsm.states = new_state_array; +} + + +#[cfg(test)] +mod test { + use std::rc::Rc; + + use graphviz_rust::cmd::Format; + + use crate::configotron::fsm::{builder::elimate_unused_states, masking::{MaskPresets, TransitionMask}, new_state_ref, test::debug_file_dump, transition::FSMTranistion, FSMState, FSMStateAction, FSM}; + + #[test] + fn state_elimitnation() { + let z0 = new_state_ref(FSMState::new( + "z0".to_string(), FSMStateAction::Terminal, + )); + let z1 = new_state_ref(FSMState::new( + "z1".to_string(), FSMStateAction::Terminal, + )); + let z2 = new_state_ref(FSMState::new( + "z2".to_string(), FSMStateAction::Terminal, + )); + let z3 = new_state_ref(FSMState::new( + "z3".to_string(), FSMStateAction::Terminal, + )); + let z4 = new_state_ref(FSMState::new( + "z4".to_string(), FSMStateAction::Terminal, + )); + let z5 = new_state_ref(FSMState::new( + "z5".to_string(), FSMStateAction::Terminal, + )); + + let start = z0.clone(); + + /* + * Links: + * (z0) -> (z1) + * (z1) -> (z2), (z3) + * (z2) -> (z2) + * (z3) -> (z1) + * X (z4) -> (z3) + * X (z5) -> (z5) + */ + + z0.borrow_mut().set_transitions({ + let t = FSMTranistion::new(Rc::downgrade(&z1)); + t + }); + z1.borrow_mut().set_transitions({ + let mut t = FSMTranistion::new(Rc::downgrade(&z2)); + t.apply(TransitionMask::from(MaskPresets::LowerCase), Rc::downgrade(&z3)); + t + }); + z2.borrow_mut().set_transitions({ + let t = FSMTranistion::new(Rc::downgrade(&z2)); + t + }); + z3.borrow_mut().set_transitions({ + let t = FSMTranistion::new(Rc::downgrade(&z1)); + t + }); + z4.borrow_mut().set_transitions({ + let t = FSMTranistion::new(Rc::downgrade(&z3)); + t + }); + z5.borrow_mut().set_transitions({ + let t = FSMTranistion::new(Rc::downgrade(&z5)); + t + }); + + + let state_prev = vec![z0.clone(), z1.clone(), z2.clone(), z3.clone(), z4.clone(), z5.clone()]; + let state_after = vec![z0.clone(), z1.clone(), z2.clone(), z3.clone()]; + + let mut fsm = FSM { + states: state_prev, + name: "test_fsm".to_string(), + start: Some(start) + }; + + debug_file_dump(fsm.render_graph(Format::Svg).unwrap(), "/tmp/state_elimitiation_before.svg".to_string()); + + elimate_unused_states(&mut fsm); + + debug_file_dump(fsm.render_graph(Format::Svg).unwrap(), "/tmp/state_elimitiation_after.svg".to_string()); + + + assert_eq!(fsm.states.len(), state_after.len()); + + for (i, j) in fsm.states.iter().zip(state_after) { + assert_eq!(i.borrow().name, j.borrow().name) + } + + + } +} \ No newline at end of file diff --git a/src/configotron/fsm/builder/numbers.rs b/src/configotron/fsm/builder/numbers.rs new file mode 100644 index 0000000..075eac6 --- /dev/null +++ b/src/configotron/fsm/builder/numbers.rs @@ -0,0 +1,203 @@ +use std::{rc::Rc}; + +use crate::configotron::fsm::{builder::elimate_unused_states, masking::{MaskPresets, TransitionMask}, new_state_ref, transition::FSMTranistion, FSMState, FSMStateAction, FSMStateRef}; + +use super::super::FSM; + +fn number_of_digits(i: i32) -> u32 { + if i == 0 { + 1 + } else { + let mut n = i.abs(); + let mut digits = 0; + while n > 0 { // Yes, with floating point math it does not work, sorry ;( + n /= 10; + digits += 1; + } + digits + } +} + +fn nth_decimal_digit(num: u32, n: u32) -> u32 { + let num_digits = number_of_digits(num as i32); + if n >= num_digits { + return 0; + } + let divisor = 10u32.pow(num_digits - n - 1); + (num / divisor) % 10 +} + +fn create_fsm_number_upperbound(max: u32) -> FSM { + let length_of_number = number_of_digits(max as i32); + + // Creating All states + let error_state = new_state_ref(FSMState::new("e".to_string(), FSMStateAction::Error)); + let goal_state = new_state_ref(FSMState::new("g".to_string(), FSMStateAction::Terminal)); + + let mut main_line: Vec = Vec::new(); + let mut side_line: Vec = Vec::new(); + + // Create and Link Main to side + for i in 0..length_of_number { + let digit = nth_decimal_digit(max, i); + + let new_main_state = new_state_ref(FSMState::new( + format!("m{}", i), FSMStateAction::Terminal)); + let new_side_state = new_state_ref(FSMState::new( + format!("s{}", i), FSMStateAction::Terminal)); + + let mut main_state_transition = FSMTranistion::new(Rc::downgrade(&error_state)); + + if digit > 0 { + main_state_transition.apply(TransitionMask::from(MaskPresets::NumberRange(0..=(digit as u8 - 1))), Rc::downgrade(&new_side_state)); + } + + new_main_state.borrow_mut().set_transitions( + main_state_transition + ); + + new_side_state.borrow_mut().set_transitions( + FSMTranistion::new(Rc::downgrade(&error_state)) + ); + + main_line.push(new_main_state.clone()); + side_line.push(new_side_state.clone()); + }; + + // Link Main to main, side to side + for (i, + ( + (prev_main, next_main), + (prev_side, next_side) + ) + ) in + main_line.iter().zip(main_line.iter().skip(1)) + .zip(side_line.iter().zip(side_line.iter().skip(1))) + .enumerate() { + let digit = nth_decimal_digit(max, i as u32); + + match &mut prev_main.borrow_mut().transition { + None => {}, + Some(t) => { + + if digit < 9 { + t.apply( + TransitionMask::from(MaskPresets::NumberRange((digit as u8 + 1)..=9)), + Rc::downgrade(next_side) + ); + } + + t.apply( + TransitionMask::from(MaskPresets::Char(std::char::from_digit(digit, 10).unwrap())), + Rc::downgrade(next_main) + ); + } + } + + match &mut prev_side.borrow_mut().transition { + None => {}, + Some(t) => { + t.apply( + TransitionMask::from(MaskPresets::Numbers), + Rc::downgrade(next_side) + ); + } + } + } + + // Link last main to side, goal + match &mut main_line.last() { + Some(main_last) => { + let last_digit = max % 10; + match &mut main_last.borrow_mut().transition { + Some(t) => { + t.apply(TransitionMask::from(MaskPresets::Char( + std::char::from_digit(last_digit, 10).unwrap() + )), Rc::downgrade(&goal_state)); + + t.apply(TransitionMask::from(MaskPresets::NumberRange(0..=(last_digit as u8))), + Rc::downgrade(&goal_state) + ); + }, + _ => {} + } + }, + _ => {} + } + + // Link goal to error + goal_state.borrow_mut().set_transitions(FSMTranistion::new(Rc::downgrade(&error_state))); + + // Linking error to error + error_state.borrow_mut().set_transitions(FSMTranistion::new(Rc::downgrade(&error_state))); + + // Combinding in one array + let mut states: Vec>> = vec![error_state, goal_state]; + let first_state: Option = match main_line.first() { + None => None, + Some(first) => { + Some(first.clone()) + } + }; + states.append(&mut main_line); + states.append(&mut side_line); + + let mut fsm = FSM { + name: format!("FSM_UpperBound_{}", max), + states: states, + start: first_state + }; + + elimate_unused_states(&mut fsm); + + fsm +} + + +#[cfg(test)] +mod test { + use graphviz_rust::cmd::Format; + + use crate::configotron::fsm::{builder::numbers::{create_fsm_number_upperbound, number_of_digits}, run::run_fsm, test::debug_file_dump, FSMStateAction}; + + + #[test] + fn build_upper_bound() { + + for max in vec![4026, 124, 9999, 1000, 0, 42398] { + let fsm = create_fsm_number_upperbound(max); + let data = fsm.render_graph(Format::Svg).unwrap(); + println!("Testing Lower Bound FSM {}", max); + + for i in 0..=(if max == 0 {10} else {max * 10} ) { + + assert_eq!(run_fsm(&i.to_string(), &fsm), if i <= max { + FSMStateAction::Terminal + } else { + FSMStateAction::Error + }); + } + + // Testing against refernce machine + let file_name = format!("build_number_upper_bound_{}.svg", max); + debug_file_dump(data.clone(), format!("/tmp/{}", file_name).to_string()); + + } + } + + #[test] + fn number_of_digits_test() { + assert_eq!(number_of_digits(0), 1); + assert_eq!(number_of_digits(9), 1); + assert_eq!(number_of_digits(10), 2); + assert_eq!(number_of_digits(99), 2); + assert_eq!(number_of_digits(100), 3); + assert_eq!(number_of_digits(-1), 1); + assert_eq!(number_of_digits(-9), 1); + assert_eq!(number_of_digits(-10), 2); + assert_eq!(number_of_digits(-99), 2); + assert_eq!(number_of_digits(-100), 3); + assert_eq!(number_of_digits(123456), 6); + assert_eq!(number_of_digits(-123456), 6); + } +} \ No newline at end of file diff --git a/src/configotron/fsm/masking.rs b/src/configotron/fsm/masking.rs index 8bf1711..05911a1 100644 --- a/src/configotron/fsm/masking.rs +++ b/src/configotron/fsm/masking.rs @@ -9,6 +9,7 @@ pub enum MaskPresets { UpperCase, AllHumanReadable, Numbers, + NumberRange(RangeInclusive), SpecialChars, WhiteSpace, LineTermination, @@ -33,6 +34,11 @@ impl From for TransitionMask { MaskPresets::AnyCase => { set_range(0x41..=0x5a); // UpperCase set_range(0x61..=0x7a); // LowerCase + }, + MaskPresets::NumberRange(r) => { + let start = (*r.start() as i32) + 0x30; + let end = (*r.end() as i32) + 0x30; + set_range(start..=end); } MaskPresets::LowerCase => { set_range(0x61..=0x7a); // LowerCase diff --git a/src/configotron/fsm/mod.rs b/src/configotron/fsm/mod.rs index 6065258..700f433 100644 --- a/src/configotron/fsm/mod.rs +++ b/src/configotron/fsm/mod.rs @@ -1,25 +1,33 @@ pub mod masking; pub mod transition; +pub mod builder; +pub mod run; use graphviz_rust::{ - dot_structures::{Attribute, Edge, EdgeTy, Graph, Id, NodeId, Stmt, Vertex}, - exec, - printer::PrinterContext, + cmd::Layout, dot_structures::{Attribute, Edge, EdgeTy, Graph, Id, NodeId, Stmt, Vertex}, exec, printer::PrinterContext }; use transition::FSMTranistion; use std::{cell::RefCell, rc::Rc}; +pub type FSMStateRef = Rc>; + +pub fn new_state_ref(s: FSMState) -> FSMStateRef { + Rc::new(RefCell::new(s)) +} + #[derive(Debug, Clone)] pub struct FSM { name: String, - states: Vec>>, + states: Vec, + start: Option } impl FSM { - pub fn new(state: Vec>>, name: &str) -> Self { + pub fn new(state: Vec, name: &str) -> Self { FSM { states: state, name: name.to_string(), + start: None } } @@ -34,24 +42,43 @@ impl FSM { stmts.push(Stmt::Node(graphviz_rust::dot_structures::Node { id: NodeId(Id::Plain(s_borrowed.to_graph_label()), None), attributes: { - let mut res = vec![Attribute( - Id::Plain("label".to_string()), - Id::Plain(s_borrowed.to_graph_label()), - )]; + let mut res = vec![]; + let label = s_borrowed.to_graph_label(); + match s_borrowed.action { - FSMStateAction::NONE => { + FSMStateAction::None => { res.push(Attribute( Id::Plain("shape".to_string()), Id::Plain("circle".to_string()), )); } - FSMStateAction::TERMINAL => { + FSMStateAction::Error => { + res.push(Attribute( + Id::Plain("shape".to_string()), + Id::Plain("circle".to_string()), + )); + } + FSMStateAction::Reset => { + res.push(Attribute( + Id::Plain("shape".to_string()), + Id::Plain("circle".to_string()), + )); + } + FSMStateAction::Terminal => { res.push(Attribute( Id::Plain("shape".to_string()), Id::Plain("doublecircle".to_string()), )); } } + + res.push( + Attribute( + Id::Plain("label".to_string()), + Id::Plain(label), + ) + ); + res }, })); @@ -100,16 +127,21 @@ impl FSM { println!("{}", graphviz_rust::print(g.clone(), &mut ctx)); - let data = exec(g, &mut ctx, vec![format.into()])?; + let data = exec(g, &mut ctx, vec![ + format.into(), + graphviz_rust::cmd::CommandArg::Layout(Layout::Dot) + ])?; Ok(data) } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum FSMStateAction { - NONE, - TERMINAL, + None, + Terminal, + Error, + Reset } #[derive(Debug, Clone)] @@ -150,23 +182,28 @@ mod test { use super::transition::FSMTranistion; use super::masking::{MaskPresets, TransitionMask}; + pub fn debug_file_dump(d: Vec, filepath: String) { + let mut output_file = std::fs::File::create(filepath).unwrap(); + output_file.write_all(&d).unwrap(); + } + #[test] fn simple_fsm_render() { let z0 = Rc::new(RefCell::new(FSMState::new( "z0".to_string(), - FSMStateAction::NONE, + FSMStateAction::None, ))); let z1 = Rc::new(RefCell::new(FSMState::new( "z1".to_string(), - FSMStateAction::NONE, + FSMStateAction::None, ))); let z2 = Rc::new(RefCell::new(FSMState::new( "z2".to_string(), - FSMStateAction::TERMINAL, + FSMStateAction::Terminal, ))); let z3 = Rc::new(RefCell::new(FSMState::new( "z3".to_string(), - FSMStateAction::NONE, + FSMStateAction::None, ))); let mut z0_transisions = FSMTranistion::new_from_mask( diff --git a/src/configotron/fsm/run.rs b/src/configotron/fsm/run.rs new file mode 100644 index 0000000..19e335c --- /dev/null +++ b/src/configotron/fsm/run.rs @@ -0,0 +1,18 @@ +use std::{cell::RefCell, rc::{Rc, Weak}}; + +use crate::configotron::fsm::{FSMState, FSMStateAction, FSM}; + +pub fn run_fsm(input: &str, fsm: &FSM) -> FSMStateAction { + let mut state: Weak> = Rc::downgrade(fsm.start.as_ref().unwrap()); + + for c in input.chars() { + let n = c as u8; + if c.is_ascii() && n <= 0x7F { + let rc_state = state.upgrade().unwrap(); + let s = rc_state.borrow(); + state = s.transition.as_ref().unwrap().get_next(n); + } + }; + + state.upgrade().unwrap().borrow().action.clone() +} diff --git a/src/configotron/fsm/transition.rs b/src/configotron/fsm/transition.rs index f07e020..8d65551 100644 --- a/src/configotron/fsm/transition.rs +++ b/src/configotron/fsm/transition.rs @@ -24,6 +24,10 @@ impl FSMTranistion { FSMTranistion { array } } + pub fn get_next(&self, c: u8) -> StateRef { + self.array[c as usize].clone() + } + pub fn new(default: StateRef) -> Self { let array: [StateRef; 128] = std::array::from_fn(|_| Weak::clone(&default)); diff --git a/tests/ref/build_number_upper_bound_0.svg b/tests/ref/build_number_upper_bound_0.svg new file mode 100644 index 0000000..a00b752 --- /dev/null +++ b/tests/ref/build_number_upper_bound_0.svg @@ -0,0 +1,61 @@ + + + + + + +root + + + +e + +e + + + +e->e + + +00-7f + + + +g + + +g + + + +g->e + + +00-7f + + + +m0 + + +m0 + + + +m0->e + + +00-'/','1'-7f + + + +m0->g + + +'0' + + + diff --git a/tests/ref/build_number_upper_bound_1000.svg b/tests/ref/build_number_upper_bound_1000.svg new file mode 100644 index 0000000..d465fca --- /dev/null +++ b/tests/ref/build_number_upper_bound_1000.svg @@ -0,0 +1,229 @@ + + + + + + +root + + + +e + +e + + + +e->e + + +00-7f + + + +g + + +g + + + +g->e + + +00-7f + + + +m0 + + +m0 + + + +m0->e + + +00-'/',':'-7f + + + +s1 + + +s1 + + + +m0->s1 + + +'2'-'9' + + + +s0 + + +s0 + + + +m0->s0 + + +'0' + + + +m1 + + +m1 + + + +m0->m1 + + +'1' + + + +s1->e + + +00-'/',':'-7f + + + +s2 + + +s2 + + + +s1->s2 + + +'0'-'9' + + + +s0->e + + +00-'/',':'-7f + + + +s0->s1 + + +'0'-'9' + + + +m1->e + + +00-'/',':'-7f + + + +m2 + + +m2 + + + +m1->m2 + + +'0' + + + +m1->s2 + + +'1'-'9' + + + +m2->e + + +00-'/',':'-7f + + + +s3 + + +s3 + + + +m2->s3 + + +'1'-'9' + + + +m3 + + +m3 + + + +m2->m3 + + +'0' + + + +s2->e + + +00-'/',':'-7f + + + +s2->s3 + + +'0'-'9' + + + +s3->e + + +00-7f + + + +m3->e + + +00-'/','1'-7f + + + +m3->g + + +'0' + + + diff --git a/tests/ref/build_number_upper_bound_124.svg b/tests/ref/build_number_upper_bound_124.svg new file mode 100644 index 0000000..5265952 --- /dev/null +++ b/tests/ref/build_number_upper_bound_124.svg @@ -0,0 +1,187 @@ + + + + + + +root + + + +e + +e + + + +e->e + + +00-7f + + + +g + + +g + + + +g->e + + +00-7f + + + +m0 + + +m0 + + + +m0->e + + +00-'/',':'-7f + + + +m1 + + +m1 + + + +m0->m1 + + +'1' + + + +s0 + + +s0 + + + +m0->s0 + + +'0' + + + +s1 + + +s1 + + + +m0->s1 + + +'2'-'9' + + + +m1->e + + +00-'/',':'-7f + + + +m1->s1 + + +'0'-'1' + + + +s2 + + +s2 + + + +m1->s2 + + +'3'-'9' + + + +m2 + + +m2 + + + +m1->m2 + + +'2' + + + +s0->e + + +00-'/',':'-7f + + + +s0->s1 + + +'0'-'9' + + + +s1->e + + +00-'/',':'-7f + + + +s1->s2 + + +'0'-'9' + + + +s2->e + + +00-7f + + + +m2->e + + +00-'/','5'-7f + + + +m2->g + + +'0'-'4' + + + diff --git a/tests/ref/build_number_upper_bound_4026.svg b/tests/ref/build_number_upper_bound_4026.svg new file mode 100644 index 0000000..f8eec19 --- /dev/null +++ b/tests/ref/build_number_upper_bound_4026.svg @@ -0,0 +1,236 @@ + + + + + + +root + + + +e + +e + + + +e->e + + +00-7f + + + +g + + +g + + + +g->e + + +00-7f + + + +m0 + + +m0 + + + +m0->e + + +00-'/',':'-7f + + + +m1 + + +m1 + + + +m0->m1 + + +'4' + + + +s1 + + +s1 + + + +m0->s1 + + +'5'-'9' + + + +s0 + + +s0 + + + +m0->s0 + + +'0'-'3' + + + +m1->e + + +00-'/',':'-7f + + + +s2 + + +s2 + + + +m1->s2 + + +'1'-'9' + + + +m2 + + +m2 + + + +m1->m2 + + +'0' + + + +s1->e + + +00-'/',':'-7f + + + +s1->s2 + + +'0'-'9' + + + +s0->e + + +00-'/',':'-7f + + + +s0->s1 + + +'0'-'9' + + + +s2->e + + +00-'/',':'-7f + + + +s3 + + +s3 + + + +s2->s3 + + +'0'-'9' + + + +m2->e + + +00-'/',':'-7f + + + +m2->s2 + + +'0'-'1' + + + +m2->s3 + + +'3'-'9' + + + +m3 + + +m3 + + + +m2->m3 + + +'2' + + + +s3->e + + +00-7f + + + +m3->e + + +00-'/','7'-7f + + + +m3->g + + +'0'-'6' + + + \ No newline at end of file diff --git a/tests/ref/build_number_upper_bound_423968.svg b/tests/ref/build_number_upper_bound_423968.svg new file mode 100644 index 0000000..5d3b206 --- /dev/null +++ b/tests/ref/build_number_upper_bound_423968.svg @@ -0,0 +1,348 @@ + + + + + + +root + + + +e + +e + + + +e->e + + +00-7f + + + +g + + +g + + + +g->e + + +00-7f + + + +m0 + + +m0 + + + +m0->e + + +00-'/',':'-7f + + + +m1 + + +m1 + + + +m0->m1 + + +'4' + + + +s0 + + +s0 + + + +m0->s0 + + +'0'-'3' + + + +s1 + + +s1 + + + +m0->s1 + + +'5'-'9' + + + +m1->e + + +00-'/',':'-7f + + + +m1->s1 + + +'0'-'1' + + + +s2 + + +s2 + + + +m1->s2 + + +'3'-'9' + + + +m2 + + +m2 + + + +m1->m2 + + +'2' + + + +s0->e + + +00-'/',':'-7f + + + +s0->s1 + + +'0'-'9' + + + +s1->e + + +00-'/',':'-7f + + + +s1->s2 + + +'0'-'9' + + + +s2->e + + +00-'/',':'-7f + + + +s3 + + +s3 + + + +s2->s3 + + +'0'-'9' + + + +m2->e + + +00-'/',':'-7f + + + +m2->s2 + + +'0'-'2' + + + +m2->s3 + + +'4'-'9' + + + +m3 + + +m3 + + + +m2->m3 + + +'3' + + + +s3->e + + +00-'/',':'-7f + + + +s4 + + +s4 + + + +s3->s4 + + +'0'-'9' + + + +m3->e + + +00-'/',':'-7f + + + +m3->s3 + + +'0'-'8' + + + +m4 + + +m4 + + + +m3->m4 + + +'9' + + + +m4->e + + +00-'/',':'-7f + + + +s5 + + +s5 + + + +m4->s5 + + +'7'-'9' + + + +m5 + + +m5 + + + +m4->m5 + + +'6' + + + +m4->s4 + + +'0'-'5' + + + +s5->e + + +00-7f + + + +m5->e + + +00-'/','9'-7f + + + +m5->g + + +'0'-'8' + + + +s4->e + + +00-'/',':'-7f + + + +s4->s5 + + +'0'-'9' + + + diff --git a/tests/ref/build_number_upper_bound_42398.svg b/tests/ref/build_number_upper_bound_42398.svg new file mode 100644 index 0000000..fe0f822 --- /dev/null +++ b/tests/ref/build_number_upper_bound_42398.svg @@ -0,0 +1,292 @@ + + + + + + +root + + + +e + +e + + + +e->e + + +00-7f + + + +g + + +g + + + +g->e + + +00-7f + + + +m0 + + +m0 + + + +m0->e + + +00-'/',':'-7f + + + +s1 + + +s1 + + + +m0->s1 + + +'5'-'9' + + + +s0 + + +s0 + + + +m0->s0 + + +'0'-'3' + + + +m1 + + +m1 + + + +m0->m1 + + +'4' + + + +s1->e + + +00-'/',':'-7f + + + +s2 + + +s2 + + + +s1->s2 + + +'0'-'9' + + + +s0->e + + +00-'/',':'-7f + + + +s0->s1 + + +'0'-'9' + + + +m1->e + + +00-'/',':'-7f + + + +m1->s1 + + +'0'-'1' + + + +m1->s2 + + +'3'-'9' + + + +m2 + + +m2 + + + +m1->m2 + + +'2' + + + +s2->e + + +00-'/',':'-7f + + + +s3 + + +s3 + + + +s2->s3 + + +'0'-'9' + + + +m2->e + + +00-'/',':'-7f + + + +m2->s2 + + +'0'-'2' + + + +m3 + + +m3 + + + +m2->m3 + + +'3' + + + +m2->s3 + + +'4'-'9' + + + +m3->e + + +00-'/',':'-7f + + + +m3->s3 + + +'0'-'8' + + + +m4 + + +m4 + + + +m3->m4 + + +'9' + + + +s3->e + + +00-'/',':'-7f + + + +s4 + + +s4 + + + +s3->s4 + + +'0'-'9' + + + +m4->e + + +00-'/','9'-7f + + + +m4->g + + +'0'-'8' + + + +s4->e + + +00-7f + + + diff --git a/tests/ref/build_number_upper_bound_9999.svg b/tests/ref/build_number_upper_bound_9999.svg new file mode 100644 index 0000000..67ec17e --- /dev/null +++ b/tests/ref/build_number_upper_bound_9999.svg @@ -0,0 +1,222 @@ + + + + + + +root + + + +e + +e + + + +e->e + + +00-7f + + + +g + + +g + + + +g->e + + +00-7f + + + +m0 + + +m0 + + + +m0->e + + +00-'/',':'-7f + + + +m1 + + +m1 + + + +m0->m1 + + +'9' + + + +s0 + + +s0 + + + +m0->s0 + + +'0'-'8' + + + +m1->e + + +00-'/',':'-7f + + + +m2 + + +m2 + + + +m1->m2 + + +'9' + + + +s1 + + +s1 + + + +m1->s1 + + +'0'-'8' + + + +s0->e + + +00-'/',':'-7f + + + +s0->s1 + + +'0'-'9' + + + +m2->e + + +00-'/',':'-7f + + + +s2 + + +s2 + + + +m2->s2 + + +'0'-'8' + + + +m3 + + +m3 + + + +m2->m3 + + +'9' + + + +s1->e + + +00-'/',':'-7f + + + +s1->s2 + + +'0'-'9' + + + +s2->e + + +00-'/',':'-7f + + + +s3 + + +s3 + + + +s2->s3 + + +'0'-'9' + + + +m3->e + + +00-'/',':'-7f + + + +m3->g + + +'0'-'9' + + + +s3->e + + +00-7f + + + diff --git a/tests/ref/debug-simle_fsm_building.svg b/tests/ref/debug-simle_fsm_building.svg new file mode 100644 index 0000000..b808b09 --- /dev/null +++ b/tests/ref/debug-simle_fsm_building.svg @@ -0,0 +1,101 @@ + + + + + + +root + + + +z0 + +z0 + + + +z2 + + +z2 + + + +z0->z2 + + +'b' + + + +z3 + +z3 + + + +z0->z3 + + +00-'`','c'-7f + + + +z1 + +z1 + + + +z0->z1 + + +'a' + + + +z2->z2 + + +'a' + + + +z2->z3 + + +00-'`','b'-7f + + + +z3->z3 + + +00-7f + + + +z1->z2 + + +'b' + + + +z1->z3 + + +00-'`','c'-7f + + + +z1->z1 + + +'a' + + + diff --git a/tests/ref/state_elimitiation_after.svg b/tests/ref/state_elimitiation_after.svg new file mode 100644 index 0000000..7dcb52c --- /dev/null +++ b/tests/ref/state_elimitiation_after.svg @@ -0,0 +1,76 @@ + + + + + + +root + + + +z0 + + +z0 + + + +z1 + + +z1 + + + +z0->z1 + + +00-7f + + + +z2 + + +z2 + + + +z1->z2 + + +00-'`','{'-7f + + + +z3 + + +z3 + + + +z1->z3 + + +'a'-'z' + + + +z2->z2 + + +00-7f + + + +z3->z1 + + +00-7f + + + diff --git a/tests/ref/state_elimitiation_before.svg b/tests/ref/state_elimitiation_before.svg new file mode 100644 index 0000000..e6d4bfb --- /dev/null +++ b/tests/ref/state_elimitiation_before.svg @@ -0,0 +1,104 @@ + + + + + + +root + + + +z0 + + +z0 + + + +z1 + + +z1 + + + +z0->z1 + + +00-7f + + + +z2 + + +z2 + + + +z1->z2 + + +00-'`','{'-7f + + + +z3 + + +z3 + + + +z1->z3 + + +'a'-'z' + + + +z2->z2 + + +00-7f + + + +z3->z1 + + +00-7f + + + +z4 + + +z4 + + + +z4->z3 + + +00-7f + + + +z5 + + +z5 + + + +z5->z5 + + +00-7f + + +