use regex::Regex;
use std::env;
use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;
use walkdir::WalkDir;
const RENAMED_RULES: &[(&str, &str, &str)] = &[
(
"generate_keyword",
"generate_keyword_forbidden",
"GenerateKeywordForbidden",
),
("tab_charactor", "tab_character", "TabCharacter"),
(
"genvar_declaration",
"genvar_declaration_in_loop",
"GenvarDeclarationInLoop",
),
];
fn main() {
let root_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let out_dir = env::var("OUT_DIR").unwrap();
let re_struct = Regex::new(r"pub struct ([a-zA-Z0-9]*)").unwrap();
let mut rules = Vec::new();
for entry in WalkDir::new("src/rules") {
let entry = entry.unwrap();
if entry.file_type().is_file() {
let f = File::open(entry.path()).unwrap();
let mut f = BufReader::new(f);
let mut s = String::new();
let _ = f.read_to_string(&mut s);
let cap = re_struct.captures(&s);
if let Some(cap) = cap {
let struct_name = String::from(&cap[1]);
let file_name = String::from(entry.path().file_stem().unwrap().to_string_lossy());
rules.push((file_name, struct_name));
}
}
}
rules.sort_by(|a, b| a.0.cmp(&b.0));
let out_rules = Path::new(&out_dir).join("rules.rs");
let mut out_rules = File::create(&out_rules).unwrap();
for (file_name, _) in &rules {
let _ = write!(
out_rules,
"#[path = \"{}/src/rules/{}.rs\"]\n",
root_dir.replace("\\", "\\\\"),
file_name
);
let _ = write!(out_rules, "pub mod {};\n", file_name);
}
for (file_name, _) in &rules {
let _ = write!(out_rules, "pub use {}::*;\n", file_name);
}
let out_config_rules = Path::new(&out_dir).join("config_rules.rs");
let mut out_config_rules = File::create(&out_config_rules).unwrap();
let mut body = String::new();
for (file_name, _) in &rules {
body.push_str(&format!(" #[serde(default = \"default_as_false\")]\n"));
body.push_str(&format!(" pub {}: bool,\n", file_name));
}
for (org_name, _, _) in RENAMED_RULES {
body.push_str(&format!(" #[serde(default = \"default_as_false\")]\n"));
body.push_str(&format!(" pub {}: bool,\n", org_name));
}
let str_config_rules = format!(
r##"
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigRules {{
{}
}}"##,
body
);
let _ = write!(out_config_rules, "{}", str_config_rules);
let out_impl_config = Path::new(&out_dir).join("impl_config.rs");
let mut out_impl_config = File::create(&out_impl_config).unwrap();
let mut enable_all_body = String::new();
let mut gen_rules_body = String::new();
let mut gen_all_rules_body = String::new();
let mut check_rename_body = String::new();
for (file_name, struct_name) in &rules {
enable_all_body.push_str(&format!(" self.rules.{} = true;\n", file_name));
gen_rules_body.push_str(&format!(" if self.rules.{} {{\n", file_name));
gen_rules_body.push_str(&format!(
" ret.push(Box::new({}::default()));\n",
struct_name
));
gen_rules_body.push_str(&format!(" }}\n"));
gen_all_rules_body.push_str(&format!(
" ret.push(Box::new({}::default()));\n",
struct_name
));
}
for (org_name, file_name, struct_name) in RENAMED_RULES {
gen_rules_body.push_str(&format!(" if self.rules.{} {{\n", org_name));
gen_rules_body.push_str(&format!(
" ret.push(Box::new({}::default()));\n",
struct_name
));
gen_rules_body.push_str(&format!(" }}\n"));
check_rename_body.push_str(&format!(" if self.rules.{} {{\n", org_name));
check_rename_body.push_str(&format!(
" ret.push((String::from(\"{}\"), String::from(\"{}\")));\n",
org_name, file_name
));
check_rename_body.push_str(&format!(" }}\n"));
}
let str_impl_config = format!(
r##"
impl Config {{
pub fn new() -> Self {{
toml::from_str("").unwrap()
}}
pub fn enable_all(mut self) -> Self {{
{}
self
}}
pub fn gen_rules(&self) -> Vec<Box<dyn Rule>> {{
let mut ret: Vec<Box<dyn Rule>> = Vec::new();
{}
ret
}}
pub fn gen_all_rules() -> Vec<Box<dyn Rule>> {{
let mut ret: Vec<Box<dyn Rule>> = Vec::new();
{}
ret
}}
pub fn check_rename(&self) -> Vec<(String, String)> {{
let mut ret: Vec<(String, String)> = Vec::new();
{}
ret
}}
}}"##,
enable_all_body, gen_rules_body, gen_all_rules_body, check_rename_body
);
let _ = write!(out_impl_config, "{}", str_impl_config);
let out_test = Path::new(&out_dir).join("test.rs");
let mut out_test = File::create(&out_test).unwrap();
let test_verbose = ["genvar_declaration_out_loop"];
for (file_name, _) in &rules {
let silent = if test_verbose.contains(&file_name.as_str()) {
"false"
} else {
"true"
};
let _ = write!(out_test, "#[test]\n");
let _ = write!(out_test, "fn test_{}() {{\n", file_name);
let _ = write!(out_test, " test(\"{}\", {});\n", file_name, silent);
let _ = write!(out_test, "}}\n");
}
}