Skip to content

Commit 7690adf

Browse files
Emilgardiswez
authored andcommitted
Updated name resolving for unions
1 parent 5ccff19 commit 7690adf

File tree

1 file changed

+98
-3
lines changed

1 file changed

+98
-3
lines changed

src/generate/peripheral.rs

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ struct Region {
118118
fields: Vec<RegisterBlockField>,
119119
offset: u32,
120120
end: u32,
121+
/// This is only used for regions with `fields.len() > 1`
122+
pub ident: Option<String>,
121123
}
122124

123125
impl Region {
@@ -146,6 +148,77 @@ impl Region {
146148
Some(idents[0].to_owned())
147149
}
148150

151+
fn common_ident(&self) -> Option<String> {
152+
// https://stackoverflow.com/a/40296745/4284367
153+
fn split_keep(text: &str) -> Vec<&str> {
154+
let mut result = Vec::new();
155+
let mut last = 0;
156+
for (index, matched) in text.match_indices(|c: char| c.is_numeric() || !c.is_alphabetic()) {
157+
if last != index {
158+
result.push(&text[last..index]);
159+
}
160+
result.push(matched);
161+
last = index + matched.len();
162+
}
163+
if last < text.len() {
164+
result.push(&text[last..]);
165+
}
166+
result
167+
}
168+
169+
let idents: Vec<_> = self.fields
170+
.iter()
171+
.filter_map(|f| {
172+
match f.field.ident {
173+
None => None,
174+
Some(ref ident) => {
175+
Some(ident.as_ref())
176+
}
177+
}
178+
})
179+
.collect();
180+
181+
if idents.is_empty() {
182+
return None;
183+
}
184+
185+
let x: Vec<_> = idents
186+
.iter()
187+
.map(|i| split_keep(i))
188+
.collect();
189+
let mut index = 0;
190+
let first = x.get(0).unwrap();
191+
// Get first elem, check against all other, break on mismatch
192+
'outer: while index < first.len() {
193+
for ident_match in x.iter().skip(1) {
194+
if let Some(match_) = ident_match.get(index) {
195+
if match_ != first.get(index).unwrap() {
196+
break 'outer;
197+
}
198+
} else {
199+
break 'outer;
200+
}
201+
}
202+
index += 1;
203+
}
204+
if index <= 1 {
205+
None
206+
} else {
207+
if first.get(index).is_some() && first.get(index).unwrap().chars().all(|c| c.is_numeric()) {
208+
Some(first.iter().take(index).cloned().collect())
209+
} else {
210+
Some(first.iter().take(index - 1).cloned().collect())
211+
}
212+
}
213+
}
214+
215+
fn compute_ident(&self) -> Option<String>{
216+
if let Some(ident) = self.common_ident() {
217+
Some(ident)
218+
} else {
219+
self.shortest_ident()
220+
}
221+
}
149222
/// Return a description of this region
150223
fn description(&self) -> String {
151224
let mut result = String::new();
@@ -194,7 +267,8 @@ impl FieldRegions {
194267
let mut new_region = Region {
195268
fields: vec![field.clone()],
196269
offset: field.offset,
197-
end: field.offset + field.size / BITS_PER_BYTE
270+
end: field.offset + field.size / BITS_PER_BYTE,
271+
ident: None,
198272
};
199273

200274
// Locate existing region(s) that we intersect with and
@@ -248,6 +322,26 @@ impl FieldRegions {
248322
pub fn is_union(&self) -> bool {
249323
self.regions.len() == 1 && self.regions[0].fields.len() > 1
250324
}
325+
326+
/// Resolves type name conflicts
327+
pub fn resolve_idents(&mut self) -> Result<()> {
328+
let idents: Vec<_> = {
329+
self.regions.iter_mut()
330+
.filter(|r| r.fields.len() > 1)
331+
.map(|r| {
332+
r.ident = r.compute_ident();
333+
r.ident.clone()
334+
}).collect()
335+
};
336+
self.regions.iter_mut()
337+
.filter(|r| r.ident.is_some())
338+
.filter(|r| r.fields.len() > 1 && (idents.iter().filter(|ident| **ident == r.ident).count() > 1))
339+
.inspect(|r| eprintln!("WARNING: Found type name conflict with region {:?}, renamed to {:?}", r.ident, r.shortest_ident()))
340+
.for_each(|r| {
341+
r.ident = r.shortest_ident();
342+
});
343+
Ok(())
344+
}
251345
}
252346

253347
fn register_or_cluster_block(
@@ -268,7 +362,8 @@ fn register_or_cluster_block(
268362
}
269363

270364
let block_is_union = regions.is_union();
271-
365+
// We need to compute the idents of each register/union block first to make sure no conflicts exists.
366+
regions.resolve_idents()?;
272367
// The end of the region from the prior iteration of the loop
273368
let mut last_end = None;
274369

@@ -314,7 +409,7 @@ fn register_or_cluster_block(
314409
}
315410

316411
if region.fields.len() > 1 && !block_is_union {
317-
let (type_name, name) = match region.shortest_ident() {
412+
let (type_name, name) = match region.ident.clone() {
318413
Some(prefix) => {
319414
(Ident::new(format!("{}Union", prefix.to_sanitized_pascal_case())),
320415
Ident::new(prefix))

0 commit comments

Comments
 (0)