190 lines
7.6 KiB
Rust
190 lines
7.6 KiB
Rust
use crate::tokenizer::Token;
|
|
use regex::{Captures, Match, Regex};
|
|
use toml::{Table, Value};
|
|
|
|
// MetaRules
|
|
// Struct containing all meta rules.
|
|
pub struct MetaRules {
|
|
replacement_rules: Vec<(String, (String, String))>,
|
|
interpolation_rules: Vec<(String, (String, String))>,
|
|
token_rules: Vec<(String, String)>,
|
|
pub special_tokens: Vec<(String, Token)>,
|
|
}
|
|
|
|
// Implementation of MetaRules
|
|
// Trait implementation
|
|
impl MetaRules {
|
|
// @name new
|
|
// @return MetaRules
|
|
// @brief Create a new rule struct by reading from a configuration file.
|
|
// @param configuration_filename: &str
|
|
pub fn new(configuration_filename: &str) -> MetaRules {
|
|
let configuration_content: String = std::fs::read_to_string(configuration_filename)
|
|
.expect("[ERROR] Could not open configuration file!");
|
|
let mut replacements: Vec<(String, (String, String))> = vec![];
|
|
let mut interpolation: Vec<(String, (String, String))> = vec![];
|
|
let mut meta_token_rules: Vec<(String, String)> = vec![];
|
|
let meta_tokens: Vec<(String, Token)> = vec![];
|
|
let configuration = gtoml::parse(configuration_content.as_str())
|
|
.expect("[ERROR] TOML invalid in preprocessor!");
|
|
let configuration_unpacked: Table = Table::try_from(configuration).unwrap();
|
|
let meta_configuration: Table = match configuration_unpacked.get("meta") {
|
|
Some(config) => config.as_table().unwrap().clone(),
|
|
None => Table::new(),
|
|
};
|
|
|
|
if !meta_configuration.is_empty() {
|
|
if meta_configuration.contains_key("replacements") {
|
|
println!("[INFO] Found replacement rules.");
|
|
let replacement_rules: Table = meta_configuration
|
|
.get("replacements")
|
|
.unwrap()
|
|
.as_table()
|
|
.unwrap()
|
|
.clone();
|
|
for key in replacement_rules.keys() {
|
|
let value: Vec<Value> = replacement_rules
|
|
.get(key)
|
|
.unwrap()
|
|
.as_array()
|
|
.unwrap()
|
|
.clone();
|
|
let name: String = key.clone();
|
|
let pattern: String = value[0].as_str().unwrap().to_owned();
|
|
let replacement: String = value[1].as_str().unwrap().to_owned();
|
|
replacements.push((name, (pattern, replacement)));
|
|
}
|
|
}
|
|
|
|
if meta_configuration.contains_key("interpolation") {
|
|
println!("[INFO] Found interpolation rules.");
|
|
let interpolation_rules: Table = meta_configuration
|
|
.get("interpolation")
|
|
.unwrap()
|
|
.as_table()
|
|
.unwrap()
|
|
.clone();
|
|
for key in interpolation_rules.keys() {
|
|
let value: Vec<Value> = interpolation_rules
|
|
.get(key)
|
|
.unwrap()
|
|
.as_array()
|
|
.unwrap()
|
|
.clone();
|
|
let name: String = key.clone();
|
|
let pattern: String = value[0].as_str().unwrap().to_owned();
|
|
let cmd: &str = value[1].as_str().unwrap();
|
|
interpolation.push((name, (pattern, String::from(cmd))));
|
|
}
|
|
}
|
|
|
|
if meta_configuration.contains_key("token") {
|
|
println!("[INFO] Found token rules.");
|
|
let token_rules: Table = meta_configuration
|
|
.get("token")
|
|
.unwrap()
|
|
.as_table()
|
|
.unwrap()
|
|
.clone();
|
|
for rule in token_rules.keys() {
|
|
let pattern: String =
|
|
token_rules.get(rule).unwrap().as_str().unwrap().to_owned();
|
|
meta_token_rules.push((rule.clone(), pattern));
|
|
}
|
|
}
|
|
} else {
|
|
println!("[WARNING] No meta configuration, skipping preprocessor.");
|
|
}
|
|
|
|
MetaRules {
|
|
replacement_rules: replacements,
|
|
interpolation_rules: interpolation,
|
|
token_rules: meta_token_rules,
|
|
special_tokens: meta_tokens,
|
|
}
|
|
}
|
|
|
|
// @name process
|
|
// @return String
|
|
// @brief Run preprocessor on raw code.
|
|
// @param rule_set: MetaRules, raw_code: String
|
|
pub fn process(&mut self, raw_code: String) -> String {
|
|
let mut processed_code: String = raw_code.clone();
|
|
|
|
// replacement rules
|
|
for rule in self.replacement_rules.iter() {
|
|
println!("[INFO] Applying rule {}", rule.0);
|
|
let base_pattern: Regex = Regex::new((rule.1 .0).as_str()).unwrap();
|
|
processed_code = base_pattern
|
|
.replace_all(processed_code.as_str(), rule.1 .1.as_str())
|
|
.to_string();
|
|
}
|
|
|
|
// interpolation rules
|
|
for rule in self.interpolation_rules.iter() {
|
|
println!("[INFO] Applying rule {}", rule.0);
|
|
let base_pattern: Regex = Regex::new((rule.1 .0).as_str()).unwrap();
|
|
let processed_code_replacement = processed_code.clone();
|
|
|
|
let captures: Option<Captures> =
|
|
base_pattern.captures(processed_code_replacement.as_str());
|
|
let directive: String;
|
|
match captures {
|
|
Some(n) => directive = n.get(0).map_or("", |m| m.as_str()).to_string(),
|
|
None => continue,
|
|
};
|
|
let command: &str = &base_pattern.replace(directive.as_str(), rule.1 .1.as_str());
|
|
let subprocess = std::process::Command::new("/bin/bash")
|
|
.arg("-c")
|
|
.arg(String::from("echo \"$(") + command + ")\"")
|
|
.output()
|
|
.expect((String::from("") + "Failed to run command " + command + "!").as_str());
|
|
processed_code = base_pattern
|
|
.replace(
|
|
processed_code.as_str(),
|
|
String::from_utf8(subprocess.stdout).unwrap(),
|
|
)
|
|
.to_string();
|
|
}
|
|
|
|
for token_style in self.token_rules.iter() {
|
|
println!("[INFO] Searching meta tokens of style {}", token_style.0);
|
|
|
|
// Search all occurrences
|
|
let token_pattern: Regex =
|
|
Regex::new(token_style.1.as_str()).expect("Could not assign pattern.");
|
|
let match_list: Match;
|
|
match_list = match token_pattern.find(processed_code.as_str()) {
|
|
Some(n) => n,
|
|
None => continue,
|
|
};
|
|
|
|
// Create id for each occurrence
|
|
let meta_id: String = String::from("meta_token_")
|
|
+ match_list.start().to_string().as_str()
|
|
+ "__"
|
|
+ match_list.end().to_string().as_str();
|
|
|
|
// Replace token by id
|
|
let meta_value: String = match_list.as_str().to_string();
|
|
let value_regex: Regex =
|
|
Regex::new(meta_value.as_str()).expect("Could not create pattern.");
|
|
processed_code = value_regex
|
|
.replace(processed_code.as_str(), meta_id.as_str())
|
|
.to_string();
|
|
println!("Replace {} with {}.", meta_value, meta_id);
|
|
|
|
// Safe id and token
|
|
self.special_tokens.push((
|
|
meta_id,
|
|
Token {
|
|
token: meta_value,
|
|
token_type: crate::TokenType::IDENTIFIER,
|
|
},
|
|
));
|
|
}
|
|
|
|
return processed_code;
|
|
}
|
|
}
|