pysprint_cli/
parser.rs

1use std::collections::HashMap;
2
3// // TODO
4// pub struct EvaluateOptions {
5//     numeric: HashMap<String, Box<f64>>,
6//     textual: HashMap<String, String>,
7//     boolean: HashMap<String, Box<bool>>
8// }
9
10// // TODO
11// pub struct IntermediateHooks {
12//     before_evaulate_triggers: Vec<String>,
13//     after_evaulate_triggers: Vec<String>
14// }
15
16#[derive(Debug)]
17pub struct FilePatternOptions {
18    pub exclude_patterns: Vec<String>,
19    pub skip_files: Vec<String>,
20    pub extensions: Vec<String>,
21}
22
23fn read_yaml(file: &str) -> Result<serde_yaml::Value, Box<dyn std::error::Error>> {
24    let f = std::fs::File::open(file)?;
25    Ok(serde_yaml::from_reader(f)?)
26}
27
28pub fn parse(
29    file: &str,
30) -> (
31    HashMap<String, Box<f64>>,
32    HashMap<String, String>,
33    HashMap<String, Box<bool>>,
34    Vec<String>,
35    Vec<String>,
36    FilePatternOptions,
37) {
38    let yaml_file = read_yaml(file).unwrap();
39
40    // options that can be represented as a number
41    let mut number_options: HashMap<String, Box<f64>> = HashMap::new();
42    // options that can be represented as text
43    let mut text_options: HashMap<String, String> = HashMap::new();
44    // options that can be represented as boolean
45    let mut bool_options: HashMap<String, Box<bool>> = HashMap::new();
46    // trigger before evaluate
47    let mut before_evaulate_triggers: Vec<String> = Vec::new();
48    // trigger after evaluate
49    let mut after_evaluate_triggers: Vec<String> = Vec::new();
50    // options that fit in a vector
51    let mut exclude_patterns: Vec<String> = Vec::new();
52    let mut skip_files: Vec<String> = Vec::new();
53    let mut extensions: Vec<String> = Vec::new();
54
55    // parsing the standard sections
56    for section in vec!["load_options", "preprocess", "evaluate"].iter() {
57        for feature in yaml_file[section].as_sequence().iter() {
58            for entities in feature.iter() {
59                let load_option: serde_yaml::Value = serde_yaml::to_value(entities).unwrap();
60                if let serde_yaml::Value::Mapping(options) = load_option {
61                    for option in options.iter() {
62                        match option {
63                            (serde_yaml::Value::String(key), serde_yaml::Value::Number(val)) => {
64                                number_options
65                                    .insert(key.to_string(), Box::new(val.as_f64().unwrap()));
66                            }
67                            (serde_yaml::Value::String(key), serde_yaml::Value::String(val)) => {
68                                text_options.insert(key.to_string(), val.to_string());
69                            }
70                            (serde_yaml::Value::String(key), serde_yaml::Value::Bool(val)) => {
71                                bool_options.insert(key.to_string(), Box::new(*val));
72                            }
73                            (serde_yaml::Value::String(key), serde_yaml::Value::Sequence(seq)) => {
74                                match key.as_str() {
75                                    "exclude_patterns" => {
76                                        seq.iter()
77                                            .filter_map(|d| match d {
78                                                serde_yaml::Value::String(string) => {
79                                                    Some(string.to_owned())
80                                                }
81                                                _ => None,
82                                            })
83                                            .collect::<Vec<String>>()
84                                            .as_slice()
85                                            .clone_into(&mut exclude_patterns);
86                                    }
87                                    "skip" => {
88                                        seq.iter()
89                                            .filter_map(|d| match d {
90                                                serde_yaml::Value::String(string) => {
91                                                    Some(string.to_owned())
92                                                }
93                                                _ => None,
94                                            })
95                                            .collect::<Vec<String>>()
96                                            .as_slice()
97                                            .clone_into(&mut skip_files);
98                                    }
99                                    "extensions" => {
100                                        seq.iter()
101                                            .filter_map(|d| match d {
102                                                serde_yaml::Value::String(string) => {
103                                                    Some(string.to_owned())
104                                                }
105                                                _ => None,
106                                            })
107                                            .collect::<Vec<String>>()
108                                            .as_slice()
109                                            .clone_into(&mut extensions);
110                                    }
111                                    _ => {}
112                                }
113                            }
114                            _ => panic!(
115                                "yaml contains values that are unknown in this context: {:?}",
116                                option
117                            ),
118                        }
119                    }
120                }
121            }
122        }
123    }
124    // parsing the "before_evaluate" section for subcommands to run
125    for commands in yaml_file["before_evaluate"].as_sequence().iter() {
126        for command in commands.iter() {
127            if let serde_yaml::Value::String(cmd) = command {
128                before_evaulate_triggers.push(cmd.to_string());
129            }
130        }
131    }
132
133    // parsing the "after_evaluate" section for subcommands to run
134    for commands in yaml_file["after_evaluate"].as_sequence().iter() {
135        for command in commands.iter() {
136            if let serde_yaml::Value::String(cmd) = command {
137                after_evaluate_triggers.push(cmd.to_string());
138            }
139        }
140    }
141
142    // getting the method section
143    for commands in yaml_file["method"].as_sequence().iter() {
144        for command in commands.iter() {
145            if let serde_yaml::Value::String(cmd) = command {
146                match cmd.to_string().as_str() {
147                    "fft" => {
148                        text_options.insert(String::from("methodname"), String::from("FFTMethod"))
149                    }
150                    "wft" => {
151                        text_options.insert(String::from("methodname"), String::from("WFTMethod"))
152                    }
153                    "mm" => text_options
154                        .insert(String::from("methodname"), String::from("MinMaxMethod")),
155                    _ => panic!("method named {:?} is not implemented", cmd),
156                };
157            }
158        }
159    }
160
161    for commands in yaml_file["method_details"].as_sequence().iter() {
162        for command in commands.iter() {
163            match command {
164                serde_yaml::Value::String(cmd) => {
165                    bool_options.insert(cmd.to_string(), Box::new(true));
166                }
167                serde_yaml::Value::Mapping(options) => {
168                    for option in options.iter() {
169                        match option {
170                            (serde_yaml::Value::String(key), serde_yaml::Value::Number(val)) => {
171                                number_options
172                                    .insert(key.to_string(), Box::new(val.as_f64().unwrap()));
173                            }
174                            (serde_yaml::Value::String(key), serde_yaml::Value::String(val)) => {
175                                text_options.insert(key.to_string(), val.to_string());
176                            }
177                            (serde_yaml::Value::String(key), serde_yaml::Value::Bool(val)) => {
178                                bool_options.insert(key.to_string(), Box::new(*val));
179                            }
180                            _ => panic!(
181                                "yaml contains values that are unknown in this context: {:?}",
182                                option
183                            ),
184                        }
185                    }
186                }
187                _ => {}
188            }
189        }
190    }
191
192    (
193        number_options,
194        text_options,
195        bool_options,
196        before_evaulate_triggers,
197        after_evaluate_triggers,
198        FilePatternOptions {
199            exclude_patterns,
200            skip_files,
201            extensions,
202        },
203    )
204}