Skip to content

add _env keyword #196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]

* Add `_env` string variable map

## [v0.3.10] 2024-02-26

* Allow to specify `name` for `enumeratedValues`
Expand Down
37 changes: 21 additions & 16 deletions src/patch/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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
Expand All @@ -55,6 +55,7 @@ pub trait DeviceExt {
pspec: &str,
peripheral: &Hash,
config: &Config,
env: &Env,
) -> PatchResult;
}

Expand All @@ -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)
Expand Down Expand Up @@ -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}`")
})?;
Expand All @@ -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}`"))?,
}
}
Expand All @@ -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:?}`"))?;
}

Expand All @@ -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}`"))?;
}
}
Expand Down Expand Up @@ -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::<Vec<_>>();
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());
Expand Down Expand Up @@ -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)? {
Expand All @@ -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,
Expand All @@ -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}"));
Expand Down Expand Up @@ -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 {
Expand Down
57 changes: 42 additions & 15 deletions src/patch/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -30,6 +32,31 @@ use crate::get_encoder_config;

const VAL_LVL: ValidateLevel = ValidateLevel::Weak;

pub type Env = HashMap<Cow<'static, str>, 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<String> {
s.map(|s| insert_env(s, env).into_owned())
}

#[non_exhaustive]
#[derive(Clone, Debug)]
pub struct Config {
Expand Down Expand Up @@ -429,10 +456,10 @@ fn modify_dim_element<T: Clone>(
Ok(())
}

fn make_field(fadd: &Hash) -> Result<FieldInfoBuilder> {
fn make_field(fadd: &Hash, env: &Env) -> Result<FieldInfoBuilder> {
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")?
Expand Down Expand Up @@ -460,11 +487,11 @@ fn make_field(fadd: &Hash) -> Result<FieldInfoBuilder> {
Ok(fnew)
}

fn make_register(radd: &Hash) -> Result<RegisterInfoBuilder> {
fn make_register(radd: &Hash, env: &Env) -> 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(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)?)
Expand All @@ -473,7 +500,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()?, env)?
.name(fname.str()?.into())
.build(VAL_LVL)?
.single(),
Expand Down Expand Up @@ -519,18 +546,18 @@ fn make_register(radd: &Hash) -> Result<RegisterInfoBuilder> {
Ok(rnew)
}

fn make_cluster(cadd: &Hash) -> Result<ClusterInfoBuilder> {
fn make_cluster(cadd: &Hash, env: &Env) -> Result<ClusterInfoBuilder> {
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) => {
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, env)?
.name(rname.str()?.into())
.build(VAL_LVL)?;
if let Some(dim) = make_dim_element(radd)? {
Expand Down Expand Up @@ -565,12 +592,12 @@ fn make_interrupt(iadd: &Hash) -> Result<InterruptBuilder> {
Ok(int)
}

fn make_peripheral(padd: &Hash, modify: bool) -> Result<PeripheralInfoBuilder> {
fn make_peripheral(padd: &Hash, modify: bool, env: &Env) -> Result<PeripheralInfoBuilder> {
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")? {
Expand Down Expand Up @@ -619,7 +646,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, env)?
.name(rname.str()?.into())
.build(VAL_LVL)?;
if let Some(dim) = make_dim_element(radd)? {
Expand Down
Loading