machine.rs 5.35 KB
Newer Older
1
use crate::automatadefs::mealy::{InputSymbol, Mealy, MealyBuilder, OutputSymbol, State};
2
use fnv::{FnvHashMap, FnvHashSet};
3
4
5
6
7
8
use std::{
    convert::TryInto,
    fs::{canonicalize, File},
    io::{self, BufRead},
    path::Path,
};
9

Bharat Garhewal's avatar
Bharat Garhewal committed
10
11
12
#[must_use]
/// # Panics
/// If file is not found.
13
14
15
16
17
18
19
pub fn read_mealy_from_file(
    file_path: &str,
) -> (
    Mealy,
    FnvHashMap<String, InputSymbol>,
    FnvHashMap<String, OutputSymbol>,
) {
Bharat's avatar
Bharat committed
20
    let mut states = FnvHashSet::<State>::default();
21
22
23
24
25
    let mut output_alphabet = FnvHashSet::<OutputSymbol>::default();
    let mut input_map = FnvHashMap::<String, InputSymbol>::default();
    let mut output_map = FnvHashMap::<String, OutputSymbol>::default();
    let mut trans_function = FnvHashMap::<(State, InputSymbol), State>::default();
    let mut output_function = FnvHashMap::<(State, InputSymbol), OutputSymbol>::default();
26
    let mut initial_state = State::new(u32::MAX);
27
    let mut state_map = FnvHashMap::<String, State>::default();
28
29
30
    let mut curr_state_max: i32 = -1;
    let mut curr_input_max: i32 = -1;
    let mut curr_output_max: i32 = -1;
31
32
    let file_path =
        canonicalize(file_path).unwrap_or_else(|_| panic!("File {:?} not found.", file_path));
33
    if let Ok(lines) = read_lines(file_path) {
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
        for line in lines.flatten() {
            if line.contains("__start0") && line.contains("->") {
                let mut init_line = line.split_whitespace().rev();
                let state_decl_initial = init_line.next().unwrap();
                let state_initial_str = &state_decl_initial[..state_decl_initial.len() - 1];
                if !state_map.contains_key(state_initial_str) {
                    curr_state_max += 1;
                    state_map.insert(
                        state_initial_str.to_string(),
                        State::new(curr_state_max.try_into().unwrap()),
                    );
                    states.insert(State::new(curr_state_max.try_into().unwrap()));
                }
                initial_state = *state_map.get(&state_initial_str.to_string()).unwrap();
                continue;
            }
            if !line.contains("label") {
                continue;
            }
53
54
55
56
57
58
59
60
            let mut state_map_fetch = |state_str| -> State {
                *state_map.entry(state_str).or_insert_with(|| {
                    curr_state_max += 1;
                    let ns = State::new(curr_state_max.try_into().unwrap());
                    states.insert(ns);
                    ns
                })
            };
61
62
            if line.contains("->") {
                let (from_str, input_action, output_action, to_str) = extract_transition(&line);
63
                let from_state = state_map_fetch(from_str.to_string());
64
65
66
67
                if initial_state.raw() == u32::MAX {
                    initial_state = from_state;
                    log::info!("Selected state {} as initial!", from_str);
                    assert_eq!(initial_state.raw(), 0);
68
                }
69
70
71
72
                let to_state = state_map_fetch(to_str.to_string());
                let input = *input_map
                    .entry(input_action.to_string())
                    .or_insert_with(|| {
73
                        curr_input_max += 1;
74
75
76
77
78
                        InputSymbol::new(curr_input_max.try_into().unwrap())
                    });
                let output = *output_map
                    .entry(output_action.to_string())
                    .or_insert_with(|| {
79
                        curr_output_max += 1;
80
81
82
83
                        let out = OutputSymbol::new(curr_output_max.try_into().unwrap());
                        output_alphabet.insert(out);
                        out
                    });
84
85
                trans_function.insert((from_state, input), to_state);
                output_function.insert((from_state, input), output);
86
87
88
            }
        }
    }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    let input_alphabet = (0..input_map.len())
        .into_iter()
        .map(InputSymbol::from)
        .collect();
    let ret = (
        MealyBuilder::default()
            .states(states)
            .initial_state(initial_state)
            .trans_function(trans_function)
            .output_function(output_function)
            .output_alphabet(output_alphabet)
            .input_alphabet(input_alphabet)
            .build()
            .unwrap(),
        input_map,
        output_map,
    );
    ret
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
}

fn extract_transition(line: &str) -> (&str, &str, &str, &str) {
    let arr_idx = line.find("->").unwrap();
    let from_state = line[..arr_idx].trim();

    let begin_label_idx = line.find('[').unwrap();
    let to_state = line[arr_idx + 2..begin_label_idx].trim();

    let mut quote_idx = line.rmatch_indices('"');
    let close_quote_idx = quote_idx.next().unwrap().0;
    let open_quote_idx = quote_idx.next().unwrap().0;
    // let open_quote_idx = line.find(r#"""#).unwrap();
    // let close_quote_idx = line.rfind(r#"""#).unwrap();
    let sep_idx = line.find('/').unwrap();
    let input_str = line[open_quote_idx + 1..sep_idx].trim();
    let output_str = line[sep_idx + 1..close_quote_idx].trim();
    (from_state, input_str, output_str, to_state)
}

// The output is wrapped in a Result to allow matching on errors
// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
    P: AsRef<Path>,
{
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}