Refactor Variant to work with char
. Add function to select variant.
This commit is contained in:
parent
0c3d77b90b
commit
ef9b4f3769
67
src/mfvi.rs
67
src/mfvi.rs
|
@ -14,22 +14,22 @@ struct Translation<'a> {
|
|||
|
||||
#[derive(Clone)]
|
||||
/// Holds the set of delimiters that should be removed from the MML to select a variant.
|
||||
pub struct Variant<'v> {
|
||||
keep_delim: &'v str,
|
||||
remove_delims: HashSet<&'v str>,
|
||||
pub struct Variant {
|
||||
keep_delim: char,
|
||||
remove_delims: HashSet<char>,
|
||||
}
|
||||
|
||||
impl<'v> Variant<'v> {
|
||||
impl Variant {
|
||||
/// Get the set of character delimiters to remove from MML for this variant.
|
||||
pub fn ignores(&self) -> &HashSet<&str> {
|
||||
pub fn ignores(&self) -> &HashSet<char> {
|
||||
&self.remove_delims
|
||||
}
|
||||
}
|
||||
|
||||
/// The list of all variants defined in an MML file.
|
||||
pub struct VariantList<'v> {
|
||||
all_delims: HashSet<&'v str>,
|
||||
variants: BTreeMap<&'v str, Variant<'v>>,
|
||||
all_delims: HashSet<char>,
|
||||
variants: BTreeMap<&'v str, Variant>,
|
||||
}
|
||||
|
||||
impl<'v> VariantList<'v> {
|
||||
|
@ -43,14 +43,16 @@ impl<'v> VariantList<'v> {
|
|||
fn finish(mut self) -> Self {
|
||||
for (_, v) in self.variants.iter_mut() {
|
||||
v.remove_delims = self.all_delims.clone();
|
||||
v.remove_delims.remove(v.keep_delim);
|
||||
v.remove_delims.remove(&v.keep_delim);
|
||||
}
|
||||
|
||||
if self.variants.is_empty() {
|
||||
self.variants.insert(
|
||||
"_default_",
|
||||
Variant {
|
||||
keep_delim: "",
|
||||
// Not that we expect to find NUL bytes, but effectively we will remove all
|
||||
// delimiters with this variant.
|
||||
keep_delim: '\0',
|
||||
remove_delims: self.all_delims.clone(),
|
||||
},
|
||||
);
|
||||
|
@ -115,17 +117,17 @@ pub fn get_variants<'a>(input: &'a str, sfx_mode: SfxMode) -> VariantList<'a> {
|
|||
if let Some((first, second)) = l.trim().rsplit_once(char::is_whitespace) {
|
||||
use SfxMode::*;
|
||||
match sfx_mode {
|
||||
Off => state.all_delims.insert(first),
|
||||
On => state.all_delims.insert(second),
|
||||
Off => state.all_delims.insert(first_char(first)),
|
||||
On => state.all_delims.insert(first_char(second)),
|
||||
};
|
||||
}
|
||||
} else if let Some(l) = line.strip_prefix("#VARIANT") {
|
||||
let (first, second) = {
|
||||
let rest = l.trim();
|
||||
if let Some((f, s)) = rest.rsplit_once(' ') {
|
||||
(f, s)
|
||||
(first_char(f), s)
|
||||
} else {
|
||||
(rest, "_default_")
|
||||
(first_char(rest), "_default_")
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -153,3 +155,42 @@ pub fn get_variants<'a>(input: &'a str, sfx_mode: SfxMode) -> VariantList<'a> {
|
|||
})
|
||||
.finish()
|
||||
}
|
||||
|
||||
fn first_char(s: &str) -> char {
|
||||
s.chars().next().unwrap_or('\0')
|
||||
}
|
||||
|
||||
pub fn select_variant<'i>(input: &'i str, var: &'i Variant) -> String {
|
||||
let mut output = input.to_string();
|
||||
// Workspace for converting char to &str in the loop.
|
||||
let mut buf = [0; 4];
|
||||
// Set of chars to find in `input`.
|
||||
let charlist: Vec<char> = var
|
||||
.remove_delims
|
||||
.iter()
|
||||
.copied()
|
||||
.chain([var.keep_delim])
|
||||
.collect();
|
||||
let mut needles = input.rmatch_indices(&charlist[..]).peekable();
|
||||
|
||||
while let Some((idx, c)) = needles.next() {
|
||||
match c {
|
||||
// Remove the char if it is the `keep_delim`.
|
||||
d if var.keep_delim.encode_utf8(&mut buf) == d => {
|
||||
// `replace_range` doesn't make a full copy of the string the way `remove` does.
|
||||
output.replace_range(idx..=idx, "");
|
||||
}
|
||||
// Anything else will be in `remove_delim`, so find a matching pair and remove
|
||||
// them and everything between them.
|
||||
d => match needles.peek() {
|
||||
Some(&(idx_1, d2)) if d == d2 => {
|
||||
needles.next();
|
||||
output.replace_range(idx_1..=idx, "");
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue