From 38028cc9eaad6c3f940a2d52fd4ac09433be1c15 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 12 Mar 2024 14:07:39 +0300 Subject: [PATCH] Interpolate path and name --- CHANGELOG-rust.md | 2 ++ src/patch/mod.rs | 76 ++++++++++++++++++++++++++++++++++------- src/patch/peripheral.rs | 28 ++++++++------- src/patch/register.rs | 12 ++++--- 4 files changed, 89 insertions(+), 29 deletions(-) diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index e20c653..122291f 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -5,6 +5,8 @@ This changelog tracks the Rust `svdtools` project. See ## [Unreleased] +* Interpolate path and name in `description` and `derivedFrom` + ## [v0.3.12] 2024-03-23 * `dimArrayIndex` support diff --git a/src/patch/mod.rs b/src/patch/mod.rs index 5f3a4c9..5ca40b8 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -1,8 +1,10 @@ pub mod patch_cli; +use std::borrow::Cow; use std::fs::File; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; +use svd_parser::expand::{BlockPath, FieldPath, RegisterPath}; use svd_parser::svd::{ addressblock::AddressBlockBuilder, interrupt::InterruptBuilder, Access, AddressBlock, AddressBlockUsage, ClusterInfo, ClusterInfoBuilder, Cpu, CpuBuilder, Endian, EnumeratedValue, @@ -462,10 +464,10 @@ fn modify_dim_element( Ok(()) } -fn make_field(fadd: &Hash) -> Result { +fn make_field(fadd: &Hash, rpath: Option<&RegisterPath>) -> Result { let mut fnew = FieldInfo::builder() - .description(fadd.get_string("description")?) - .derived_from(fadd.get_string("derivedFrom")?) + .description(opt_interpolate(&rpath, fadd.get_str("description")?)) + .derived_from(opt_interpolate(&rpath, fadd.get_str("derivedFrom")?)) .access(fadd.get_str("access")?.and_then(Access::parse_str)) .modified_write_values( fadd.get_str("modifiedWriteValues")? @@ -493,11 +495,11 @@ fn make_field(fadd: &Hash) -> Result { Ok(fnew) } -fn make_register(radd: &Hash) -> Result { +fn make_register(radd: &Hash, path: Option<&BlockPath>) -> Result { let mut rnew = RegisterInfo::builder() .display_name(radd.get_string("displayName")?) - .description(radd.get_string("description")?) - .derived_from(radd.get_string("derivedFrom")?) + .description(opt_interpolate(&path, radd.get_str("description")?)) + .derived_from(opt_interpolate(&path, radd.get_str("derivedFrom")?)) .alternate_group(radd.get_string("alternateGroup")?) .alternate_register(radd.get_string("alternateRegister")?) .properties(get_register_properties(radd)?) @@ -506,7 +508,7 @@ fn make_register(radd: &Hash) -> Result { let mut fields = Vec::new(); for (fname, val) in h { fields.push( - make_field(val.hash()?)? + make_field(val.hash()?, None)? .name(fname.str()?.into()) .build(VAL_LVL)? .single(), @@ -552,10 +554,10 @@ fn make_register(radd: &Hash) -> Result { Ok(rnew) } -fn make_cluster(cadd: &Hash) -> Result { +fn make_cluster(cadd: &Hash, path: Option<&BlockPath>) -> Result { let mut cnew = ClusterInfo::builder() - .description(cadd.get_string("description")?) - .derived_from(cadd.get_string("derivedFrom")?) + .description(opt_interpolate(&path, cadd.get_str("description")?)) + .derived_from(opt_interpolate(&path, cadd.get_str("derivedFrom")?)) .default_register_properties(get_register_properties(cadd)?) .children(match cadd.get_hash("registers")? { Some(h) => { @@ -563,7 +565,7 @@ fn make_cluster(cadd: &Hash) -> Result { for (rname, val) in h { ch.push(RegisterCluster::Register({ let radd = val.hash()?; - let reg = make_register(radd)? + let reg = make_register(radd, None)? .name(rname.str()?.into()) .build(VAL_LVL)?; if let Some(dim) = make_dim_element(radd)? { @@ -652,7 +654,7 @@ fn make_peripheral(padd: &Hash, modify: bool) -> Result { for (rname, val) in h.iter() { regs.push(RegisterCluster::Register({ let radd = val.hash()?; - let reg = make_register(radd)? + let reg = make_register(radd, None)? .name(rname.str()?.into()) .build(VAL_LVL)?; if let Some(dim) = make_dim_element(radd)? { @@ -802,3 +804,53 @@ impl Spec for str { } } } + +fn opt_interpolate(path: &Option<&T>, s: Option<&str>) -> Option { + path.and_then(|path| path.interpolate_opt(s)) +} + +trait Interpolate { + fn interpolate<'a>(&self, s: &'a str) -> Cow<'a, str>; + fn interpolate_opt(&self, s: Option<&str>) -> Option { + s.map(|s| self.interpolate(s).into_owned()) + } +} + +impl Interpolate for BlockPath { + fn interpolate<'a>(&self, s: &'a str) -> Cow<'a, str> { + let mut cow = Cow::Borrowed(s); + if cow.contains("`peripheral`") { + cow = cow.replace("`peripheral`", &self.peripheral).into() + } + if cow.contains("`block_path`") { + cow = cow.replace("`block_path`", &self.to_string()).into() + } + cow + } +} + +impl Interpolate for RegisterPath { + fn interpolate<'a>(&self, s: &'a str) -> Cow<'a, str> { + let mut cow = self.block.interpolate(s); + if cow.contains("`register`") { + cow = cow.replace("`register`", &self.name).into() + } + if cow.contains("`register_path`") { + cow = cow.replace("`register_path`", &self.to_string()).into() + } + cow + } +} + +impl Interpolate for FieldPath { + fn interpolate<'a>(&self, s: &'a str) -> Cow<'a, str> { + let mut cow = self.register().interpolate(s); + if cow.contains("`field`") { + cow = cow.replace("`field`", &self.name).into() + } + if cow.contains("`field_path`") { + cow = cow.replace("`field_path`", &self.to_string()).into() + } + cow + } +} diff --git a/src/patch/peripheral.rs b/src/patch/peripheral.rs index f9e0559..453c010 100644 --- a/src/patch/peripheral.rs +++ b/src/patch/peripheral.rs @@ -202,7 +202,9 @@ pub(crate) trait RegisterBlockExt: Name { )); } self.add_child(RegisterCluster::Register({ - let reg = make_register(radd)?.name(rname.into()).build(VAL_LVL)?; + let reg = make_register(radd, Some(bpath))? + .name(rname.into()) + .build(VAL_LVL)?; if let Some(dim) = make_dim_element(radd)? { reg.array(dim.build(VAL_LVL)?) } else { @@ -221,7 +223,9 @@ pub(crate) trait RegisterBlockExt: Name { )); } self.add_child(RegisterCluster::Cluster({ - let cl = make_cluster(cadd)?.name(cname.into()).build(VAL_LVL)?; + let cl = make_cluster(cadd, Some(bpath))? + .name(cname.into()) + .build(VAL_LVL)?; if let Some(dim) = make_dim_element(cadd)? { cl.array(dim.build(VAL_LVL)?) } else { @@ -245,7 +249,7 @@ pub(crate) trait RegisterBlockExt: Name { })?; ( rderive, - make_register(hash)?.derived_from(Some(rderive.into())), + make_register(hash, Some(bpath))?.derived_from(Some(rderive.into())), ) } else { return Err(anyhow!("derive: incorrect syntax for {rname}")); @@ -295,7 +299,7 @@ pub(crate) trait RegisterBlockExt: Name { ) })? .clone(); - let fixes = make_register(rcopy)? + let fixes = make_register(rcopy, Some(bpath))? .name(rname.into()) .display_name(Some("".into())); // Modifying fields in derived register not implemented @@ -325,10 +329,10 @@ pub(crate) trait RegisterBlockExt: Name { "Could not find `{bpath}:{rcspec}. Present registers: {present}.`" )) } else { - modify_cluster(ctags, rcmod) + modify_cluster(ctags, rcmod, bpath) } } else { - modify_register(rtags, rcmod) + modify_register(rtags, rcmod, bpath) } } @@ -342,7 +346,7 @@ pub(crate) trait RegisterBlockExt: Name { "Could not find `{bpath}:{rspec}. Present registers: {present}.`" )); } - modify_register(rtags, rmod) + modify_register(rtags, rmod, bpath) } /// Modify cspec inside ptag according to cmod @@ -355,7 +359,7 @@ pub(crate) trait RegisterBlockExt: Name { "Could not find cluster `{bpath}:{cspec}. Present clusters: {present}.`" )); } - modify_cluster(ctags, cmod) + modify_cluster(ctags, cmod, bpath) } /// Work through a register or cluster fn process_child( @@ -553,8 +557,8 @@ pub(crate) trait RegisterBlockExt: Name { } } -fn modify_register(rtags: Vec<&mut Register>, rmod: &Hash) -> PatchResult { - let register_builder = make_register(rmod)?; +fn modify_register(rtags: Vec<&mut Register>, rmod: &Hash, bpath: &BlockPath) -> PatchResult { + let register_builder = make_register(rmod, Some(bpath))?; let dim = make_dim_element(rmod)?; for rtag in rtags { modify_dim_element(rtag, &dim)?; @@ -566,8 +570,8 @@ fn modify_register(rtags: Vec<&mut Register>, rmod: &Hash) -> PatchResult { Ok(()) } -fn modify_cluster(ctags: Vec<&mut Cluster>, cmod: &Hash) -> PatchResult { - let cluster_builder = make_cluster(cmod)?; +fn modify_cluster(ctags: Vec<&mut Cluster>, cmod: &Hash, bpath: &BlockPath) -> PatchResult { + let cluster_builder = make_cluster(cmod, Some(bpath))?; let dim = make_dim_element(cmod)?; for ctag in ctags { modify_dim_element(ctag, &dim)?; diff --git a/src/patch/register.rs b/src/patch/register.rs index f203a7a..436bb56 100644 --- a/src/patch/register.rs +++ b/src/patch/register.rs @@ -110,7 +110,7 @@ pub trait RegisterExt { fn strip_end(&mut self, substr: &str) -> PatchResult; /// Modify fspec inside rtag according to fmod - fn modify_field(&mut self, fspec: &str, fmod: &Hash) -> PatchResult; + fn modify_field(&mut self, fspec: &str, fmod: &Hash, rpath: &RegisterPath) -> PatchResult; /// Merge all fspec in rtag. /// Support list of field to auto-merge, and dict with fspec or list of fspec @@ -175,7 +175,7 @@ impl RegisterExt for Register { // Handle modifications for (fspec, fmod) in rmod.hash_iter("_modify") { let fspec = fspec.str()?; - self.modify_field(fspec, fmod.hash()?) + self.modify_field(fspec, fmod.hash()?, &rpath) .with_context(|| format!("Modifying fields matched to `{fspec}`"))?; } // Handle additions @@ -268,9 +268,9 @@ impl RegisterExt for Register { Ok(()) } - fn modify_field(&mut self, fspec: &str, fmod: &Hash) -> PatchResult { + fn modify_field(&mut self, fspec: &str, fmod: &Hash, rpath: &RegisterPath) -> PatchResult { let ftags = self.iter_fields(fspec).collect::>(); - let field_builder = make_field(fmod)?; + let field_builder = make_field(fmod, Some(rpath))?; let dim = make_dim_element(fmod)?; if !ftags.is_empty() { for ftag in ftags { @@ -313,7 +313,9 @@ impl RegisterExt for Register { if self.get_field(fname).is_some() { return Err(anyhow!("register {rpath} already has a field {fname}")); } - let fnew = make_field(fadd)?.name(fname.into()).build(VAL_LVL)?; + let fnew = make_field(fadd, Some(rpath))? + .name(fname.into()) + .build(VAL_LVL)?; let fnew = if let Some(dim) = make_dim_element(fadd)? { fnew.array(dim.build(VAL_LVL)?) } else {