@@ -118,6 +118,8 @@ struct Region {
118
118
fields : Vec < RegisterBlockField > ,
119
119
offset : u32 ,
120
120
end : u32 ,
121
+ /// This is only used for regions with `fields.len() > 1`
122
+ pub ident : Option < String > ,
121
123
}
122
124
123
125
impl Region {
@@ -146,6 +148,77 @@ impl Region {
146
148
Some ( idents[ 0 ] . to_owned ( ) )
147
149
}
148
150
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
+ }
149
222
/// Return a description of this region
150
223
fn description ( & self ) -> String {
151
224
let mut result = String :: new ( ) ;
@@ -194,7 +267,8 @@ impl FieldRegions {
194
267
let mut new_region = Region {
195
268
fields : vec ! [ field. clone( ) ] ,
196
269
offset : field. offset ,
197
- end : field. offset + field. size / BITS_PER_BYTE
270
+ end : field. offset + field. size / BITS_PER_BYTE ,
271
+ ident : None ,
198
272
} ;
199
273
200
274
// Locate existing region(s) that we intersect with and
@@ -248,6 +322,26 @@ impl FieldRegions {
248
322
pub fn is_union ( & self ) -> bool {
249
323
self . regions . len ( ) == 1 && self . regions [ 0 ] . fields . len ( ) > 1
250
324
}
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
+ }
251
345
}
252
346
253
347
fn register_or_cluster_block (
@@ -268,7 +362,8 @@ fn register_or_cluster_block(
268
362
}
269
363
270
364
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 ( ) ?;
272
367
// The end of the region from the prior iteration of the loop
273
368
let mut last_end = None ;
274
369
@@ -314,7 +409,7 @@ fn register_or_cluster_block(
314
409
}
315
410
316
411
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 ( ) {
318
413
Some ( prefix) => {
319
414
( Ident :: new ( format ! ( "{}Union" , prefix. to_sanitized_pascal_case( ) ) ) ,
320
415
Ident :: new ( prefix) )
0 commit comments