diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index 45c55fca..7d3fc52c 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -5,6 +5,8 @@ This changelog tracks the Rust `svdtools` project. See ## [Unreleased] +* Add `_env` string variable map + ## [v0.3.10] 2024-02-26 * Allow to specify `name` for `enumeratedValues` diff --git a/src/patch/device.rs b/src/patch/device.rs index c06da2a1..dc812f08 100644 --- a/src/patch/device.rs +++ b/src/patch/device.rs @@ -9,7 +9,7 @@ use std::{fs::File, io::Read, path::Path}; use super::iterators::{MatchIter, Matched}; use super::peripheral::{PeripheralExt, RegisterBlockExt}; use super::yaml_ext::{AsType, GetVal}; -use super::{abspath, matchname, Config, PatchResult, Spec, VAL_LVL}; +use super::{abspath, matchname, update_env, Config, Env, PatchResult, Spec, VAL_LVL}; use super::{make_address_block, make_address_blocks, make_cpu, make_interrupt, make_peripheral}; use super::{make_dim_element, modify_dim_element, modify_register_properties}; @@ -33,14 +33,14 @@ pub trait DeviceExt { fn modify_cpu(&mut self, cmod: &Hash) -> PatchResult; /// Modify pspec inside device according to pmod - fn modify_peripheral(&mut self, pspec: &str, pmod: &Hash) -> PatchResult; + fn modify_peripheral(&mut self, pspec: &str, pmod: &Hash, env: &Env) -> PatchResult; /// Add pname given by padd to device - fn add_peripheral(&mut self, pname: &str, padd: &Hash) -> PatchResult; + fn add_peripheral(&mut self, pname: &str, padd: &Hash, env: &Env) -> PatchResult; /// Remove registers from pname and mark it as derivedFrom pderive. /// Update all derivedFrom referencing pname - fn derive_peripheral(&mut self, pname: &str, pderive: &Yaml) -> PatchResult; + fn derive_peripheral(&mut self, pname: &str, pderive: &Yaml, env: &Env) -> PatchResult; /// Move registers from pold to pnew. /// Update all derivedFrom referencing pold @@ -55,6 +55,7 @@ pub trait DeviceExt { pspec: &str, peripheral: &Hash, config: &Config, + env: &Env, ) -> PatchResult; } @@ -64,6 +65,9 @@ impl DeviceExt for Device { } fn process(&mut self, device: &Hash, config: &Config) -> PatchResult { + let mut env = Env::new(); + update_env(&mut env, device)?; + // Handle any deletions for pspec in device.str_vec_iter("_delete")? { self.delete_peripheral(pspec) @@ -91,7 +95,7 @@ impl DeviceExt for Device { "_peripherals" => { for (pspec, pmod) in val.hash()? { let pspec = pspec.str()?; - self.modify_peripheral(pspec, pmod.hash()?) + self.modify_peripheral(pspec, pmod.hash()?, &env) .with_context(|| { format!("Modifying peripherals matched to `{pspec}`") })?; @@ -115,7 +119,7 @@ impl DeviceExt for Device { } _ => self - .modify_peripheral(key, val.hash()?) + .modify_peripheral(key, val.hash()?, &env) .with_context(|| format!("Modifying peripherals matched to `{key}`"))?, } } @@ -130,14 +134,14 @@ impl DeviceExt for Device { // Handle any new peripherals (!) for (pname, padd) in device.hash_iter("_add") { let pname = pname.str()?; - self.add_peripheral(pname, padd.hash()?) + self.add_peripheral(pname, padd.hash()?, &env) .with_context(|| format!("Adding peripheral `{pname}`"))?; } // Handle any derived peripherals for (pname, pderive) in device.hash_iter("_derive") { let pname = pname.str()?; - self.derive_peripheral(pname, pderive) + self.derive_peripheral(pname, pderive, &env) .with_context(|| format!("Deriving peripheral `{pname}` from `{pderive:?}`"))?; } @@ -154,7 +158,7 @@ impl DeviceExt for Device { let periphspec = periphspec.str()?; if !periphspec.starts_with('_') { //val["_path"] = device["_path"]; // TODO: check - self.process_peripheral(periphspec, val.hash()?, config) + self.process_peripheral(periphspec, val.hash()?, config, &env) .with_context(|| format!("According to `{periphspec}`"))?; } } @@ -218,11 +222,11 @@ impl DeviceExt for Device { Ok(()) } - fn modify_peripheral(&mut self, pspec: &str, pmod: &Hash) -> PatchResult { + fn modify_peripheral(&mut self, pspec: &str, pmod: &Hash, env: &Env) -> PatchResult { let mut modified = HashSet::new(); let ptags = self.iter_peripherals(pspec).collect::>(); if !ptags.is_empty() { - let peripheral_builder = make_peripheral(pmod, true)?; + let peripheral_builder = make_peripheral(pmod, true, env)?; let dim = make_dim_element(pmod)?; for ptag in ptags { modified.insert(ptag.name.clone()); @@ -267,12 +271,12 @@ impl DeviceExt for Device { Ok(()) } - fn add_peripheral(&mut self, pname: &str, padd: &Hash) -> PatchResult { + fn add_peripheral(&mut self, pname: &str, padd: &Hash, env: &Env) -> PatchResult { if self.get_peripheral(pname).is_some() { return Err(anyhow!("device already has a peripheral {pname}")); } - let pnew = make_peripheral(padd, false)? + let pnew = make_peripheral(padd, false, env)? .name(pname.to_string()) .build(VAL_LVL)?; let pnew = if let Some(dim) = make_dim_element(padd)? { @@ -285,7 +289,7 @@ impl DeviceExt for Device { Ok(()) } - fn derive_peripheral(&mut self, pname: &str, pderive: &Yaml) -> PatchResult { + fn derive_peripheral(&mut self, pname: &str, pderive: &Yaml, env: &Env) -> PatchResult { let (pderive, info) = if let Some(pderive) = pderive.as_str() { ( pderive, @@ -300,7 +304,7 @@ impl DeviceExt for Device { })?; ( pderive, - make_peripheral(hash, true)?.derived_from(Some(pderive.into())), + make_peripheral(hash, true, env)?.derived_from(Some(pderive.into())), ) } else { return Err(anyhow!("derive: incorrect syntax for {pname}")); @@ -415,13 +419,14 @@ impl DeviceExt for Device { pspec: &str, peripheral: &Hash, config: &Config, + env: &Env, ) -> PatchResult { // Find all peripherals that match the spec let mut pcount = 0; let (pspec, ignore) = pspec.spec(); for ptag in self.iter_peripherals(pspec) { pcount += 1; - ptag.process(peripheral, config) + ptag.process(peripheral, config, env.clone()) .with_context(|| format!("Processing peripheral `{}`", ptag.name))?; } if !ignore && pcount == 0 { diff --git a/src/patch/mod.rs b/src/patch/mod.rs index c8535947..ff0bf6d0 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -1,5 +1,7 @@ pub mod patch_cli; +use std::borrow::Cow; +use std::collections::HashMap; use std::fs::File; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; @@ -30,6 +32,31 @@ use crate::get_encoder_config; const VAL_LVL: ValidateLevel = ValidateLevel::Weak; +pub type Env = HashMap, String>; + +fn update_env(env: &mut Env, dict: &Hash) -> PatchResult { + for (key, val) in dict.hash_iter("_env") { + let key = key.str()?; + let val = val.str()?; + env.insert(key.to_string().into(), val.to_string()); + } + Ok(()) +} + +fn insert_env<'a>(s: &'a str, env: &Env) -> Cow<'a, str> { + let mut s = Cow::Borrowed(s); + for (k, v) in env { + let k = format!("`{k}`"); + if s.contains(&k) { + s = s.replace(&k, v).into(); + } + } + s +} +fn insert_env_opt(s: Option<&str>, env: &Env) -> Option { + s.map(|s| insert_env(s, env).into_owned()) +} + #[non_exhaustive] #[derive(Clone, Debug)] pub struct Config { @@ -429,10 +456,10 @@ fn modify_dim_element( Ok(()) } -fn make_field(fadd: &Hash) -> Result { +fn make_field(fadd: &Hash, env: &Env) -> Result { let mut fnew = FieldInfo::builder() - .description(fadd.get_string("description")?) - .derived_from(fadd.get_string("derivedFrom")?) + .description(insert_env_opt(fadd.get_str("description")?, env)) + .derived_from(insert_env_opt(fadd.get_str("derivedFrom")?, env)) .access(fadd.get_str("access")?.and_then(Access::parse_str)) .modified_write_values( fadd.get_str("modifiedWriteValues")? @@ -460,11 +487,11 @@ fn make_field(fadd: &Hash) -> Result { Ok(fnew) } -fn make_register(radd: &Hash) -> Result { +fn make_register(radd: &Hash, env: &Env) -> Result { let mut rnew = RegisterInfo::builder() .display_name(radd.get_string("displayName")?) - .description(radd.get_string("description")?) - .derived_from(radd.get_string("derivedFrom")?) + .description(insert_env_opt(radd.get_str("description")?, env)) + .derived_from(insert_env_opt(radd.get_str("derivedFrom")?, env)) .alternate_group(radd.get_string("alternateGroup")?) .alternate_register(radd.get_string("alternateRegister")?) .properties(get_register_properties(radd)?) @@ -473,7 +500,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()?, env)? .name(fname.str()?.into()) .build(VAL_LVL)? .single(), @@ -519,10 +546,10 @@ fn make_register(radd: &Hash) -> Result { Ok(rnew) } -fn make_cluster(cadd: &Hash) -> Result { +fn make_cluster(cadd: &Hash, env: &Env) -> Result { let mut cnew = ClusterInfo::builder() - .description(cadd.get_string("description")?) - .derived_from(cadd.get_string("derivedFrom")?) + .description(insert_env_opt(cadd.get_str("description")?, env)) + .derived_from(insert_env_opt(cadd.get_str("derivedFrom")?, env)) .default_register_properties(get_register_properties(cadd)?) .children(match cadd.get_hash("registers")? { Some(h) => { @@ -530,7 +557,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, env)? .name(rname.str()?.into()) .build(VAL_LVL)?; if let Some(dim) = make_dim_element(radd)? { @@ -565,12 +592,12 @@ fn make_interrupt(iadd: &Hash) -> Result { Ok(int) } -fn make_peripheral(padd: &Hash, modify: bool) -> Result { +fn make_peripheral(padd: &Hash, modify: bool, env: &Env) -> Result { let mut pnew = PeripheralInfo::builder() .display_name(padd.get_string("displayName")?) .version(padd.get_string("version")?) - .description(padd.get_string("description")?) - .derived_from(padd.get_string("derivedFrom")?) + .description(insert_env_opt(padd.get_str("description")?, env)) + .derived_from(insert_env_opt(padd.get_str("derivedFrom")?, env)) .group_name(padd.get_string("groupName")?) .interrupt(if !modify { match padd.get_hash("interrupts")? { @@ -619,7 +646,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, env)? .name(rname.str()?.into()) .build(VAL_LVL)?; if let Some(dim) = make_dim_element(radd)? { diff --git a/src/patch/peripheral.rs b/src/patch/peripheral.rs index 149f95e1..9c938d9a 100644 --- a/src/patch/peripheral.rs +++ b/src/patch/peripheral.rs @@ -11,7 +11,7 @@ use super::register::{RegisterExt, RegisterInfoExt}; use super::yaml_ext::{AsType, GetVal, ToYaml}; use super::{ check_offsets, common_description, make_dim_element, matchname, matchsubspec, - modify_dim_element, spec_ind, Config, PatchResult, Spec, VAL_LVL, + modify_dim_element, spec_ind, update_env, Config, Env, PatchResult, Spec, VAL_LVL, }; use super::{make_cluster, make_interrupt, make_register}; @@ -22,13 +22,13 @@ pub type RegMatchIterMut<'a, 'b> = MatchIter<'b, RegisterIterMut<'a>>; /// Collecting methods for processing peripheral contents pub trait PeripheralExt: InterruptExt + RegisterBlockExt { /// Work through a peripheral, handling all registers - fn process(&mut self, peripheral: &Hash, config: &Config) -> PatchResult; + fn process(&mut self, peripheral: &Hash, config: &Config, env: Env) -> PatchResult; } /// Collecting methods for processing cluster contents pub trait ClusterExt: RegisterBlockExt { /// Work through a cluster, handling all registers - fn process(&mut self, peripheral: &Hash, pname: &str, config: &Config) -> PatchResult; + fn process(&mut self, peripheral: &Hash, config: &Config, env: Env) -> PatchResult; } /// Collecting methods for processing peripheral interrupt contents @@ -64,35 +64,47 @@ pub trait RegisterBlockExt { fn delete_cluster(&mut self, cspec: &str) -> PatchResult; /// Add rname given by radd to ptag - fn add_register(&mut self, rname: &str, radd: &Hash) -> PatchResult; + fn add_register(&mut self, rname: &str, radd: &Hash, env: &Env) -> PatchResult; /// Add cname given by cadd to ptag - fn add_cluster(&mut self, cname: &str, cadd: &Hash) -> PatchResult; + fn add_cluster(&mut self, cname: &str, cadd: &Hash, env: &Env) -> PatchResult; /// Remove fields from rname and mark it as derivedFrom rderive. /// Update all derivedFrom referencing rname - fn derive_register(&mut self, rname: &str, rderive: &Yaml) -> PatchResult; + fn derive_register(&mut self, rname: &str, rderive: &Yaml, env: &Env) -> PatchResult; /// Remove fields from rname and mark it as derivedFrom rderive. /// Update all derivedFrom referencing rname fn derive_cluster(&mut self, cname: &str, cderive: &Yaml) -> PatchResult; /// Add rname given by deriving from rcopy to ptag - fn copy_register(&mut self, rname: &str, rcopy: &Hash) -> PatchResult; + fn copy_register(&mut self, rname: &str, rcopy: &Hash, env: &Env) -> PatchResult; /// Add cname given by deriving from ccopy to ptag fn copy_cluster(&mut self, rname: &str, ccopy: &Hash) -> PatchResult; /// Modify rspec inside ptag according to rmod - fn modify_register(&mut self, rspec: &str, rmod: &Hash) -> PatchResult; + fn modify_register(&mut self, rspec: &str, rmod: &Hash, env: &Env) -> PatchResult; /// Modify cspec inside ptag according to cmod - fn modify_cluster(&mut self, cspec: &str, cmod: &Hash) -> PatchResult; + fn modify_cluster(&mut self, cspec: &str, cmod: &Hash, env: &Env) -> PatchResult; /// Work through a register, handling all fields - fn process_register(&mut self, rspec: &str, register: &Hash, config: &Config) -> PatchResult; + fn process_register( + &mut self, + rspec: &str, + register: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult; /// Work through a cluster, handling all contents - fn process_cluster(&mut self, cspec: &str, cluster: &Hash, config: &Config) -> PatchResult; + fn process_cluster( + &mut self, + cspec: &str, + cluster: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult; /// Delete substring from the beginning of register names inside ptag fn strip_start(&mut self, prefix: &str) -> PatchResult; @@ -101,17 +113,33 @@ pub trait RegisterBlockExt { fn strip_end(&mut self, suffix: &str) -> PatchResult; /// Collect same registers in peripheral into register array - fn collect_in_array(&mut self, rspec: &str, rmod: &Hash, config: &Config) -> PatchResult; + fn collect_in_array( + &mut self, + rspec: &str, + rmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult; /// Collect registers in peripheral into clusters - fn collect_in_cluster(&mut self, cname: &str, cmod: &Hash, config: &Config) -> PatchResult; + fn collect_in_cluster( + &mut self, + cname: &str, + cmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult; /// Clear contents of all fields inside registers matched by rspec fn clear_fields(&mut self, rspec: &str) -> PatchResult; } impl PeripheralExt for Peripheral { - fn process(&mut self, pmod: &Hash, config: &Config) -> PatchResult { + fn process(&mut self, pmod: &Hash, config: &Config, mut env: Env) -> PatchResult { + env.insert("peripheral".into(), self.name.clone()); + env.insert("block_path".into(), self.name.clone()); + update_env(&mut env, pmod)?; + // For derived peripherals, only process interrupts if self.derived_from.is_some() { if let Some(deletions) = pmod.get_hash("_delete").ok().flatten() { @@ -200,7 +228,7 @@ impl PeripheralExt for Peripheral { for (rname, val) in rcopy.hash()? { let rname = rname.str()?; let rcopy = val.hash()?; - self.copy_register(rname, rcopy).with_context(|| { + self.copy_register(rname, rcopy, &env).with_context(|| { format!("Copying register `{rname}` from `{val:?}`") })?; } @@ -215,7 +243,7 @@ impl PeripheralExt for Peripheral { } _ => { let rcopy = rcopy.hash()?; - self.copy_register(rname, rcopy) + self.copy_register(rname, rcopy, &env) .with_context(|| format!("Copying register `{rname}` from `{rcopy:?}`"))?; } } @@ -238,7 +266,7 @@ impl PeripheralExt for Peripheral { "_registers" => { for (rspec, val) in rmod { let rspec = rspec.str()?; - self.modify_register(rspec, val.hash()?) + self.modify_register(rspec, val.hash()?, &env) .with_context(|| format!("Modifying registers matched to `{rspec}`"))?; } } @@ -253,12 +281,12 @@ impl PeripheralExt for Peripheral { "_cluster" => { for (cspec, val) in rmod { let cspec = cspec.str()?; - self.modify_cluster(cspec, val.hash()?) + self.modify_cluster(cspec, val.hash()?, &env) .with_context(|| format!("Modifying clusters matched to `{cspec}`"))?; } } rspec => self - .modify_register(rspec, rmod) + .modify_register(rspec, rmod, &env) .with_context(|| format!("Modifying registers matched to `{rspec}`"))?, } } @@ -277,14 +305,14 @@ impl PeripheralExt for Peripheral { "_registers" => { for (rname, val) in radd { let rname = rname.str()?; - self.add_register(rname, val.hash()?) + self.add_register(rname, val.hash()?, &env) .with_context(|| format!("Adding register `{rname}`"))?; } } "_clusters" => { for (cname, val) in radd { let cname = cname.str()?; - self.add_cluster(cname, val.hash()?) + self.add_cluster(cname, val.hash()?, &env) .with_context(|| format!("Adding cluster `{cname}`"))?; } } @@ -296,7 +324,7 @@ impl PeripheralExt for Peripheral { } } rname => self - .add_register(rname, radd) + .add_register(rname, radd, &env) .with_context(|| format!("Adding register `{rname}`"))?, } } @@ -307,7 +335,7 @@ impl PeripheralExt for Peripheral { "_registers" => { for (rname, val) in rderive.hash()? { let rname = rname.str()?; - self.derive_register(rname, val).with_context(|| { + self.derive_register(rname, val, &env).with_context(|| { format!("Deriving register `{rname}` from `{val:?}`") })?; } @@ -321,9 +349,10 @@ impl PeripheralExt for Peripheral { } } _ => { - self.derive_register(rname, rderive).with_context(|| { - format!("Deriving register `{rname}` from `{rderive:?}`") - })?; + self.derive_register(rname, rderive, &env) + .with_context(|| { + format!("Deriving register `{rname}` from `{rderive:?}`") + })?; } } } @@ -332,7 +361,7 @@ impl PeripheralExt for Peripheral { for (rspec, register) in pmod { let rspec = rspec.str()?; if !rspec.starts_with('_') { - self.process_register(rspec, register.hash()?, config) + self.process_register(rspec, register.hash()?, config, &env) .with_context(|| format!("According to `{rspec}`"))?; } } @@ -340,14 +369,14 @@ impl PeripheralExt for Peripheral { // Collect registers in arrays for (rspec, rmod) in pmod.hash_iter("_array") { let rspec = rspec.str()?; - self.collect_in_array(rspec, rmod.hash()?, config) + self.collect_in_array(rspec, rmod.hash()?, config, &env) .with_context(|| format!("Collecting registers matched to `{rspec}` in array"))?; } // Collect registers in clusters for (cname, cmod) in pmod.hash_iter("_cluster") { let cname = cname.str()?; - self.collect_in_cluster(cname, cmod.hash()?, config) + self.collect_in_cluster(cname, cmod.hash()?, config, &env) .with_context(|| format!("Collecting registers in cluster `{cname}`"))?; } @@ -355,7 +384,7 @@ impl PeripheralExt for Peripheral { for (cspec, cluster) in pmod.hash_iter("_clusters") { let cspec = cspec.str()?; if !cspec.starts_with('_') { - self.process_cluster(cspec, cluster.hash()?, config) + self.process_cluster(cspec, cluster.hash()?, config, &env) .with_context(|| format!("According to `{cspec}`"))?; } } @@ -406,11 +435,11 @@ impl RegisterBlockExt for Peripheral { self.clusters_mut().matched(spec) } - fn modify_register(&mut self, rspec: &str, rmod: &Hash) -> PatchResult { + fn modify_register(&mut self, rspec: &str, rmod: &Hash, env: &Env) -> PatchResult { // TODO: empty error let rtags = self.iter_registers(rspec).collect::>(); if !rtags.is_empty() { - let register_builder = make_register(rmod)?; + let register_builder = make_register(rmod, env)?; let dim = make_dim_element(rmod)?; for rtag in rtags { modify_dim_element(rtag, &dim)?; @@ -423,7 +452,7 @@ impl RegisterBlockExt for Peripheral { Ok(()) } - fn add_register(&mut self, rname: &str, radd: &Hash) -> PatchResult { + fn add_register(&mut self, rname: &str, radd: &Hash, env: &Env) -> PatchResult { if self.registers().any(|r| r.name == rname) { return Err(anyhow!( "peripheral {} already has a register {rname}", @@ -433,7 +462,9 @@ impl RegisterBlockExt for Peripheral { self.registers .get_or_insert_with(Default::default) .push(RegisterCluster::Register({ - let reg = make_register(radd)?.name(rname.into()).build(VAL_LVL)?; + let reg = make_register(radd, env)? + .name(rname.into()) + .build(VAL_LVL)?; if let Some(dim) = make_dim_element(radd)? { reg.array(dim.build(VAL_LVL)?) } else { @@ -443,7 +474,7 @@ impl RegisterBlockExt for Peripheral { Ok(()) } - fn add_cluster(&mut self, cname: &str, cadd: &Hash) -> PatchResult { + fn add_cluster(&mut self, cname: &str, cadd: &Hash, env: &Env) -> PatchResult { if self.clusters().any(|c| c.name == cname) { return Err(anyhow!( "peripheral {} already has a cluster {cname}", @@ -453,7 +484,7 @@ impl RegisterBlockExt for Peripheral { self.registers .get_or_insert_with(Default::default) .push(RegisterCluster::Cluster({ - let cl = make_cluster(cadd)?.name(cname.into()).build(VAL_LVL)?; + let cl = make_cluster(cadd, env)?.name(cname.into()).build(VAL_LVL)?; if let Some(dim) = make_dim_element(cadd)? { cl.array(dim.build(VAL_LVL)?) } else { @@ -463,7 +494,7 @@ impl RegisterBlockExt for Peripheral { Ok(()) } - fn derive_register(&mut self, rname: &str, rderive: &Yaml) -> PatchResult { + fn derive_register(&mut self, rname: &str, rderive: &Yaml, env: &Env) -> PatchResult { let (rderive, info) = if let Some(rderive) = rderive.as_str() { ( rderive, @@ -475,7 +506,7 @@ impl RegisterBlockExt for Peripheral { })?; ( rderive, - make_register(hash)?.derived_from(Some(rderive.into())), + make_register(hash, env)?.derived_from(Some(rderive.into())), ) } else { return Err(anyhow!("derive: incorrect syntax for {rname}")); @@ -510,7 +541,7 @@ impl RegisterBlockExt for Peripheral { todo!() } - fn copy_register(&mut self, rname: &str, rcopy: &Hash) -> PatchResult { + fn copy_register(&mut self, rname: &str, rcopy: &Hash, env: &Env) -> PatchResult { let srcname = rcopy.get_str("_from")?.ok_or_else(|| { anyhow!("derive: source register not given, please add a _from field to {rname}") })?; @@ -520,7 +551,7 @@ impl RegisterBlockExt for Peripheral { .find(|r| r.name == srcname) .ok_or_else(|| anyhow!("peripheral {} does not have register {srcname}", self.name))? .clone(); - let fixes = make_register(rcopy)? + let fixes = make_register(rcopy, env)? .name(rname.into()) .display_name(Some("".into())); // Modifying fields in derived register not implemented @@ -557,11 +588,11 @@ impl RegisterBlockExt for Peripheral { Ok(()) } - fn modify_cluster(&mut self, cspec: &str, cmod: &Hash) -> PatchResult { + fn modify_cluster(&mut self, cspec: &str, cmod: &Hash, env: &Env) -> PatchResult { // TODO: empty error let ctags = self.iter_clusters(cspec).collect::>(); if !ctags.is_empty() { - let cluster_builder = make_cluster(cmod)?; + let cluster_builder = make_cluster(cmod, env)?; let dim = make_dim_element(cmod)?; for ctag in ctags { modify_dim_element(ctag, &dim)?; @@ -618,18 +649,28 @@ impl RegisterBlockExt for Peripheral { Ok(()) } - fn collect_in_array(&mut self, rspec: &str, rmod: &Hash, config: &Config) -> PatchResult { - let pname = self.name.clone(); + fn collect_in_array( + &mut self, + rspec: &str, + rmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { if let Some(regs) = self.registers.as_mut() { - collect_in_array(regs, &pname, rspec, rmod, config)?; + collect_in_array(regs, rspec, rmod, config, env)?; } Ok(()) } - fn collect_in_cluster(&mut self, cname: &str, cmod: &Hash, config: &Config) -> PatchResult { - let pname = self.name.clone(); + fn collect_in_cluster( + &mut self, + cname: &str, + cmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { if let Some(regs) = self.registers.as_mut() { - collect_in_cluster(regs, &pname, cname, cmod, config)?; + collect_in_cluster(regs, cname, cmod, config, env)?; } Ok(()) } @@ -644,19 +685,25 @@ impl RegisterBlockExt for Peripheral { Ok(()) } - fn process_register(&mut self, rspec: &str, rmod: &Hash, config: &Config) -> PatchResult { + fn process_register( + &mut self, + rspec: &str, + rmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { // Find all registers that match the spec let mut rcount = 0; - let pname = self.name.clone(); let (rspec, ignore) = rspec.spec(); for rtag in self.iter_registers(rspec) { rcount += 1; - rtag.process(rmod, &pname, config) + rtag.process(rmod, config, env.clone()) .with_context(|| format!("Processing register `{}`", rtag.name))?; } if !ignore && rcount == 0 { Err(anyhow!( - "Could not find `{pname}:{rspec}. Present registers: {}.`", + "Could not find `{}:{rspec}. Present registers: {}.`", + env.get("block_path").unwrap(), self.registers().map(|r| r.name.as_str()).join(", ") )) } else { @@ -664,19 +711,25 @@ impl RegisterBlockExt for Peripheral { } } - fn process_cluster(&mut self, cspec: &str, cmod: &Hash, config: &Config) -> PatchResult { + fn process_cluster( + &mut self, + cspec: &str, + cmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { // Find all clusters that match the spec let mut ccount = 0; - let pname = self.name.clone(); let (cspec, ignore) = cspec.spec(); for ctag in self.iter_clusters(cspec) { ccount += 1; - ctag.process(cmod, &pname, config) + ctag.process(cmod, config, env.clone()) .with_context(|| format!("Processing cluster `{}`", ctag.name))?; } if !ignore && ccount == 0 { Err(anyhow!( - "Could not find `{pname}:{cspec}. Present clusters: {}.`", + "Could not find `{}:{cspec}. Present clusters: {}.`", + env.get("block_path").unwrap(), self.clusters().map(|c| c.name.as_str()).join(", ") )) } else { @@ -686,7 +739,12 @@ impl RegisterBlockExt for Peripheral { } impl ClusterExt for Cluster { - fn process(&mut self, pmod: &Hash, _pname: &str, config: &Config) -> PatchResult { + fn process(&mut self, pmod: &Hash, config: &Config, mut env: Env) -> PatchResult { + env.insert("cluster".into(), self.name.clone()); + env.entry("block_path".into()) + .and_modify(|p| *p = format!("{p}.{}", self.name)); + update_env(&mut env, pmod)?; + // Handle deletions if let Some(deletions) = pmod.get(&"_delete".to_yaml()) { match deletions { @@ -735,7 +793,7 @@ impl ClusterExt for Cluster { for (rname, val) in rcopy.hash()? { let rname = rname.str()?; let rcopy = val.hash()?; - self.copy_register(rname, rcopy).with_context(|| { + self.copy_register(rname, rcopy, &env).with_context(|| { format!("Copying register `{rname}` from `{val:?}`") })?; } @@ -750,7 +808,7 @@ impl ClusterExt for Cluster { } _ => { let rcopy = rcopy.hash()?; - self.copy_register(rname, rcopy) + self.copy_register(rname, rcopy, &env) .with_context(|| format!("Copying register `{rname}` from `{rcopy:?}`"))?; } } @@ -773,19 +831,19 @@ impl ClusterExt for Cluster { "_registers" => { for (rspec, val) in rmod { let rspec = rspec.str()?; - self.modify_register(rspec, val.hash()?) + self.modify_register(rspec, val.hash()?, &env) .with_context(|| format!("Modifying registers matched to `{rspec}`"))?; } } "_cluster" => { for (cspec, val) in rmod { let cspec = cspec.str()?; - self.modify_cluster(cspec, val.hash()?) + self.modify_cluster(cspec, val.hash()?, &env) .with_context(|| format!("Modifying clusters matched to `{cspec}`"))?; } } rspec => self - .modify_register(rspec, rmod) + .modify_register(rspec, rmod, &env) .with_context(|| format!("Modifying registers matched to `{rspec}`"))?, } } @@ -804,19 +862,19 @@ impl ClusterExt for Cluster { "_registers" => { for (rname, val) in radd { let rname = rname.str()?; - self.add_register(rname, val.hash()?) + self.add_register(rname, val.hash()?, &env) .with_context(|| format!("Adding register `{rname}`"))?; } } "_clusters" => { for (cname, val) in radd { let cname = cname.str()?; - self.add_cluster(cname, val.hash()?) + self.add_cluster(cname, val.hash()?, &env) .with_context(|| format!("Adding cluster `{cname}`"))?; } } rname => self - .add_register(rname, radd) + .add_register(rname, radd, &env) .with_context(|| format!("Adding register `{rname}`"))?, } } @@ -827,7 +885,7 @@ impl ClusterExt for Cluster { "_registers" => { for (rname, val) in rderive.hash()? { let rname = rname.str()?; - self.derive_register(rname, val).with_context(|| { + self.derive_register(rname, val, &env).with_context(|| { format!("Deriving register `{rname}` from `{val:?}`") })?; } @@ -841,9 +899,10 @@ impl ClusterExt for Cluster { } } _ => { - self.derive_register(rname, rderive).with_context(|| { - format!("Deriving register `{rname}` from `{rderive:?}`") - })?; + self.derive_register(rname, rderive, &env) + .with_context(|| { + format!("Deriving register `{rname}` from `{rderive:?}`") + })?; } } } @@ -852,7 +911,7 @@ impl ClusterExt for Cluster { for (cspec, cluster) in pmod.hash_iter("_clusters") { let cspec = cspec.str()?; if !cspec.starts_with('_') { - self.process_cluster(cspec, cluster.hash()?, config) + self.process_cluster(cspec, cluster.hash()?, config, &env) .with_context(|| format!("According to `{cspec}`"))?; } } @@ -861,7 +920,7 @@ impl ClusterExt for Cluster { for (rspec, register) in pmod { let rspec = rspec.str()?; if !rspec.starts_with('_') { - self.process_register(rspec, register.hash()?, config) + self.process_register(rspec, register.hash()?, config, &env) .with_context(|| format!("According to `{rspec}`"))?; } } @@ -869,14 +928,14 @@ impl ClusterExt for Cluster { // Collect registers in arrays for (rspec, rmod) in pmod.hash_iter("_array") { let rspec = rspec.str()?; - self.collect_in_array(rspec, rmod.hash()?, config) + self.collect_in_array(rspec, rmod.hash()?, config, &env) .with_context(|| format!("Collecting registers matched to `{rspec}` in array"))?; } // Collect registers in clusters for (cname, cmod) in pmod.hash_iter("_cluster") { let cname = cname.str()?; - self.collect_in_cluster(cname, cmod.hash()?, config) + self.collect_in_cluster(cname, cmod.hash()?, config, &env) .with_context(|| format!("Collecting registers in cluster `{cname}`"))?; } @@ -893,10 +952,10 @@ impl RegisterBlockExt for Cluster { self.clusters_mut().matched(spec) } - fn modify_register(&mut self, rspec: &str, rmod: &Hash) -> PatchResult { + fn modify_register(&mut self, rspec: &str, rmod: &Hash, env: &Env) -> PatchResult { let rtags = self.iter_registers(rspec).collect::>(); if !rtags.is_empty() { - let register_builder = make_register(rmod)?; + let register_builder = make_register(rmod, env)?; let dim = make_dim_element(rmod)?; for rtag in rtags { modify_dim_element(rtag, &dim)?; @@ -909,7 +968,7 @@ impl RegisterBlockExt for Cluster { Ok(()) } - fn add_register(&mut self, rname: &str, radd: &Hash) -> PatchResult { + fn add_register(&mut self, rname: &str, radd: &Hash, env: &Env) -> PatchResult { if self.registers().any(|r| r.name == rname) { return Err(anyhow!( "peripheral {} already has a register {rname}", @@ -917,7 +976,9 @@ impl RegisterBlockExt for Cluster { )); } self.children.push(RegisterCluster::Register({ - let reg = make_register(radd)?.name(rname.into()).build(VAL_LVL)?; + let reg = make_register(radd, env)? + .name(rname.into()) + .build(VAL_LVL)?; if let Some(dim) = make_dim_element(radd)? { reg.array(dim.build(VAL_LVL)?) } else { @@ -927,7 +988,7 @@ impl RegisterBlockExt for Cluster { Ok(()) } - fn add_cluster(&mut self, cname: &str, cadd: &Hash) -> PatchResult { + fn add_cluster(&mut self, cname: &str, cadd: &Hash, env: &Env) -> PatchResult { if self.clusters().any(|c| c.name == cname) { return Err(anyhow!( "peripheral {} already has a register {cname}", @@ -935,7 +996,7 @@ impl RegisterBlockExt for Cluster { )); } self.children.push(RegisterCluster::Cluster({ - let cl = make_cluster(cadd)?.name(cname.into()).build(VAL_LVL)?; + let cl = make_cluster(cadd, env)?.name(cname.into()).build(VAL_LVL)?; if let Some(dim) = make_dim_element(cadd)? { cl.array(dim.build(VAL_LVL)?) } else { @@ -945,7 +1006,7 @@ impl RegisterBlockExt for Cluster { Ok(()) } - fn derive_register(&mut self, rname: &str, rderive: &Yaml) -> PatchResult { + fn derive_register(&mut self, rname: &str, rderive: &Yaml, env: &Env) -> PatchResult { let (rderive, info) = if let Some(rderive) = rderive.as_str() { ( rderive, @@ -957,7 +1018,7 @@ impl RegisterBlockExt for Cluster { })?; ( rderive, - make_register(hash)?.derived_from(Some(rderive.into())), + make_register(hash, env)?.derived_from(Some(rderive.into())), ) } else { return Err(anyhow!("derive: incorrect syntax for {rname}")); @@ -990,7 +1051,7 @@ impl RegisterBlockExt for Cluster { todo!() } - fn copy_register(&mut self, rname: &str, rcopy: &Hash) -> PatchResult { + fn copy_register(&mut self, rname: &str, rcopy: &Hash, env: &Env) -> PatchResult { let srcname = rcopy.get_str("_from")?.ok_or_else(|| { anyhow!("derive: source register not given, please add a _from field to {rname}") })?; @@ -1000,7 +1061,7 @@ impl RegisterBlockExt for Cluster { .find(|r| r.name == srcname) .ok_or_else(|| anyhow!("peripheral {} does not have register {srcname}", self.name,))? .clone(); - let fixes = make_register(rcopy)? + let fixes = make_register(rcopy, env)? .name(rname.into()) .display_name(Some("".into())); // Modifying fields in derived register not implemented @@ -1030,10 +1091,10 @@ impl RegisterBlockExt for Cluster { Ok(()) } - fn modify_cluster(&mut self, cspec: &str, cmod: &Hash) -> PatchResult { + fn modify_cluster(&mut self, cspec: &str, cmod: &Hash, env: &Env) -> PatchResult { let ctags = self.iter_clusters(cspec).collect::>(); if !ctags.is_empty() { - let cluster_builder = make_cluster(cmod)?; + let cluster_builder = make_cluster(cmod, env)?; let dim = make_dim_element(cmod)?; for ctag in ctags { modify_dim_element(ctag, &dim)?; @@ -1090,16 +1151,26 @@ impl RegisterBlockExt for Cluster { Ok(()) } - fn collect_in_array(&mut self, rspec: &str, rmod: &Hash, config: &Config) -> PatchResult { - let pname = self.name.clone(); + fn collect_in_array( + &mut self, + rspec: &str, + rmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { let regs = &mut self.children; - collect_in_array(regs, &pname, rspec, rmod, config) + collect_in_array(regs, rspec, rmod, config, env) } - fn collect_in_cluster(&mut self, cname: &str, cmod: &Hash, config: &Config) -> PatchResult { - let pname = self.name.clone(); + fn collect_in_cluster( + &mut self, + cname: &str, + cmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { let regs = &mut self.children; - collect_in_cluster(regs, &pname, cname, cmod, config) + collect_in_cluster(regs, cname, cmod, config, env) } fn clear_fields(&mut self, rspec: &str) -> PatchResult { @@ -1112,20 +1183,25 @@ impl RegisterBlockExt for Cluster { Ok(()) } - fn process_register(&mut self, rspec: &str, rmod: &Hash, config: &Config) -> PatchResult { + fn process_register( + &mut self, + rspec: &str, + rmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { // Find all registers that match the spec let mut rcount = 0; - let pname = self.name.clone(); let (rspec, ignore) = rspec.spec(); for rtag in self.iter_registers(rspec) { rcount += 1; - rtag.process(rmod, &pname, config) + rtag.process(rmod, config, env.clone()) .with_context(|| format!("Processing register `{}`", rtag.name))?; } if !ignore && rcount == 0 { Err(anyhow!( - "Could not find `{pname}:{}:{rspec}. Present registers: {}.`", - self.name, + "Could not find `{}:{rspec}. Present registers: {}.`", + env.get("block_path").unwrap(), self.registers().map(|r| r.name.as_str()).join(", ") )) } else { @@ -1133,20 +1209,25 @@ impl RegisterBlockExt for Cluster { } } - fn process_cluster(&mut self, cspec: &str, cmod: &Hash, config: &Config) -> PatchResult { + fn process_cluster( + &mut self, + cspec: &str, + cmod: &Hash, + config: &Config, + env: &Env, + ) -> PatchResult { // Find all clusters that match the spec let mut ccount = 0; - let pname = self.name.clone(); let (cspec, ignore) = cspec.spec(); for ctag in self.iter_clusters(cspec) { ccount += 1; - ctag.process(cmod, &pname, config) + ctag.process(cmod, config, env.clone()) .with_context(|| format!("Processing cluster `{}`", ctag.name))?; } if !ignore && ccount == 0 { Err(anyhow!( - "Could not find `{pname}:{}:{cspec}. Present clusters: {}.`", - self.name, + "Could not find `{}:{cspec}. Present clusters: {}.`", + env.get("block_path").unwrap(), self.clusters().map(|c| c.name.as_str()).join(", ") )) } else { @@ -1157,10 +1238,10 @@ impl RegisterBlockExt for Cluster { fn collect_in_array( regs: &mut Vec, - path: &str, rspec: &str, rmod: &Hash, config: &Config, + env: &Env, ) -> PatchResult { let mut registers = Vec::new(); let mut place = usize::MAX; @@ -1182,7 +1263,8 @@ fn collect_in_array( return Ok(()); } return Err(anyhow!( - "{path}: registers {rspec} not found. Present registers: {}.`", + "{}: registers {rspec} not found. Present registers: {}.`", + env.get("block_path").unwrap(), regs.iter() .filter_map(|rc| match rc { RegisterCluster::Register(r) => Some(r.name.as_str()), @@ -1222,7 +1304,7 @@ fn collect_in_array( if !check_offsets(&offsets, dim_increment) { return Err(anyhow!( "{}: registers cannot be collected into {rspec} array. Different addressOffset increments", - path + env.get("block_path").unwrap(), )); } let bitmasks = registers @@ -1232,7 +1314,7 @@ fn collect_in_array( if !bitmasks.iter().all(|&m| m == bitmasks[0]) { return Err(anyhow!( "{}: registers cannot be collected into {rspec} array. Different bit masks", - path + env.get("block_path").unwrap(), )); } @@ -1251,7 +1333,7 @@ fn collect_in_array( registers[0].description = common_description(&descs, &dim_index).ok_or_else(|| { anyhow!( "{}: registers cannot be collected into {rspec} array. Please, specify description", - path + env.get("block_path").unwrap(), ) })?; } @@ -1267,7 +1349,7 @@ fn collect_in_array( registers[0].display_name = common_description(&names, &dim_index).ok_or_else(|| { anyhow!( "{}: registers cannot be collected into {rspec} array. Please, specify displayName", - path + env.get("block_path").unwrap(), ) })?; } @@ -1281,7 +1363,7 @@ fn collect_in_array( ); let mut config = config.clone(); config.update_fields = true; - reg.process(rmod, path, &config) + reg.process(rmod, &config, env.clone()) .with_context(|| format!("Processing register `{}`", reg.name))?; regs.insert(place, RegisterCluster::Register(reg)); Ok(()) @@ -1289,10 +1371,10 @@ fn collect_in_array( fn collect_in_cluster( regs: &mut Vec, - path: &str, cname: &str, cmod: &Hash, config: &Config, + env: &Env, ) -> PatchResult { let mut rdict = linked_hash_map::LinkedHashMap::new(); let mut first = None; @@ -1328,7 +1410,8 @@ fn collect_in_cluster( continue; } return Err(anyhow!( - "{path}: registers {rspec} not found. Present registers: {}.`", + "{}: registers {rspec} not found. Present registers: {}.`", + env.get("block_path").unwrap(), regs.iter() .filter_map(|rc| match rc { RegisterCluster::Register(r) => Some(r.name.as_str()), @@ -1340,7 +1423,10 @@ fn collect_in_cluster( rspecs.push(rspec.to_string()); if single { if registers.len() > 1 { - return Err(anyhow!("{path}: more than one registers {rspec} found")); + return Err(anyhow!( + "{}: more than one registers {rspec} found", + env.get("block_path").unwrap() + )); } } else { registers.sort_by_key(|r| r.address_offset); @@ -1365,12 +1451,14 @@ fn collect_in_cluster( let len = registers.len(); if dim != len { return Err(anyhow!( - "{path}: registers cannot be collected into {cname} cluster. Different number of registers {rspec} ({len}) and {rspec1} ({dim})" + "{}: registers cannot be collected into {cname} cluster. Different number of registers {rspec} ({len}) and {rspec1} ({dim})", + env.get("block_path").unwrap() )); } if dim_index != new_dim_index { return Err(anyhow!( - "{path}: registers cannot be collected into {cname} cluster. {rspec} and {rspec1} have different indeces" + "{}: registers cannot be collected into {cname} cluster. {rspec} and {rspec1} have different indeces", + env.get("block_path").unwrap(), )); } } else { @@ -1387,12 +1475,14 @@ fn collect_in_cluster( } if !check_offsets(&offsets, dim_increment) { return Err(anyhow!( - "{path}: registers cannot be collected into {cname} cluster. Different addressOffset increments in {rspec} registers" + "{}: registers cannot be collected into {cname} cluster. Different addressOffset increments in {rspec} registers", + env.get("block_path").unwrap(), )); } if !bitmasks.iter().all(|&m| m == bitmasks[0]) { return Err(anyhow!( - "{path}: registers cannot be collected into {cname} cluster. Different bit masks in {rspec} registers" + "{}: registers cannot be collected into {cname} cluster. Different bit masks in {rspec} registers", + env.get("block_path").unwrap(), )); } } @@ -1400,7 +1490,8 @@ fn collect_in_cluster( } if rdict.is_empty() { return Err(anyhow!( - "{path}: registers cannot be collected into {cname} cluster. No matches found" + "{}: registers cannot be collected into {cname} cluster. No matches found", + env.get("block_path").unwrap(), )); } let address_offset = rdict @@ -1424,7 +1515,7 @@ fn collect_in_cluster( for (_, (rmod, mut registers)) in rdict.into_iter() { let mut reg = registers.swap_remove(0).single(); let rmod = rmod.hash()?; - reg.process(rmod, path, &config) + reg.process(rmod, &config, env.clone()) .with_context(|| format!("Processing register `{}`", reg.name))?; if let Some(name) = rmod.get_str("name")? { reg.name = name.into(); @@ -1438,7 +1529,7 @@ fn collect_in_cluster( for (rspec, (rmod, mut registers)) in rdict.into_iter() { let mut reg = registers.swap_remove(0).single(); let rmod = rmod.hash()?; - reg.process(rmod, path, &config) + reg.process(rmod, &config, env.clone()) .with_context(|| format!("Processing register `{}`", reg.name))?; reg.name = if let Some(name) = rmod.get_str("name")? { name.into() diff --git a/src/patch/register.rs b/src/patch/register.rs index e6acf6d7..275108e5 100644 --- a/src/patch/register.rs +++ b/src/patch/register.rs @@ -12,7 +12,7 @@ use super::iterators::{MatchIter, Matched}; use super::yaml_ext::{AsType, GetVal, ToYaml}; use super::{ check_offsets, common_description, make_dim_element, matchname, modify_dim_element, spec_ind, - Config, PatchResult, Spec, VAL_LVL, + update_env, Config, Env, PatchResult, Spec, VAL_LVL, }; use super::{make_derived_enumerated_values, make_ev_array, make_ev_name, make_field}; @@ -38,10 +38,10 @@ impl RegisterInfoExt for RegisterInfo { /// Collecting methods for processing register contents pub trait RegisterExt { /// Work through a register, handling all fields - fn process(&mut self, rmod: &Hash, pname: &str, config: &Config) -> PatchResult; + fn process(&mut self, rmod: &Hash, config: &Config, env: Env) -> PatchResult; /// Add fname given by fadd to rtag - fn add_field(&mut self, fname: &str, fadd: &Hash) -> PatchResult; + fn add_field(&mut self, fname: &str, fadd: &Hash, env: &Env) -> PatchResult; /// Delete fields matched by fspec inside rtag fn delete_field(&mut self, fspec: &str) -> PatchResult; @@ -55,20 +55,20 @@ pub trait RegisterExt { /// Work through a field, handling either an enum or a range fn process_field( &mut self, - pname: &str, fspec: &str, fmod: &Yaml, config: &Config, + env: &Env, ) -> PatchResult; /// Add an enumeratedValues given by field to all fspec in rtag fn process_field_enum( &mut self, - pname: &str, fspec: &str, fmod: &Hash, usage: Option, config: &Config, + env: &Env, ) -> PatchResult; /// Set readAction for field @@ -78,7 +78,7 @@ pub trait RegisterExt { fn set_field_modified_write_values(&mut self, fspec: &str, mwv: ModifiedWriteValues); /// Add a writeConstraint range given by field to all fspec in rtag - fn process_field_range(&mut self, pname: &str, fspec: &str, fmod: &[Yaml]) -> PatchResult; + fn process_field_range(&mut self, fspec: &str, fmod: &[Yaml], env: &Env) -> PatchResult; /// Delete substring from the beginning bitfield names inside rtag fn strip_start(&mut self, substr: &str) -> PatchResult; @@ -87,7 +87,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, env: &Env) -> PatchResult; /// Merge all fspec in rtag. /// Support list of field to auto-merge, and dict with fspec or list of fspec @@ -102,7 +102,12 @@ pub trait RegisterExt { } impl RegisterExt for Register { - fn process(&mut self, rmod: &Hash, pname: &str, config: &Config) -> PatchResult { + fn process(&mut self, rmod: &Hash, config: &Config, mut env: Env) -> PatchResult { + env.insert("register".into(), self.name.clone()); + let rpath = format!("{}.{}", env.get("block_path").unwrap(), self.name); + env.insert("register_path".into(), rpath); + update_env(&mut env, rmod)?; + if self.derived_from.is_some() { return Ok(()); } @@ -131,13 +136,13 @@ 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()?, &env) .with_context(|| format!("Modifying fields matched to `{fspec}`"))?; } // Handle additions for (fname, fadd) in rmod.hash_iter("_add") { let fname = fname.str()?; - self.add_field(fname, fadd.hash()?) + self.add_field(fname, fadd.hash()?, &env) .with_context(|| format!("Adding field `{fname}`"))?; } @@ -184,7 +189,7 @@ impl RegisterExt for Register { for (fspec, field) in rmod { let fspec = fspec.str()?; if !fspec.starts_with('_') { - self.process_field(pname, fspec, field, config) + self.process_field(fspec, field, config, &env) .with_context(|| format!("Processing field matched to `{fspec}`"))?; } } @@ -227,9 +232,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, env: &Env) -> PatchResult { let ftags = self.iter_fields(fspec).collect::>(); - let field_builder = make_field(fmod)?; + let field_builder = make_field(fmod, env)?; let dim = make_dim_element(fmod)?; if !ftags.is_empty() { for ftag in ftags { @@ -268,14 +273,14 @@ impl RegisterExt for Register { Ok(()) } - fn add_field(&mut self, fname: &str, fadd: &Hash) -> PatchResult { + fn add_field(&mut self, fname: &str, fadd: &Hash, env: &Env) -> PatchResult { if self.get_field(fname).is_some() { return Err(anyhow!( "register {} already has a field {fname}", self.name )); } - let fnew = make_field(fadd)?.name(fname.into()).build(VAL_LVL)?; + let fnew = make_field(fadd, env)?.name(fname.into()).build(VAL_LVL)?; let fnew = if let Some(dim) = make_dim_element(fadd)? { fnew.array(dim.build(VAL_LVL)?) } else { @@ -507,10 +512,10 @@ impl RegisterExt for Register { fn process_field( &mut self, - pname: &str, fspec: &str, fmod: &Yaml, config: &Config, + env: &Env, ) -> PatchResult { const READ: phf::Map<&'static str, Option> = phf::phf_map! { "_read" => None, @@ -537,7 +542,7 @@ impl RegisterExt for Register { let is_read = READ.keys().any(|key| fmod.contains_key(&key.to_yaml())); let is_write = WRITE.keys().any(|key| fmod.contains_key(&key.to_yaml())); if !is_read && !is_write { - self.process_field_enum(pname, fspec, fmod, None, config) + self.process_field_enum(fspec, fmod, None, config, env) .with_context(|| "Adding read-write enumeratedValues")?; } else { if is_read { @@ -545,11 +550,11 @@ impl RegisterExt for Register { if let Some(fmod) = fmod.get_hash(key)? { if !fmod.is_empty() { self.process_field_enum( - pname, fspec, fmod, Some(Usage::Read), config, + env, ) .with_context(|| "Adding read-only enumeratedValues")?; } @@ -565,11 +570,11 @@ impl RegisterExt for Register { if let Some(fmod) = fmod.get_hash(key)? { if !fmod.is_empty() { self.process_field_enum( - pname, fspec, fmod, Some(Usage::Write), config, + env, ) .with_context(|| "Adding write-only enumeratedValues")?; } @@ -582,7 +587,7 @@ impl RegisterExt for Register { } } Yaml::Array(fmod) if fmod.len() == 2 => { - self.process_field_range(pname, fspec, fmod) + self.process_field_range(fspec, fmod, env) .with_context(|| "Adding writeConstraint range")?; } _ => {} @@ -608,11 +613,11 @@ impl RegisterExt for Register { fn process_field_enum( &mut self, - pname: &str, fspec: &str, mut fmod: &Hash, usage: Option, config: &Config, + env: &Env, ) -> PatchResult { fn set_enum( f: &mut FieldInfo, @@ -697,12 +702,21 @@ impl RegisterExt for Register { .filter(|e| e.name.as_deref() == Some(d)); let orig_usage = match (derived_enums.next(), derived_enums.next()) { (Some(e), None) => e.usage().ok_or_else(|| { - anyhow!("{pname}: multilevel derive for {d} is not supported") + anyhow!( + "{}: multilevel derive for {d} is not supported", + env.get("register_path").unwrap() + ) })?, - (None, _) => return Err(anyhow!("{pname}: enumeratedValues {d} can't be found")), + (None, _) => { + return Err(anyhow!( + "{}: enumeratedValues {d} can't be found", + env.get("register_path").unwrap() + )) + } (Some(_), Some(_)) => { return Err(anyhow!( - "{pname}: enumeratedValues {d} was found multiple times" + "{}: enumeratedValues {d} was found multiple times", + env.get("register_path").unwrap(), )); } }; @@ -734,8 +748,8 @@ impl RegisterExt for Register { return Ok(()); } return Err(anyhow!( - "Could not find field {pname}:{}:{fspec}. Present fields: {}.`", - self.name, + "Could not find field {}:{fspec}. Present fields: {}.`", + env.get("register_path").unwrap(), self.fields().map(|f| f.name.as_str()).join(", ") )); } @@ -786,7 +800,7 @@ impl RegisterExt for Register { Ok(()) } - fn process_field_range(&mut self, pname: &str, fspec: &str, fmod: &[Yaml]) -> PatchResult { + fn process_field_range(&mut self, fspec: &str, fmod: &[Yaml], env: &Env) -> PatchResult { let mut set_any = false; let (fspec, ignore) = fspec.spec(); for ftag in self.iter_fields(fspec) { @@ -798,8 +812,8 @@ impl RegisterExt for Register { } if !ignore && !set_any { return Err(anyhow!( - "Could not find field {pname}:{}:{fspec}. Present fields: {}.`", - self.name, + "Could not find field {}:{fspec}. Present fields: {}.`", + env.get("register_path").unwrap(), self.fields().map(|f| f.name.as_str()).join(", ") )); }