Skip to content
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

registers_with_uniq_names #216

Draft
wants to merge 4 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
8 changes: 6 additions & 2 deletions src/generate/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
19 changes: 17 additions & 2 deletions src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -330,6 +330,7 @@ pub fn fields(
format!("EnumeratedValue {} has no <value> field",
ev.name)
})?);

Ok(Variant {
description: description,
sc: sc,
Expand All @@ -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();
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand Down
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};
Expand Down Expand Up @@ -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! {
Expand Down Expand Up @@ -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),
}
}
}
Expand All @@ -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),
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
}
_ => {}
}
}
}