@@ -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
123125impl 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
253347fn 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