From 369807d77ca762c40bafbae61ffffef207abee1e Mon Sep 17 00:00:00 2001 From: Astro Date: Fri, 11 May 2018 17:47:13 +0200 Subject: [PATCH 1/4] registers_with_uniq_names --- src/generate/peripheral.rs | 8 ++++++-- src/util.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs index 903a69a3..5f3ed5d7 100644 --- a/src/generate/peripheral.rs +++ b/src/generate/peripheral.rs @@ -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 ®isters { mod_items.extend(register::render( reg, - ®isters, + ®isters[..], p, all_peripherals, defaults, diff --git a/src/util.rs b/src/util.rs index ab216538..6868b6b1 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::collections::HashSet; use inflections::Inflect; use svd::{Access, Cluster, Register}; @@ -148,6 +149,13 @@ pub fn name_of(register: &Register) -> Cow { } } +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 +269,30 @@ pub fn only_registers(ercs: &[Either]) -> Vec<&Register> { .collect(); registers } + +/// Renames registers if their name occurs multiple times +pub fn registers_with_uniq_names<'a, I: Iterator>(registers: I) -> Vec> { + 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() +} From 8e6f21256f728361b746d805e0ab2fff2258f133 Mon Sep 17 00:00:00 2001 From: Astro Date: Fri, 11 May 2018 19:27:01 +0200 Subject: [PATCH 2/4] avoid enum identifier collisions --- src/generate/register.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/generate/register.rs b/src/generate/register.rs index 782cf592..cfd98988 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use cast::u64; use either::Either; use quote::Tokens; @@ -313,7 +315,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 +332,7 @@ pub fn fields( format!("EnumeratedValue {} has no field", ev.name) })?); + Ok(Variant { description: description, sc: sc, @@ -340,6 +343,33 @@ pub fn fields( }) .collect::>>()?; + // Count identifiers + let mut sc_counts = HashMap::::new(); + for variant in variants.iter() { + let sc_count = sc_counts.entry( + variant.sc.as_ref().to_owned() + ).or_insert(0); + *sc_count += 1; + } + // Rename identifiers that occur multiple times into a + // series where both `sc` and `pc` end in `…_1`, + // `…_2`, and so on. + let mut sc_indexes = HashMap::::new(); + for variant in variants.iter_mut() { + match sc_counts.get(variant.sc.as_ref()) { + Some(count) if *count > 1 => { + let sc_index = sc_indexes.entry( + variant.sc.as_ref().to_owned() + ).or_insert(0); + *sc_index += 1; + + variant.sc = Ident::new(format!("{}_{}", variant.sc, *sc_index)); + variant.pc = Ident::new(format!("{}_{}", variant.pc, *sc_index)); + } + _ => {} + } + } + let pc_r = &f.pc_r; if let Some(ref base) = base { let pc = base.field.to_sanitized_upper_case(); From 20ccad38cdb2b0e6f17b71e560e951ee84a9a290 Mon Sep 17 00:00:00 2001 From: Astro Date: Fri, 11 May 2018 20:26:59 +0200 Subject: [PATCH 3/4] avoid W enum identifiers too with generic rename_identifiers() --- src/generate/register.rs | 43 ++++++++++++------------------------ src/util.rs | 47 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/generate/register.rs b/src/generate/register.rs index cfd98988..8de8f559 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use cast::u64; use either::Either; use quote::Tokens; @@ -343,32 +341,12 @@ pub fn fields( }) .collect::>>()?; - // Count identifiers - let mut sc_counts = HashMap::::new(); - for variant in variants.iter() { - let sc_count = sc_counts.entry( - variant.sc.as_ref().to_owned() - ).or_insert(0); - *sc_count += 1; - } - // Rename identifiers that occur multiple times into a - // series where both `sc` and `pc` end in `…_1`, - // `…_2`, and so on. - let mut sc_indexes = HashMap::::new(); - for variant in variants.iter_mut() { - match sc_counts.get(variant.sc.as_ref()) { - Some(count) if *count > 1 => { - let sc_index = sc_indexes.entry( - variant.sc.as_ref().to_owned() - ).or_insert(0); - *sc_index += 1; - - variant.sc = Ident::new(format!("{}_{}", variant.sc, *sc_index)); - variant.pc = Ident::new(format!("{}_{}", variant.pc, *sc_index)); - } - _ => {} - } - } + 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 { @@ -679,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 @@ -706,6 +684,13 @@ pub fn fields( ) .collect::>>()?; + 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; } diff --git a/src/util.rs b/src/util.rs index 6868b6b1..ace2b76e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; -use std::collections::HashSet; +use std::hash::Hash; +use std::collections::{HashMap, HashSet}; use inflections::Inflect; use svd::{Access, Cluster, Register}; @@ -296,3 +297,47 @@ pub fn registers_with_uniq_names<'a, I: Iterator>(registers } }).collect() } + +fn count_occurrences<'a, K, I>(iter: I) -> HashMap +where + K: Eq + Hash, + I: Iterator, +{ + 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(entries: &mut Vec, 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::::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); + } + _ => {} + } + } +} From 5abcbaf318ffff4ebb7a74b6366a1cd69853d473 Mon Sep 17 00:00:00 2001 From: Astro Date: Sat, 12 May 2018 00:17:22 +0200 Subject: [PATCH 4/4] add santitize_underscores() to to_sanitized_upper_case/to_sanitized_pascal_case --- src/util.rs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/util.rs b/src/util.rs index ace2b76e..90a93b7a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -39,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! { @@ -111,26 +114,32 @@ impl ToSanitizedSnakeCase for str { impl ToSanitizedUpperCase for str { fn to_sanitized_upper_case(&self) -> Cow { - 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 { - 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), } } } @@ -139,6 +148,13 @@ pub fn respace(s: &str) -> String { s.split_whitespace().collect::>().join(" ") } +fn santitize_underscores(s: &str) -> String { + s.split('_') + .filter(|part| part.len() > 0) + .collect::>() + .join("_") +} + pub fn name_of(register: &Register) -> Cow { match *register { Register::Single(ref info) => Cow::from(&*info.name),