From ac05c844b409c488e0991abcae66a10d12f9c252 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 14 Nov 2024 23:15:51 +0100 Subject: [PATCH] add support for include/exclude regexes in transforms. --- src/transform/common.rs | 113 ++++++++++++++++++++++++-- src/transform/delete.rs | 10 +-- src/transform/delete_enums.rs | 6 +- src/transform/delete_enums_used_in.rs | 5 +- src/transform/delete_fieldsets.rs | 6 +- src/transform/delete_registers.rs | 10 +-- src/transform/make_block.rs | 16 ++-- src/transform/make_field_array.rs | 14 ++-- src/transform/make_register_array.rs | 10 +-- src/transform/merge_blocks.rs | 12 ++- src/transform/merge_enums.rs | 12 ++- src/transform/merge_fieldsets.rs | 12 ++- src/transform/modify_byte_offset.rs | 19 ++--- src/transform/rename.rs | 6 +- src/transform/rename_enum_variants.rs | 10 +-- src/transform/rename_fields.rs | 10 +-- src/transform/rename_interrupts.rs | 6 +- src/transform/rename_registers.rs | 10 +-- 18 files changed, 177 insertions(+), 110 deletions(-) diff --git a/src/transform/common.rs b/src/transform/common.rs index 4371407..43c9a40 100644 --- a/src/transform/common.rs +++ b/src/transform/common.rs @@ -4,8 +4,105 @@ use std::collections::{BTreeMap, BTreeSet}; use crate::ir::*; -pub(crate) fn make_regex(r: &str) -> Result { - regex::Regex::new(&format!("^{}$", r)) +#[derive(Debug, Clone)] +pub struct RegexSet { + include: Vec, + exclude: Vec, +} + +impl RegexSet { + pub fn captures<'h>(&self, haystack: &'h str) -> Option> { + for r in &self.exclude { + if r.is_match(haystack) { + return None; + } + } + for r in &self.include { + if let Some(c) = r.captures(haystack) { + return Some(c); + } + } + None + } + + pub fn is_match(&self, haystack: &str) -> bool { + for r in &self.exclude { + if r.is_match(haystack) { + return false; + } + } + for r in &self.include { + if r.is_match(haystack) { + return true; + } + } + false + } +} + +impl<'de> Deserialize<'de> for RegexSet { + fn deserialize(de: D) -> Result + where + D: serde::Deserializer<'de>, + { + fn make_regex(r: &str) -> Result { + regex::Regex::new(&format!("^{}$", r)) + } + + #[derive(Deserialize)] + #[serde(untagged)] + enum VecOrString { + One(String), + Many(Vec), + } + impl VecOrString { + fn regexes(self) -> Vec { + let strs = match self { + VecOrString::Many(s) => s, + VecOrString::One(s) => vec![s], + }; + strs.into_iter().map(|s| make_regex(&s).unwrap()).collect() + } + } + + impl Default for VecOrString { + fn default() -> Self { + Self::Many(vec![]) + } + } + + #[derive(Deserialize)] + #[serde(untagged)] + enum Inner { + String(String), + Complex { + include: VecOrString, + #[serde(default)] + exclude: VecOrString, + }, + } + + let x = Inner::deserialize(de)?; + match x { + Inner::String(s) => Ok(RegexSet { + include: vec![make_regex(&s).unwrap()], + exclude: vec![], + }), + Inner::Complex { include, exclude } => Ok(RegexSet { + include: include.regexes(), + exclude: exclude.regexes(), + }), + } + } +} + +impl Serialize for RegexSet { + fn serialize(&self, _: S) -> Result + where + S: serde::Serializer, + { + todo!() + } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Serialize, Deserialize)] @@ -154,7 +251,7 @@ pub(crate) fn check_mergeable_fieldsets_inner( Ok(()) } -pub(crate) fn match_all(set: impl Iterator, re: ®ex::Regex) -> BTreeSet { +pub(crate) fn match_all(set: impl Iterator, re: &RegexSet) -> BTreeSet { let mut ids: BTreeSet = BTreeSet::new(); for id in set { if re.is_match(&id) { @@ -166,7 +263,7 @@ pub(crate) fn match_all(set: impl Iterator, re: ®ex::Regex) -> pub(crate) fn match_groups( set: impl Iterator, - re: ®ex::Regex, + re: &RegexSet, to: &str, ) -> BTreeMap> { let mut groups: BTreeMap> = BTreeMap::new(); @@ -184,7 +281,7 @@ pub(crate) fn match_groups( groups } -pub(crate) fn match_expand(s: &str, regex: ®ex::Regex, res: &str) -> Option { +pub(crate) fn match_expand(s: &str, regex: &RegexSet, res: &str) -> Option { let m = regex.captures(s)?; let mut dst = String::new(); m.expand(res, &mut dst); @@ -299,14 +396,12 @@ pub(crate) fn calc_array(mut offsets: Vec, mode: ArrayMode) -> anyhow::Resu // filter enum by enum name, then copy variant description pub(crate) fn extract_variant_desc( ir: &IR, - enum_names: &str, + enum_names: &RegexSet, bit_size: Option, ) -> anyhow::Result> { - let re = make_regex(enum_names)?; - let mut enum_desc_pair: BTreeMap = BTreeMap::new(); for (e_name, e_struct) in ir.enums.iter().filter(|(e_name, e_struct)| { - bit_size.map_or(true, |s| s == e_struct.bit_size) && re.is_match(e_name) + bit_size.map_or(true, |s| s == e_struct.bit_size) && enum_names.is_match(e_name) }) { let variant_desc_str = e_struct.variants.iter().fold(String::new(), |mut acc, v| { acc.push_str( diff --git a/src/transform/delete.rs b/src/transform/delete.rs index f387dc0..ebaabd2 100644 --- a/src/transform/delete.rs +++ b/src/transform/delete.rs @@ -7,16 +7,14 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct Delete { - pub from: String, + pub from: RegexSet, } impl Delete { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let re = make_regex(&self.from)?; - let mut ids: BTreeSet = BTreeSet::new(); for (id, _fs) in ir.fieldsets.iter() { - if re.is_match(id) { + if self.from.is_match(id) { info!("deleting fieldset {}", id); ids.insert(id.clone()); } @@ -30,7 +28,7 @@ impl Delete { let mut ids: BTreeSet = BTreeSet::new(); for (id, _e) in ir.enums.iter() { - if re.is_match(id) { + if self.from.is_match(id) { info!("deleting enum {}", id); ids.insert(id.clone()); } @@ -44,7 +42,7 @@ impl Delete { let mut ids: BTreeSet = BTreeSet::new(); for (id, _b) in ir.blocks.iter() { - if re.is_match(id) { + if self.from.is_match(id) { info!("deleting block {}", id); ids.insert(id.clone()); } diff --git a/src/transform/delete_enums.rs b/src/transform/delete_enums.rs index 1612548..16763e7 100644 --- a/src/transform/delete_enums.rs +++ b/src/transform/delete_enums.rs @@ -7,7 +7,7 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct DeleteEnums { - pub from: String, + pub from: RegexSet, pub bit_size: Option, #[serde(default)] pub soft: bool, @@ -21,12 +21,10 @@ impl DeleteEnums { append_variant_desc_to_field(ir, &variant_desc, self.bit_size); } - let re = make_regex(&self.from)?; - let mut ids: BTreeSet = BTreeSet::new(); for (id, e) in ir.enums.iter() { let bit_size_matches = self.bit_size.map_or(true, |s| s == e.bit_size); - if re.is_match(id) && bit_size_matches { + if self.from.is_match(id) && bit_size_matches { info!("deleting enum {}", id); ids.insert(id.clone()); } diff --git a/src/transform/delete_enums_used_in.rs b/src/transform/delete_enums_used_in.rs index c3cbaae..916086e 100644 --- a/src/transform/delete_enums_used_in.rs +++ b/src/transform/delete_enums_used_in.rs @@ -8,18 +8,17 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct DeleteEnumsUsedIn { - pub fieldsets: String, + pub fieldsets: RegexSet, #[serde(default)] pub soft: bool, } impl DeleteEnumsUsedIn { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let re = make_regex(&self.fieldsets)?; let mut ids: BTreeSet = BTreeSet::new(); for (id, fs) in ir.fieldsets.iter() { - if re.is_match(id) { + if self.fieldsets.is_match(id) { info!("matched fieldset {}", id); for f in &fs.fields { if let Some(id) = &f.enumm { diff --git a/src/transform/delete_fieldsets.rs b/src/transform/delete_fieldsets.rs index cb7dd66..4f17c58 100644 --- a/src/transform/delete_fieldsets.rs +++ b/src/transform/delete_fieldsets.rs @@ -7,7 +7,7 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct DeleteFieldsets { - pub from: String, + pub from: RegexSet, #[serde(default)] pub useless: bool, #[serde(default)] @@ -16,11 +16,9 @@ pub struct DeleteFieldsets { impl DeleteFieldsets { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let re = make_regex(&self.from)?; - let mut ids: BTreeSet = BTreeSet::new(); for (id, fs) in ir.fieldsets.iter() { - if re.is_match(id) && (!self.useless | is_useless(fs)) { + if self.from.is_match(id) && (!self.useless | is_useless(fs)) { info!("deleting fieldset {}", id); ids.insert(id.clone()); } diff --git a/src/transform/delete_registers.rs b/src/transform/delete_registers.rs index 9f00105..402d9b0 100644 --- a/src/transform/delete_registers.rs +++ b/src/transform/delete_registers.rs @@ -5,17 +5,15 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct DeleteRegisters { - pub block: String, - pub from: String, + pub block: RegexSet, + pub from: RegexSet, } impl DeleteRegisters { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.block)?; - let re = make_regex(&self.from)?; - for id in match_all(ir.blocks.keys().cloned(), &path_re) { + for id in match_all(ir.blocks.keys().cloned(), &self.block) { let b = ir.blocks.get_mut(&id).unwrap(); - b.items.retain(|i| !re.is_match(&i.name)); + b.items.retain(|i| !self.from.is_match(&i.name)); } Ok(()) } diff --git a/src/transform/make_block.rs b/src/transform/make_block.rs index f97cb35..bfeabd2 100644 --- a/src/transform/make_block.rs +++ b/src/transform/make_block.rs @@ -6,8 +6,8 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct MakeBlock { - pub blocks: String, - pub from: String, + pub blocks: RegexSet, + pub from: RegexSet, pub to_outer: String, pub to_block: String, pub to_inner: String, @@ -15,11 +15,13 @@ pub struct MakeBlock { impl MakeBlock { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.blocks)?; - let re = make_regex(&self.from)?; - for id in match_all(ir.blocks.keys().cloned(), &path_re) { + for id in match_all(ir.blocks.keys().cloned(), &self.blocks) { let b = ir.blocks.get_mut(&id).unwrap(); - let groups = match_groups(b.items.iter().map(|f| f.name.clone()), &re, &self.to_outer); + let groups = match_groups( + b.items.iter().map(|f| f.name.clone()), + &self.from, + &self.to_outer, + ); for (to, group) in groups { let b = ir.blocks.get_mut(&id).unwrap(); info!("blockifizing to {}", to); @@ -48,7 +50,7 @@ impl MakeBlock { .iter() .map(|&i| { let mut i = i.clone(); - i.name = match_expand(&i.name, &re, &self.to_inner).unwrap(); + i.name = match_expand(&i.name, &self.from, &self.to_inner).unwrap(); i.byte_offset -= byte_offset; i }) diff --git a/src/transform/make_field_array.rs b/src/transform/make_field_array.rs index aea4173..f36e0d3 100644 --- a/src/transform/make_field_array.rs +++ b/src/transform/make_field_array.rs @@ -7,8 +7,8 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct MakeFieldArray { - pub fieldsets: String, - pub from: String, + pub fieldsets: RegexSet, + pub from: RegexSet, pub to: String, #[serde(default)] pub mode: ArrayMode, @@ -16,11 +16,13 @@ pub struct MakeFieldArray { impl MakeFieldArray { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.fieldsets)?; - let re = make_regex(&self.from)?; - for id in match_all(ir.fieldsets.keys().cloned(), &path_re) { + for id in match_all(ir.fieldsets.keys().cloned(), &self.fieldsets) { let b = ir.fieldsets.get_mut(&id).unwrap(); - let groups = match_groups(b.fields.iter().map(|f| f.name.clone()), &re, &self.to); + let groups = match_groups( + b.fields.iter().map(|f| f.name.clone()), + &self.from, + &self.to, + ); for (to, group) in groups { info!("arrayizing to {}", to); diff --git a/src/transform/make_register_array.rs b/src/transform/make_register_array.rs index fd67cf3..0999312 100644 --- a/src/transform/make_register_array.rs +++ b/src/transform/make_register_array.rs @@ -6,8 +6,8 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct MakeRegisterArray { - pub blocks: String, - pub from: String, + pub blocks: RegexSet, + pub from: RegexSet, pub to: String, #[serde(default)] pub mode: ArrayMode, @@ -15,11 +15,9 @@ pub struct MakeRegisterArray { impl MakeRegisterArray { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.blocks)?; - let re = make_regex(&self.from)?; - for id in match_all(ir.blocks.keys().cloned(), &path_re) { + for id in match_all(ir.blocks.keys().cloned(), &self.blocks) { let b = ir.blocks.get_mut(&id).unwrap(); - let groups = match_groups(b.items.iter().map(|f| f.name.clone()), &re, &self.to); + let groups = match_groups(b.items.iter().map(|f| f.name.clone()), &self.from, &self.to); for (to, group) in groups { info!("arrayizing to {}", to); diff --git a/src/transform/merge_blocks.rs b/src/transform/merge_blocks.rs index 0df20e6..62911bc 100644 --- a/src/transform/merge_blocks.rs +++ b/src/transform/merge_blocks.rs @@ -7,17 +7,16 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct MergeBlocks { - pub from: String, + pub from: RegexSet, pub to: String, - pub main: Option, + pub main: Option, #[serde(default)] pub check: CheckLevel, } impl MergeBlocks { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let re = make_regex(&self.from)?; - let groups = match_groups(ir.blocks.keys().cloned(), &re, &self.to); + let groups = match_groups(ir.blocks.keys().cloned(), &self.from, &self.to); for (to, group) in groups { info!("Merging blocks, dest: {}", to); @@ -35,13 +34,12 @@ impl MergeBlocks { ir: &mut IR, ids: BTreeSet, to: String, - main: Option<&String>, + main: Option<&RegexSet>, ) -> anyhow::Result<()> { let mut main_id = ids.iter().next().unwrap().clone(); if let Some(main) = main { - let re = make_regex(main)?; for id in ids.iter() { - if re.is_match(id) { + if main.is_match(id) { main_id = id.clone(); break; } diff --git a/src/transform/merge_enums.rs b/src/transform/merge_enums.rs index 8f5d50b..6e4839b 100644 --- a/src/transform/merge_enums.rs +++ b/src/transform/merge_enums.rs @@ -7,9 +7,9 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct MergeEnums { - pub from: String, + pub from: RegexSet, pub to: String, - pub main: Option, + pub main: Option, #[serde(default)] pub check: CheckLevel, #[serde(default)] @@ -24,8 +24,7 @@ impl MergeEnums { append_variant_desc_to_field(ir, &variant_desc, None); } - let re = make_regex(&self.from)?; - let groups = match_groups(ir.enums.keys().cloned(), &re, &self.to); + let groups = match_groups(ir.enums.keys().cloned(), &self.from, &self.to); for (to, group) in groups { info!("Merging enums, dest: {}", to); @@ -43,13 +42,12 @@ impl MergeEnums { ir: &mut IR, ids: BTreeSet, to: String, - main: Option<&String>, + main: Option<&RegexSet>, ) -> anyhow::Result<()> { let mut main_id = ids.iter().next().unwrap().clone(); if let Some(main) = main { - let re = make_regex(main)?; for id in ids.iter() { - if re.is_match(id) { + if main.is_match(id) { main_id = id.clone(); break; } diff --git a/src/transform/merge_fieldsets.rs b/src/transform/merge_fieldsets.rs index b94dcb0..5ef38ab 100644 --- a/src/transform/merge_fieldsets.rs +++ b/src/transform/merge_fieldsets.rs @@ -7,17 +7,16 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct MergeFieldsets { - pub from: String, + pub from: RegexSet, pub to: String, - pub main: Option, + pub main: Option, #[serde(default)] pub check: CheckLevel, } impl MergeFieldsets { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let re = make_regex(&self.from)?; - let groups = match_groups(ir.fieldsets.keys().cloned(), &re, &self.to); + let groups = match_groups(ir.fieldsets.keys().cloned(), &self.from, &self.to); for (to, group) in groups { info!("Merging fieldsets, dest: {}", to); @@ -35,13 +34,12 @@ impl MergeFieldsets { ir: &mut IR, ids: BTreeSet, to: String, - main: Option<&String>, + main: Option<&RegexSet>, ) -> anyhow::Result<()> { let mut main_id = ids.iter().next().unwrap().clone(); if let Some(main) = main { - let re = make_regex(main)?; for id in ids.iter() { - if re.is_match(id) { + if main.is_match(id) { main_id = id.clone(); break; } diff --git a/src/transform/modify_byte_offset.rs b/src/transform/modify_byte_offset.rs index 400a7e9..366d137 100644 --- a/src/transform/modify_byte_offset.rs +++ b/src/transform/modify_byte_offset.rs @@ -5,30 +5,25 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct ModifyByteOffset { - pub blocks: String, - pub exclude_items: Option, + pub blocks: RegexSet, + pub exclude_items: Option, pub add_offset: i32, pub strict: Option, // if this value is false, bypass overflowed/underflowed modification } impl ModifyByteOffset { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.blocks)?; - let ex_re = if let Some(exclude_items) = &self.exclude_items { - make_regex(exclude_items)? - } else { - make_regex("")? - }; - let strict = self.strict.unwrap_or_default(); let mut err_names = Vec::new(); - for id in match_all(ir.blocks.keys().cloned(), &path_re) { + for id in match_all(ir.blocks.keys().cloned(), &self.blocks) { let b = ir.blocks.get_mut(&id).unwrap(); for i in &mut b.items { - if ex_re.is_match(&i.name) { - continue; + if let Some(exclude) = &self.exclude_items { + if exclude.is_match(&i.name) { + continue; + } } match i.byte_offset.checked_add_signed(self.add_offset) { diff --git a/src/transform/rename.rs b/src/transform/rename.rs index 82cb9e4..58bbb75 100644 --- a/src/transform/rename.rs +++ b/src/transform/rename.rs @@ -5,16 +5,14 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct Rename { - pub from: String, + pub from: RegexSet, pub to: String, } impl Rename { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let re = make_regex(&self.from)?; - let renamer = |name: &mut String| { - if let Some(res) = match_expand(name, &re, &self.to) { + if let Some(res) = match_expand(name, &self.from, &self.to) { *name = res } }; diff --git a/src/transform/rename_enum_variants.rs b/src/transform/rename_enum_variants.rs index 584b206..9d16b12 100644 --- a/src/transform/rename_enum_variants.rs +++ b/src/transform/rename_enum_variants.rs @@ -6,19 +6,17 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct RenameEnumVariants { #[serde(rename = "enum")] - pub enumm: String, - pub from: String, + pub enumm: RegexSet, + pub from: RegexSet, pub to: String, } impl RenameEnumVariants { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.enumm)?; - let re = make_regex(&self.from)?; - for id in match_all(ir.enums.keys().cloned(), &path_re) { + for id in match_all(ir.enums.keys().cloned(), &self.enumm) { let e = ir.enums.get_mut(&id).unwrap(); for i in &mut e.variants { - if let Some(name) = match_expand(&i.name, &re, &self.to) { + if let Some(name) = match_expand(&i.name, &self.from, &self.to) { i.name = name; } } diff --git a/src/transform/rename_fields.rs b/src/transform/rename_fields.rs index df76c15..c039b4f 100644 --- a/src/transform/rename_fields.rs +++ b/src/transform/rename_fields.rs @@ -5,19 +5,17 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct RenameFields { - pub fieldset: String, - pub from: String, + pub fieldset: RegexSet, + pub from: RegexSet, pub to: String, } impl RenameFields { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.fieldset)?; - let re = make_regex(&self.from)?; - for id in match_all(ir.fieldsets.keys().cloned(), &path_re) { + for id in match_all(ir.fieldsets.keys().cloned(), &self.fieldset) { let fs = ir.fieldsets.get_mut(&id).unwrap(); for f in &mut fs.fields { - if let Some(name) = match_expand(&f.name, &re, &self.to) { + if let Some(name) = match_expand(&f.name, &self.from, &self.to) { f.name = name; } } diff --git a/src/transform/rename_interrupts.rs b/src/transform/rename_interrupts.rs index 273ab46..1177566 100644 --- a/src/transform/rename_interrupts.rs +++ b/src/transform/rename_interrupts.rs @@ -5,17 +5,15 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct RenameInterrupts { - pub from: String, + pub from: RegexSet, pub to: String, } impl RenameInterrupts { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let re = make_regex(&self.from)?; - for d in ir.devices.values_mut() { for i in &mut d.interrupts { - if let Some(name) = match_expand(&i.name, &re, &self.to) { + if let Some(name) = match_expand(&i.name, &self.from, &self.to) { i.name = name; } } diff --git a/src/transform/rename_registers.rs b/src/transform/rename_registers.rs index 5fa0f1e..c429654 100644 --- a/src/transform/rename_registers.rs +++ b/src/transform/rename_registers.rs @@ -5,19 +5,17 @@ use crate::ir::*; #[derive(Debug, Serialize, Deserialize)] pub struct RenameRegisters { - pub block: String, - pub from: String, + pub block: RegexSet, + pub from: RegexSet, pub to: String, } impl RenameRegisters { pub fn run(&self, ir: &mut IR) -> anyhow::Result<()> { - let path_re = make_regex(&self.block)?; - let re = make_regex(&self.from)?; - for id in match_all(ir.blocks.keys().cloned(), &path_re) { + for id in match_all(ir.blocks.keys().cloned(), &self.block) { let b = ir.blocks.get_mut(&id).unwrap(); for i in &mut b.items { - if let Some(name) = match_expand(&i.name, &re, &self.to) { + if let Some(name) = match_expand(&i.name, &self.from, &self.to) { i.name = name; } }