refactoring

This commit is contained in:
Simon Gardling
2022-04-22 11:34:11 -04:00
parent e603cbb975
commit d11480ed95
17 changed files with 156 additions and 151 deletions

172
parsing/src/suggestions.rs Normal file
View File

@@ -0,0 +1,172 @@
use crate::parsing::is_number;
pub const HINT_EMPTY: Hint = Hint::Single("x^2");
const HINT_CLOSED_PARENS: Hint = Hint::Single(")");
/// Only enacts println if cfg(test) is enabled
macro_rules! test_print {
($($arg:tt)*) => {
#[cfg(test)]
println!($($arg)*)
};
}
/// Generate a hint based on the input `input`, returns an `Option<String>`
pub fn generate_hint<'a>(input: &str) -> &'a Hint<'a> {
if input.is_empty() {
return &HINT_EMPTY;
}
let chars: Vec<char> = input.chars().collect::<Vec<char>>();
let mut open_parens: usize = 0;
let mut closed_parens: usize = 0;
chars.iter().for_each(|chr| match *chr {
'(' => open_parens += 1,
')' => closed_parens += 1,
_ => {}
});
if open_parens > closed_parens {
return &HINT_CLOSED_PARENS;
}
// let len = chars.len();
let mut split: Vec<String> = Vec::new();
let mut buffer: Vec<char> = Vec::new();
for c in chars {
buffer.push(c);
if c == ')' {
split.push(buffer.iter().collect::<String>());
buffer.clear();
continue;
}
let buffer_string = buffer.iter().collect::<String>();
if ((&buffer_string == "log") | (&buffer_string == "log1")) && is_number(&c) {
continue;
}
}
if !buffer.is_empty() {
split.push(buffer.iter().collect::<String>());
}
test_print!("split: {:?}", split);
if split.is_empty() {
return COMPLETION_HASHMAP.get(input).unwrap_or(&Hint::None);
}
COMPLETION_HASHMAP.get(& unsafe {split.last().unwrap_unchecked()}.as_str()).unwrap_or(&Hint::None)
}
#[derive(PartialEq)]
pub enum Hint<'a> {
Single(&'a str),
Many(&'a [&'a str]),
None,
}
impl<'a> std::fmt::Debug for Hint<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self) }
}
impl<'a> std::fmt::Display for Hint<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Hint::Single(single_data) => {
return write!(f, "{}", single_data);
}
Hint::Many(multi_data) => {
return write!(f, "{:?}", multi_data);
}
Hint::None => {
return write!(f, "None");
}
}
}
}
impl<'a> Hint<'a> {
pub fn is_none(&self) -> bool { matches!(self, Hint::None) }
#[allow(dead_code)]
pub fn is_some(&self) -> bool { !self.is_none() }
#[allow(dead_code)]
pub fn is_single(&self) -> bool { matches!(self, Hint::Single(_)) }
}
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use super::*;
/// Tests to make sure hints are properly outputed based on input
#[test]
fn hint_test() {
let values = HashMap::from([
("", Hint::Single("x^2")),
("si", Hint::Many(&["n(", "nh(", "gnum("])),
("log", Hint::Many(&["2(", "10("])),
("cos", Hint::Many(&["(", "h("])),
("sin(", Hint::Single(")")),
("sqrt", Hint::Single("(")),
("ln(x)", Hint::None),
("ln(x)cos", Hint::Many(&["(", "h("])),
]);
for (key, value) in values {
println!("{} + {:?}", key, value);
assert_eq!(generate_hint(key), &value);
}
}
#[test]
fn hint_to_string_test() {
let values = HashMap::from([
("x^2", Hint::Single("x^2")),
(
r#"["n(", "nh(", "gnum("]"#,
Hint::Many(&["n(", "nh(", "gnum("]),
),
(r#"["n("]"#, Hint::Many(&["n("])),
("None", Hint::None),
]);
for (key, value) in values {
assert_eq!(value.to_string(), key);
}
}
#[test]
fn invalid_function_test() {
SUPPORTED_FUNCTIONS
.iter()
.map(|func1| {
SUPPORTED_FUNCTIONS
.iter()
.map(|func2| func1.to_string() + func2)
.collect::<Vec<String>>()
})
.flatten()
.filter(|func| !SUPPORTED_FUNCTIONS.contains(&func.as_str()))
.for_each(|key| {
println!("{}", key);
if generate_hint(&key).is_none() {
println!("success: {}", key);
} else {
panic!("failed: {}", key);
}
});
}
}