Skip to content

Commit e1f96a4

Browse files
committed
Revise union naming scheme
Rather than trying to compute a smart name and hoping that there is no conflict, this commit switches to a simpler scheme: we now take the shortest identifier from the components of a union and take the one that sorts earliest as the name for the union in its containing RegisterBlock. So long as the names of the registers in that block don't have collisions, we are guaranteed not to collide.
1 parent 0ed4dec commit e1f96a4

File tree

1 file changed

+28
-39
lines changed

1 file changed

+28
-39
lines changed

src/generate/peripheral.rs

Lines changed: 28 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::borrow::Cow;
2+
use std::cmp::Ordering;
23

34
use either::Either;
45
use quote::{ToTokens, Tokens};
@@ -120,43 +121,29 @@ struct Region {
120121
}
121122

122123
impl Region {
123-
/// Find the longest common prefix of the identifier names
124-
/// for the fields in this region, if any.
125-
fn common_prefix(&self) -> Option<String> {
126-
let mut char_vecs = Vec::new();
127-
let mut min_len = usize::max_value();
128-
129-
for f in &self.fields {
130-
match f.field.ident {
131-
None => return None,
132-
Some(ref ident) => {
133-
let chars : Vec<char> = ident.as_ref().chars().collect();
134-
min_len = min_len.min(chars.len());
135-
char_vecs.push(chars);
124+
fn shortest_ident(&self) -> Option<String> {
125+
let mut idents: Vec<_> = self.fields
126+
.iter()
127+
.filter_map(|f| {
128+
match f.field.ident {
129+
None => None,
130+
Some(ref ident) => {
131+
Some(ident.as_ref())
132+
}
136133
}
137-
}
134+
})
135+
.collect();
136+
if idents.is_empty() {
137+
return None;
138138
}
139-
140-
let mut result = String::new();
141-
142-
for i in 0..min_len {
143-
let c = char_vecs[0][i];
144-
for v in &char_vecs {
145-
if v[i] != c {
146-
break;
147-
}
139+
idents.sort_by(|a, b| {
140+
// Sort by length and then content
141+
match a.len().cmp(&b.len()) {
142+
Ordering::Equal => a.cmp(b),
143+
cmp @ _ => cmp
148144
}
149-
150-
// This character position is the same across
151-
// all variants, so emit it into the result
152-
result.push(c);
153-
}
154-
155-
if result.is_empty() {
156-
None
157-
} else {
158-
Some(result)
159-
}
145+
});
146+
Some(idents[0].to_owned())
160147
}
161148

162149
/// Return a description of this region
@@ -298,6 +285,8 @@ fn register_or_cluster_block(
298285

299286
for reg_block_field in &region.fields {
300287
if reg_block_field.offset != region.offset {
288+
// TODO: need to emit padding for this case.
289+
// Happens for freescale_mkl43z4
301290
eprintln!("WARNING: field {:?} has different offset {} than its union container {}",
302291
reg_block_field.field.ident,
303292
reg_block_field.offset,
@@ -319,15 +308,15 @@ fn register_or_cluster_block(
319308
}
320309

321310
if region.fields.len() > 1 && !block_is_union {
322-
let (type_name, name) = match region.common_prefix() {
311+
let (type_name, name) = match region.shortest_ident() {
323312
Some(prefix) => {
324-
(Ident::new(format!("{}_union", prefix)),
313+
(Ident::new(format!("{}Union", prefix.to_sanitized_upper_case())),
325314
Ident::new(prefix))
326315
}
327-
// If we can't find a common prefix for the name, fall back to the
328-
// region index as a unique-within-this-block identifier counter.
316+
// If we can't find a name, fall back to theregion index as a
317+
// unique-within-this-block identifier counter.
329318
None => {
330-
let ident = Ident::new(format!("u{}", i));
319+
let ident = Ident::new(format!("U{}", i));
331320
(ident.clone(), ident)
332321
}
333322
};

0 commit comments

Comments
 (0)