Skip to content

Commit 13d3f7e

Browse files
authored
Merge pull request #259 from rust-embedded/derive_field
derive field
2 parents a24feb5 + 43272fa commit 13d3f7e

File tree

6 files changed

+109
-52
lines changed

6 files changed

+109
-52
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ env:
55

66
on:
77
push:
8-
branches: master
8+
branches: [master]
99
pull_request:
1010
merge_group:
1111

CHANGELOG-rust.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ This changelog tracks the Rust `svdtools` project. See
55

66
## [Unreleased]
77

8+
* `_derive` field
9+
810
## [v0.3.20] 2024-11-14
911

1012
* Implement `_expand_cluster`

src/patch/iterators.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ where
1111
spec: &'b str,
1212
}
1313

14-
impl<'b, I> Iterator for MatchIter<'b, I>
14+
impl<I> Iterator for MatchIter<'_, I>
1515
where
1616
I: Iterator,
1717
I::Item: Name,

src/patch/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
pub mod patch_cli;
22

3+
use once_cell::sync::Lazy;
4+
use regex::Regex;
35
use std::borrow::Cow;
46
use std::fs::File;
57
use std::io::{Read, Write};
@@ -821,6 +823,17 @@ impl Spec for str {
821823
}
822824
}
823825

826+
pub(crate) fn check_dimable_name(name: &str) -> Result<()> {
827+
static PATTERN: Lazy<Regex> = Lazy::new(|| {
828+
Regex::new("^(((%s)|(%s)[_A-Za-z]{1}[_A-Za-z0-9]*)|([_A-Za-z]{1}[_A-Za-z0-9]*(\\[%s\\])?)|([_A-Za-z]{1}[_A-Za-z0-9]*(%s)?[_A-Za-z0-9]*))$").unwrap()
829+
});
830+
if PATTERN.is_match(name) {
831+
Ok(())
832+
} else {
833+
Err(anyhow!("`{name}` is incorrect name"))
834+
}
835+
}
836+
824837
fn opt_interpolate<T: Interpolate>(path: &Option<&T>, s: Option<&str>) -> Option<String> {
825838
if let Some(path) = path {
826839
path.interpolate_opt(s)

src/patch/peripheral.rs

Lines changed: 46 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,6 @@ pub(crate) trait RegisterBlockExt: Name {
128128
/// Get register by name
129129
fn get_reg(&self, name: &str) -> Option<&Register>;
130130

131-
/// Get mutable register by name
132-
fn get_mut_reg(&mut self, name: &str) -> Option<&mut Register>;
133-
134131
/// Register/cluster block
135132
#[allow(unused)]
136133
fn children(&self) -> Option<&Vec<RegisterCluster>>;
@@ -249,22 +246,22 @@ pub(crate) trait RegisterBlockExt: Name {
249246

250247
/// Remove fields from rname and mark it as derivedFrom rderive.
251248
/// Update all derivedFrom referencing rname
252-
fn derive_register(&mut self, rname: &str, rderive: &Yaml, bpath: &BlockPath) -> PatchResult {
249+
fn derive_register(&mut self, rspec: &str, rderive: &Yaml, bpath: &BlockPath) -> PatchResult {
253250
let (rderive, info) = if let Some(rderive) = rderive.as_str() {
254251
(
255252
rderive,
256253
RegisterInfo::builder().derived_from(Some(rderive.into())),
257254
)
258255
} else if let Some(hash) = rderive.as_hash() {
259256
let rderive = hash.get_str("_from")?.ok_or_else(|| {
260-
anyhow!("derive: source register not given, please add a _from field to {rname}")
257+
anyhow!("derive: source register not given, please add a _from field to {rspec}")
261258
})?;
262259
(
263260
rderive,
264261
make_register(hash, Some(bpath))?.derived_from(Some(rderive.into())),
265262
)
266263
} else {
267-
return Err(anyhow!("derive: incorrect syntax for {rname}"));
264+
return Err(anyhow!("derive: incorrect syntax for {rspec}"));
268265
};
269266

270267
// Attempt to verify that the destination register name is correct.
@@ -280,25 +277,30 @@ pub(crate) trait RegisterBlockExt: Name {
280277
})?;
281278
}
282279

283-
match self.get_mut_reg(rname) {
284-
Some(register) => register.modify_from(info, VAL_LVL)?,
285-
None => {
286-
let register = info.name(rname.into()).build(VAL_LVL)?.single();
287-
self.add_child(RegisterCluster::Register(register));
288-
}
280+
let mut found = Vec::new();
281+
for register in self.iter_registers(rspec) {
282+
found.push(register.name.to_string());
283+
register.modify_from(info.clone(), VAL_LVL)?;
284+
}
285+
if found.is_empty() {
286+
super::check_dimable_name(rspec)?;
287+
let register = info.name(rspec.into()).build(VAL_LVL)?.single();
288+
self.add_child(RegisterCluster::Register(register));
289289
}
290-
for r in self
291-
.regs_mut()
292-
.filter(|r| r.derived_from.as_deref() == Some(rname))
293-
{
294-
r.derived_from = Some(rderive.into());
290+
for rname in found {
291+
for r in self
292+
.regs_mut()
293+
.filter(|r| r.derived_from.as_deref() == Some(&rname))
294+
{
295+
r.derived_from = Some(rderive.into());
296+
}
295297
}
296298
Ok(())
297299
}
298300

299301
/// Remove fields from rname and mark it as derivedFrom rderive.
300302
/// Update all derivedFrom referencing rname
301-
fn derive_cluster(&mut self, _cname: &str, _cderive: &Yaml, _bpath: &BlockPath) -> PatchResult {
303+
fn derive_cluster(&mut self, _cspec: &str, _cderive: &Yaml, _bpath: &BlockPath) -> PatchResult {
302304
todo!()
303305
}
304306

@@ -881,9 +883,6 @@ impl RegisterBlockExt for Peripheral {
881883
fn get_reg(&self, name: &str) -> Option<&Register> {
882884
self.get_register(name)
883885
}
884-
fn get_mut_reg(&mut self, name: &str) -> Option<&mut Register> {
885-
self.get_mut_register(name)
886-
}
887886
fn children(&self) -> Option<&Vec<RegisterCluster>> {
888887
self.registers.as_ref()
889888
}
@@ -919,9 +918,6 @@ impl RegisterBlockExt for Cluster {
919918
fn get_reg(&self, name: &str) -> Option<&Register> {
920919
self.get_register(name)
921920
}
922-
fn get_mut_reg(&mut self, name: &str) -> Option<&mut Register> {
923-
self.get_mut_register(name)
924-
}
925921
fn children(&self) -> Option<&Vec<RegisterCluster>> {
926922
Some(&self.children)
927923
}
@@ -1128,29 +1124,29 @@ impl PeripheralExt for Peripheral {
11281124
}
11291125
}
11301126

1131-
for (rname, rderive) in pmod.hash_iter("_derive") {
1132-
let rname = rname.str()?;
1133-
match rname {
1127+
for (rspec, rderive) in pmod.hash_iter("_derive") {
1128+
let rspec = rspec.str()?;
1129+
match rspec {
11341130
"_registers" => {
1135-
for (rname, val) in rderive.hash()? {
1136-
let rname = rname.str()?;
1137-
self.derive_register(rname, val, &ppath).with_context(|| {
1138-
format!("Deriving register `{rname}` from `{val:?}`")
1131+
for (rspec, val) in rderive.hash()? {
1132+
let rspec = rspec.str()?;
1133+
self.derive_register(rspec, val, &ppath).with_context(|| {
1134+
format!("Deriving register `{rspec}` from `{val:?}`")
11391135
})?;
11401136
}
11411137
}
11421138
"_clusters" => {
1143-
for (cname, val) in rderive.hash()? {
1144-
let cname = cname.str()?;
1145-
self.derive_cluster(rname, val, &ppath).with_context(|| {
1146-
format!("Deriving cluster `{cname}` from `{val:?}`")
1139+
for (cspec, val) in rderive.hash()? {
1140+
let cspec = cspec.str()?;
1141+
self.derive_cluster(cspec, val, &ppath).with_context(|| {
1142+
format!("Deriving cluster `{cspec}` from `{val:?}`")
11471143
})?;
11481144
}
11491145
}
11501146
_ => {
1151-
self.derive_register(rname, rderive, &ppath)
1147+
self.derive_register(rspec, rderive, &ppath)
11521148
.with_context(|| {
1153-
format!("Deriving register `{rname}` from `{rderive:?}`")
1149+
format!("Deriving register `{rspec}` from `{rderive:?}`")
11541150
})?;
11551151
}
11561152
}
@@ -1421,29 +1417,29 @@ impl ClusterExt for Cluster {
14211417
}
14221418
}
14231419

1424-
for (rname, rderive) in cmod.hash_iter("_derive") {
1425-
let rname = rname.str()?;
1426-
match rname {
1420+
for (rspec, rderive) in cmod.hash_iter("_derive") {
1421+
let rspec = rspec.str()?;
1422+
match rspec {
14271423
"_registers" => {
1428-
for (rname, val) in rderive.hash()? {
1429-
let rname = rname.str()?;
1430-
self.derive_register(rname, val, &cpath).with_context(|| {
1431-
format!("Deriving register `{rname}` from `{val:?}`")
1424+
for (rspec, val) in rderive.hash()? {
1425+
let rspec = rspec.str()?;
1426+
self.derive_register(rspec, val, &cpath).with_context(|| {
1427+
format!("Deriving register `{rspec}` from `{val:?}`")
14321428
})?;
14331429
}
14341430
}
14351431
"_clusters" => {
1436-
for (cname, val) in rderive.hash()? {
1437-
let cname = cname.str()?;
1438-
self.derive_cluster(rname, val, &cpath).with_context(|| {
1439-
format!("Deriving cluster `{cname}` from `{val:?}`")
1432+
for (cspec, val) in rderive.hash()? {
1433+
let cspec = cspec.str()?;
1434+
self.derive_cluster(cspec, val, &cpath).with_context(|| {
1435+
format!("Deriving cluster `{cspec}` from `{val:?}`")
14401436
})?;
14411437
}
14421438
}
14431439
_ => {
1444-
self.derive_register(rname, rderive, &cpath)
1440+
self.derive_register(rspec, rderive, &cpath)
14451441
.with_context(|| {
1446-
format!("Deriving register `{rname}` from `{rderive:?}`")
1442+
format!("Deriving register `{rspec}` from `{rderive:?}`")
14471443
})?;
14481444
}
14491445
}

src/patch/register.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub trait RegisterExt {
4444
"_include",
4545
"_path",
4646
"_delete",
47+
"_derive",
4748
"_strip",
4849
"_strip_end",
4950
"_clear",
@@ -69,6 +70,9 @@ pub trait RegisterExt {
6970
/// Delete fields matched by fspec inside rtag
7071
fn delete_field(&mut self, fspec: &str) -> PatchResult;
7172

73+
/// Clear field from rname and mark it as derivedFrom rderive.
74+
fn derive_field(&mut self, fname: &str, fderive: &Yaml, rpath: &RegisterPath) -> PatchResult;
75+
7276
/// Clear contents of fields matched by fspec inside rtag
7377
fn clear_field(&mut self, fspec: &str) -> PatchResult;
7478

@@ -186,6 +190,12 @@ impl RegisterExt for Register {
186190
self.add_field(fname, fadd.hash()?, &rpath)
187191
.with_context(|| format!("Adding field `{fname}`"))?;
188192
}
193+
// Handle derives
194+
for (fspec, fderive) in rmod.hash_iter("_derive") {
195+
let fspec = fspec.str()?;
196+
self.derive_field(fspec, fderive, &rpath)
197+
.with_context(|| format!("Deriving field `{fspec}` from `{fderive:?}`"))?;
198+
}
189199

190200
// Handle merges
191201
match rmod.get_yaml("_merge") {
@@ -342,6 +352,42 @@ impl RegisterExt for Register {
342352
Ok(())
343353
}
344354

355+
fn derive_field(&mut self, fspec: &str, fderive: &Yaml, rpath: &RegisterPath) -> PatchResult {
356+
fn make_path(dpath: &str, rpath: &RegisterPath) -> String {
357+
let mut parts = dpath.split(".");
358+
if let (Some(reg), Some(field), None) = (parts.next(), parts.next(), parts.next()) {
359+
let fpath = rpath.block.new_register(reg).new_field(field);
360+
fpath.to_string()
361+
} else {
362+
dpath.into()
363+
}
364+
}
365+
let info = if let Some(dpath) = fderive.as_str() {
366+
FieldInfo::builder().derived_from(Some(make_path(dpath, rpath)))
367+
} else if let Some(hash) = fderive.as_hash() {
368+
let dpath = hash.get_str("_from")?.ok_or_else(|| {
369+
anyhow!("derive: source field not given, please add a _from field to {fspec}")
370+
})?;
371+
make_field(hash, Some(rpath))?.derived_from(Some(make_path(dpath, rpath)))
372+
} else {
373+
return Err(anyhow!("derive: incorrect syntax for {fspec}"));
374+
};
375+
376+
let mut found = false;
377+
for field in self.iter_fields(fspec) {
378+
found = true;
379+
field.modify_from(info.clone(), VAL_LVL)?;
380+
}
381+
if !found {
382+
{
383+
super::check_dimable_name(fspec)?;
384+
let field = info.name(fspec.into()).build(VAL_LVL)?.single();
385+
self.fields.get_or_insert(Vec::new()).push(field);
386+
}
387+
}
388+
Ok(())
389+
}
390+
345391
fn clear_field(&mut self, fspec: &str) -> PatchResult {
346392
for ftag in self.iter_fields(fspec) {
347393
if ftag.derived_from.is_some() {

0 commit comments

Comments
 (0)