Skip to content

registers_with_uniq_names #216

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 4 commits into
base: master
Choose a base branch
from
Draft
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
8 changes: 6 additions & 2 deletions src/generate/peripheral.rs
Original file line number Diff line number Diff line change
@@ -732,11 +732,15 @@ fn cluster_block(
let reg_block = register_or_cluster_block(&c.children, defaults, Some(&mod_name), nightly)?;

// Generate definition for each of the registers.
let registers = util::only_registers(&c.children);
let registers_cow = util::registers_with_uniq_names(
util::only_registers(&c.children)
.into_iter()
);
let registers: Vec<&Register> = registers_cow.iter().map(|cow| &**cow).collect();
for reg in &registers {
mod_items.extend(register::render(
reg,
&registers,
&registers[..],
p,
all_peripherals,
defaults,
19 changes: 17 additions & 2 deletions src/generate/register.rs
Original file line number Diff line number Diff line change
@@ -313,7 +313,7 @@ pub fn fields(
}

let has_reserved_variant = evs.values.len() != (1 << f.width);
let variants = evs.values
let mut variants = evs.values
.iter()
// filter out all reserved variants, as we should not
// generate code for them
@@ -330,6 +330,7 @@ pub fn fields(
format!("EnumeratedValue {} has no <value> field",
ev.name)
})?);

Ok(Variant {
description: description,
sc: sc,
@@ -340,6 +341,13 @@ pub fn fields(
})
.collect::<Result<Vec<_>>>()?;

util::rename_identifiers(&mut variants,
|variant| variant.sc.as_ref().to_owned(),
|variant, n| {
variant.sc = Ident::new(format!("{}_{}", variant.sc, n));
variant.pc = Ident::new(format!("{}_{}", variant.pc, n));
});

let pc_r = &f.pc_r;
if let Some(ref base) = base {
let pc = base.field.to_sanitized_upper_case();
@@ -649,7 +657,7 @@ pub fn fields(
}
});

let variants = evs.values
let mut variants = evs.values
.iter()
// filter out all reserved variants, as we should not
// generate code for them
@@ -676,6 +684,13 @@ pub fn fields(
)
.collect::<Result<Vec<_>>>()?;

util::rename_identifiers(&mut variants,
|variant| variant.sc.as_ref().to_owned(),
|variant, n| {
variant.sc = Ident::new(format!("{}_{}", variant.sc, n));
variant.pc = Ident::new(format!("{}_{}", variant.pc, n));
});

if variants.len() == 1 << f.width {
unsafety = None;
}
112 changes: 104 additions & 8 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::borrow::Cow;
use std::hash::Hash;
use std::collections::{HashMap, HashSet};

use inflections::Inflect;
use svd::{Access, Cluster, Register};
@@ -37,11 +39,14 @@ impl ToSanitizedSnakeCase for str {
}
}

let s = self.replace(BLACKLIST_CHARS, "");
let s = santitize_underscores(
&self.replace(BLACKLIST_CHARS, "")
.to_snake_case()
);

match s.chars().next().unwrap_or('\0') {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
Cow::from(format!("_{}", s.to_snake_case()))
Cow::from(format!("_{}", s))
}
_ => {
keywords! {
@@ -109,26 +114,32 @@ impl ToSanitizedSnakeCase for str {

impl ToSanitizedUpperCase for str {
fn to_sanitized_upper_case(&self) -> Cow<str> {
let s = self.replace(BLACKLIST_CHARS, "");
let s = santitize_underscores(
&self.replace(BLACKLIST_CHARS, "")
.to_upper_case()
);

match s.chars().next().unwrap_or('\0') {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
Cow::from(format!("_{}", s.to_upper_case()))
Cow::from(format!("_{}", s))
}
_ => Cow::from(s.to_upper_case()),
_ => Cow::from(s),
}
}
}

impl ToSanitizedPascalCase for str {
fn to_sanitized_pascal_case(&self) -> Cow<str> {
let s = self.replace(BLACKLIST_CHARS, "");
let s = santitize_underscores(
&self.replace(BLACKLIST_CHARS, "")
.to_pascal_case()
);

match s.chars().next().unwrap_or('\0') {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => {
Cow::from(format!("_{}", s.to_pascal_case()))
Cow::from(format!("_{}", s))
}
_ => Cow::from(s.to_pascal_case()),
_ => Cow::from(s),
}
}
}
@@ -137,6 +148,13 @@ pub fn respace(s: &str) -> String {
s.split_whitespace().collect::<Vec<_>>().join(" ")
}

fn santitize_underscores(s: &str) -> String {
s.split('_')
.filter(|part| part.len() > 0)
.collect::<Vec<_>>()
.join("_")
}

pub fn name_of(register: &Register) -> Cow<str> {
match *register {
Register::Single(ref info) => Cow::from(&*info.name),
@@ -148,6 +166,13 @@ pub fn name_of(register: &Register) -> Cow<str> {
}
}

pub fn set_name_of(register: &mut Register, name: String) {
match *register {
Register::Single(ref mut info) => info.name = name,
Register::Array(ref mut info, _) => info.name = name,
}
}

pub fn access_of(register: &Register) -> Access {
register.access.unwrap_or_else(|| {
if let Some(ref fields) = register.fields {
@@ -261,3 +286,74 @@ pub fn only_registers(ercs: &[Either<Register, Cluster>]) -> Vec<&Register> {
.collect();
registers
}

/// Renames registers if their name occurs multiple times
pub fn registers_with_uniq_names<'a, I: Iterator<Item = &'a Register>>(registers: I) -> Vec<Cow<'a, Register>> {
let (capacity, _) = registers.size_hint();
let mut seen = HashSet::with_capacity(capacity);
registers.map(|register| {
let mut n = 1;
let mut name = name_of(&*register);
let mut dup = false;
// Count up `n` until register name is not already present
// in `seen`
while seen.contains(&name) {
dup = true;
n += 1;
name = Cow::Owned(format!("{}_{}", name_of(&*register), n));
}
seen.insert(name.clone());

if dup {
let mut register = register.clone();
set_name_of(&mut register, name.into_owned());
Cow::Owned(register)
} else {
Cow::Borrowed(register)
}
}).collect()
}

fn count_occurrences<'a, K, I>(iter: I) -> HashMap<K, usize>
where
K: Eq + Hash,
I: Iterator<Item = K>,
{
let mut counts = HashMap::new();
for k in iter {
let count = counts.entry(k)
.or_insert(0);
*count += 1;
}
counts
}

// Generically rename identifiers that occur multiple times into a
// series where both `sc` and `pc` end in `…_1`, `…_2`, and so on.
pub fn rename_identifiers<E, K, G, S>(entries: &mut Vec<E>, getter: G, setter: S)
where
K: Eq + Hash + Clone,
G: Fn(&E) -> K,
S: Fn(&mut E, usize),
{
let counts = count_occurrences(
entries.iter()
.map(|entry| getter(entry))
);
// Rename identifiers that occur multiple times into a
// series where both `sc` and `pc` end in `…_1`,
// `…_2`, and so on.
let mut indexes = HashMap::<K, usize>::new();
for entry in entries.iter_mut() {
let key = getter(entry);
match counts.get(&key) {
Some(count) if *count > 1 => {
let index = indexes.entry(key).or_insert(0);
*index += 1;

setter(entry, *index);
}
_ => {}
}
}
}