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)]
|
#[derive(Clone)]
|
||||||
/// Holds the set of delimiters that should be removed from the MML to select a variant.
|
/// Holds the set of delimiters that should be removed from the MML to select a variant.
|
||||||
pub struct Variant<'v> {
|
pub struct Variant {
|
||||||
keep_delim: &'v str,
|
keep_delim: char,
|
||||||
remove_delims: HashSet<&'v str>,
|
remove_delims: HashSet<char>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> Variant<'v> {
|
impl Variant {
|
||||||
/// Get the set of character delimiters to remove from MML for this 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
|
&self.remove_delims
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The list of all variants defined in an MML file.
|
/// The list of all variants defined in an MML file.
|
||||||
pub struct VariantList<'v> {
|
pub struct VariantList<'v> {
|
||||||
all_delims: HashSet<&'v str>,
|
all_delims: HashSet<char>,
|
||||||
variants: BTreeMap<&'v str, Variant<'v>>,
|
variants: BTreeMap<&'v str, Variant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> VariantList<'v> {
|
impl<'v> VariantList<'v> {
|
||||||
|
@ -43,14 +43,16 @@ impl<'v> VariantList<'v> {
|
||||||
fn finish(mut self) -> Self {
|
fn finish(mut self) -> Self {
|
||||||
for (_, v) in self.variants.iter_mut() {
|
for (_, v) in self.variants.iter_mut() {
|
||||||
v.remove_delims = self.all_delims.clone();
|
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() {
|
if self.variants.is_empty() {
|
||||||
self.variants.insert(
|
self.variants.insert(
|
||||||
"_default_",
|
"_default_",
|
||||||
Variant {
|
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(),
|
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) {
|
if let Some((first, second)) = l.trim().rsplit_once(char::is_whitespace) {
|
||||||
use SfxMode::*;
|
use SfxMode::*;
|
||||||
match sfx_mode {
|
match sfx_mode {
|
||||||
Off => state.all_delims.insert(first),
|
Off => state.all_delims.insert(first_char(first)),
|
||||||
On => state.all_delims.insert(second),
|
On => state.all_delims.insert(first_char(second)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if let Some(l) = line.strip_prefix("#VARIANT") {
|
} else if let Some(l) = line.strip_prefix("#VARIANT") {
|
||||||
let (first, second) = {
|
let (first, second) = {
|
||||||
let rest = l.trim();
|
let rest = l.trim();
|
||||||
if let Some((f, s)) = rest.rsplit_once(' ') {
|
if let Some((f, s)) = rest.rsplit_once(' ') {
|
||||||
(f, s)
|
(first_char(f), s)
|
||||||
} else {
|
} 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()
|
.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