167 lines
4.5 KiB
Rust
167 lines
4.5 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use lazy_static::lazy_static;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
mod regex_wrapper;
|
|
use regex_wrapper::Regex;
|
|
|
|
lazy_static! {
|
|
static ref RE: Regex = Regex::new("%([A-Z])");
|
|
}
|
|
|
|
/// Representation of a rule in LangEvolveRs
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct Rule {
|
|
/// Regex that should match the input text
|
|
from: Regex,
|
|
/// Text to replace matched text
|
|
to: String,
|
|
}
|
|
|
|
impl Rule {
|
|
/// Create new rule
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `from` - literal string that represents the regex that should match
|
|
/// the input text
|
|
/// * `to` - literal string that represents the regex text that should
|
|
/// replaced the text matched by `from`
|
|
///
|
|
/// # Example
|
|
/// ```
|
|
/// # use lazy_static::lazy_static;
|
|
/// # #[path = "mod.rs"]
|
|
/// # mod rule;
|
|
/// # use rule::Rule;
|
|
/// let rule = Rule::new("ab+c*", "ab");
|
|
/// ```
|
|
pub fn new(from: &str, to: &str) -> Self {
|
|
Rule {
|
|
from: Regex::new(from),
|
|
to: String::from(to),
|
|
}
|
|
}
|
|
|
|
/// Detect the number of categories in a rule
|
|
///
|
|
/// For a rule, this function detects the number of categories set in the
|
|
/// `from` member of a `Rule` and in its `to` member. The result is returned
|
|
/// as a tuple of `u8`s.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # #[path = "mod.rs"]
|
|
/// # mod rule;
|
|
/// # use rule::Rule;
|
|
/// let rule = Rule::new("%Bea*i+", "a%A%C");
|
|
/// let nb_rules = rule.detect_number_categories();
|
|
/// assert_eq!((1 as u8, 2 as u8), nb_rules);
|
|
/// ```
|
|
pub fn detect_number_categories(&self) -> (u8, u8) {
|
|
let captures_from = self.from.to_string().matches('%').count() as u8;
|
|
let captures_to = self.to.matches('%').count() as u8;
|
|
(captures_from, captures_to)
|
|
}
|
|
|
|
fn simple_rewrite(&self, categories: &HashMap<String, String>) -> Self {
|
|
let mut rule = self.clone();
|
|
for (category, content) in categories {
|
|
rule.from = Regex::new(
|
|
rule.from
|
|
.to_string()
|
|
.replace(
|
|
format!("%{}", category).as_str(),
|
|
format!("[{}]", content).as_str(),
|
|
)
|
|
.as_str(),
|
|
);
|
|
}
|
|
rule
|
|
}
|
|
|
|
// TODO break categories in different rules
|
|
pub fn update(
|
|
&self,
|
|
categories: &HashMap<String, String>,
|
|
) -> std::result::Result<Rule, String> {
|
|
let mut rule = self.clone();
|
|
let (from_match, to_match) = self.detect_number_categories();
|
|
// If there are only simple rewrites to make in the from String
|
|
if from_match > 0 && to_match == 0 {
|
|
rule = self.simple_rewrite(&categories);
|
|
}
|
|
|
|
// If there are equivalences between from and to
|
|
if from_match > 0 && to_match <= from_match && to_match > 0 {}
|
|
|
|
Ok(rule)
|
|
}
|
|
|
|
pub fn get_from(&self) -> &Regex {
|
|
&self.from
|
|
}
|
|
|
|
pub fn get_to(&self) -> String {
|
|
self.to.clone()
|
|
}
|
|
}
|
|
|
|
impl From<String> for Rule {
|
|
/// Allow to create a rule from a single `String`
|
|
///
|
|
/// It is possible to create a rule from a string, delimited by a `>`. This
|
|
/// means a rule like `%C>%D` will be interpreted as going from `%C` to
|
|
/// `%D`.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # #[path = "mod.rs"]
|
|
/// # mod rule;
|
|
/// # use rule::Rule;
|
|
/// let rule1 = Rule::new("%C", "%D");
|
|
/// let rule2 = Rule::from(String::from("%C>%D"));
|
|
/// assert_eq!(rule1, rule2);
|
|
/// ```
|
|
fn from(source: String) -> Self {
|
|
let components: Vec<&str> = source.split_terminator('>').collect();
|
|
Rule::new(components[0], components[1])
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Rule {
|
|
/// Equality between `Rule` structs
|
|
///
|
|
/// This allows for equality comparison between two `Rule` structs.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// ```
|
|
/// # #[path = "mod.rs"]
|
|
/// # mod rule;
|
|
/// use rule::Rule;
|
|
/// let rule1 = Rule::new("%C", "%D");
|
|
/// let rule2 = Rule::from("%C>%D");
|
|
/// assert!(rule1 == rule2);
|
|
/// assert!(rule2 == rule1);
|
|
/// ```
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.from == other.from && self.to == other.to
|
|
}
|
|
}
|
|
|
|
impl Eq for Rule {}
|
|
|
|
#[test]
|
|
fn rule_new() {
|
|
let rule1 = Rule::new("([ae]+)i", "${1}i");
|
|
let rule2 = Rule {
|
|
from: Regex::new("([ae]+)i"),
|
|
to: String::from("${1}i"),
|
|
};
|
|
assert_eq!(rule1, rule2);
|
|
}
|