Skip to content

Commit

Permalink
Merge pull request #218 from rust-embedded/path_interpolate
Browse files Browse the repository at this point in the history
Interpolate path and name
  • Loading branch information
burrbull committed Mar 25, 2024
2 parents d6a30c4 + 38028cc commit b4f3770
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 29 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG-rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
76 changes: 64 additions & 12 deletions src/patch/mod.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -462,10 +464,10 @@ fn modify_dim_element<T: Clone>(
Ok(())
}

fn make_field(fadd: &Hash) -> Result<FieldInfoBuilder> {
fn make_field(fadd: &Hash, rpath: Option<&RegisterPath>) -> Result<FieldInfoBuilder> {
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")?
Expand Down Expand Up @@ -493,11 +495,11 @@ fn make_field(fadd: &Hash) -> Result<FieldInfoBuilder> {
Ok(fnew)
}

fn make_register(radd: &Hash) -> Result<RegisterInfoBuilder> {
fn make_register(radd: &Hash, path: Option<&BlockPath>) -> Result<RegisterInfoBuilder> {
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)?)
Expand All @@ -506,7 +508,7 @@ fn make_register(radd: &Hash) -> Result<RegisterInfoBuilder> {
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(),
Expand Down Expand Up @@ -552,18 +554,18 @@ fn make_register(radd: &Hash) -> Result<RegisterInfoBuilder> {
Ok(rnew)
}

fn make_cluster(cadd: &Hash) -> Result<ClusterInfoBuilder> {
fn make_cluster(cadd: &Hash, path: Option<&BlockPath>) -> Result<ClusterInfoBuilder> {
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) => {
let mut ch = Vec::new();
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)? {
Expand Down Expand Up @@ -652,7 +654,7 @@ fn make_peripheral(padd: &Hash, modify: bool) -> Result<PeripheralInfoBuilder> {
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)? {
Expand Down Expand Up @@ -802,3 +804,53 @@ impl Spec for str {
}
}
}

fn opt_interpolate<T: Interpolate>(path: &Option<&T>, s: Option<&str>) -> Option<String> {
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<String> {
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
}
}
28 changes: 16 additions & 12 deletions src/patch/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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}"));
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
}

Expand All @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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)?;
Expand All @@ -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)?;
Expand Down
12 changes: 7 additions & 5 deletions src/patch/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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::<Vec<_>>();
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 {
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit b4f3770

Please sign in to comment.