Implement sample with working preprocessor (Stage 1 + 2)

This commit is contained in:
2025-08-11 12:49:44 +02:00
parent 0b6073b5bb
commit 9e4141fc96
9 changed files with 653 additions and 22 deletions

148
src/preprocessor.rs Normal file
View File

@@ -0,0 +1,148 @@
use crate::tokenizer::Token;
use regex::{Captures, 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)>,
special_tokens: Vec<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<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 parameter = &base_pattern
.captures(processed_code_replacement.as_str())
.unwrap()[0];
let command: &str = &base_pattern.replace(parameter, rule.1 .1.as_str());
println!("{:?}", &command);
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();
}
return processed_code;
}
}