@@ -20,10 +20,20 @@ use crate::bindgen::library::Library;
2020use crate :: bindgen:: writer:: { Source , SourceWriter } ;
2121use crate :: bindgen:: Bindings ;
2222
23+ fn member_to_ident ( member : & syn:: Member ) -> String {
24+ match member {
25+ syn:: Member :: Named ( ref name) => name. unraw ( ) . to_string ( ) ,
26+ syn:: Member :: Unnamed ( ref index) => format ! ( "_{}" , index. index) ,
27+ }
28+ }
29+
2330#[ derive( Debug , Clone ) ]
2431pub enum Literal {
2532 Expr ( String ) ,
26- Path ( String ) ,
33+ Path {
34+ associated_to : Option < ( Path , String ) > ,
35+ name : String ,
36+ } ,
2737 PostfixUnaryOp {
2838 op : & ' static str ,
2939 value : Box < Literal > ,
@@ -33,6 +43,10 @@ pub enum Literal {
3343 op : & ' static str ,
3444 right : Box < Literal > ,
3545 } ,
46+ FieldAccess {
47+ base : Box < Literal > ,
48+ field : String ,
49+ } ,
3650 Struct {
3751 path : Path ,
3852 export_name : String ,
@@ -58,6 +72,9 @@ impl Literal {
5872 left. replace_self_with ( self_ty) ;
5973 right. replace_self_with ( self_ty) ;
6074 }
75+ Literal :: FieldAccess { ref mut base, .. } => {
76+ base. replace_self_with ( self_ty) ;
77+ }
6178 Literal :: Struct {
6279 ref mut path,
6380 ref mut export_name,
@@ -77,35 +94,53 @@ impl Literal {
7794 ty. replace_self_with ( self_ty) ;
7895 value. replace_self_with ( self_ty) ;
7996 }
80- Literal :: Expr ( ..) | Literal :: Path ( ..) => { }
97+ Literal :: Path {
98+ ref mut associated_to,
99+ ..
100+ } => {
101+ if let Some ( ( ref mut path, ref mut export_name) ) = * associated_to {
102+ if path. replace_self_with ( self_ty) {
103+ * export_name = self_ty. name ( ) . to_owned ( ) ;
104+ }
105+ }
106+ }
107+ Literal :: Expr ( ..) => { }
81108 }
82109 }
83110
84111 fn is_valid ( & self , bindings : & Bindings ) -> bool {
85112 match * self {
86113 Literal :: Expr ( ..) => true ,
87- Literal :: Path ( ..) => true ,
114+ Literal :: Path {
115+ ref associated_to, ..
116+ } => {
117+ if let Some ( ( ref path, _export_name) ) = associated_to {
118+ return bindings. struct_exists ( path) ;
119+ }
120+ true
121+ }
88122 Literal :: PostfixUnaryOp { ref value, .. } => value. is_valid ( bindings) ,
89123 Literal :: BinOp {
90124 ref left,
91125 ref right,
92126 ..
93127 } => left. is_valid ( bindings) && right. is_valid ( bindings) ,
128+ Literal :: FieldAccess { ref base, .. } => base. is_valid ( bindings) ,
94129 Literal :: Struct { ref path, .. } => bindings. struct_exists ( path) ,
95130 Literal :: Cast { ref value, .. } => value. is_valid ( bindings) ,
96131 }
97132 }
98133
99134 pub fn uses_only_primitive_types ( & self ) -> bool {
100135 match self {
101- Literal :: Expr ( ..) => true ,
102- Literal :: Path ( ..) => true ,
136+ Literal :: Expr ( ..) | Literal :: Path { .. } => true ,
103137 Literal :: PostfixUnaryOp { ref value, .. } => value. uses_only_primitive_types ( ) ,
104138 Literal :: BinOp {
105139 ref left,
106140 ref right,
107141 ..
108142 } => left. uses_only_primitive_types ( ) & right. uses_only_primitive_types ( ) ,
143+ Literal :: FieldAccess { ref base, .. } => base. uses_only_primitive_types ( ) ,
109144 Literal :: Struct { .. } => false ,
110145 Literal :: Cast { ref value, ref ty } => {
111146 value. uses_only_primitive_types ( ) && ty. is_primitive_or_ptr_primitive ( )
@@ -127,8 +162,18 @@ impl Literal {
127162 lit. rename_for_config ( config) ;
128163 }
129164 }
130- Literal :: Path ( ref mut name) => {
131- config. export . rename ( name) ;
165+ Literal :: FieldAccess { ref mut base, .. } => {
166+ base. rename_for_config ( config) ;
167+ }
168+ Literal :: Path {
169+ ref mut associated_to,
170+ ref mut name,
171+ } => {
172+ if let Some ( ( _path, ref mut export_name) ) = associated_to {
173+ config. export . rename ( export_name) ;
174+ } else {
175+ config. export . rename ( name) ;
176+ }
132177 }
133178 Literal :: PostfixUnaryOp { ref mut value, .. } => {
134179 value. rename_for_config ( config) ;
@@ -220,6 +265,15 @@ impl Literal {
220265 }
221266 }
222267
268+ syn:: Expr :: Field ( syn:: ExprField {
269+ ref base,
270+ ref member,
271+ ..
272+ } ) => Ok ( Literal :: FieldAccess {
273+ base : Box :: new ( Literal :: load ( base) ?) ,
274+ field : member_to_ident ( member) ,
275+ } ) ,
276+
223277 syn:: Expr :: Struct ( syn:: ExprStruct {
224278 ref path,
225279 ref fields,
@@ -228,10 +282,7 @@ impl Literal {
228282 let struct_name = path. segments [ 0 ] . ident . unraw ( ) . to_string ( ) ;
229283 let mut field_map = HashMap :: < String , Literal > :: default ( ) ;
230284 for field in fields {
231- let ident = match field. member {
232- syn:: Member :: Named ( ref name) => name. unraw ( ) . to_string ( ) ,
233- syn:: Member :: Unnamed ( ref index) => format ! ( "_{}" , index. index) ,
234- } ;
285+ let ident = member_to_ident ( & field. member ) ;
235286 let key = ident. to_string ( ) ;
236287 let value = Literal :: load ( & field. expr ) ?;
237288 field_map. insert ( key, value) ;
@@ -257,16 +308,23 @@ impl Literal {
257308 } ,
258309
259310 // Match identifiers, like `5 << SHIFT`
260- syn:: Expr :: Path ( syn:: ExprPath {
261- path : syn:: Path { ref segments, .. } ,
262- ..
263- } ) => {
264- // Handle only the simplest identifiers and error for anything else.
265- if segments. len ( ) == 1 {
266- Ok ( Literal :: Path ( format ! ( "{}" , segments. last( ) . unwrap( ) . ident) ) )
267- } else {
268- Err ( format ! ( "Unsupported path expression. {:?}" , * segments) )
269- }
311+ syn:: Expr :: Path ( syn:: ExprPath { ref path, .. } ) => {
312+ // Handle only the simplest identifiers and Associated::IDENT
313+ // kind of syntax.
314+ Ok ( match path. segments . len ( ) {
315+ 1 => Literal :: Path {
316+ associated_to : None ,
317+ name : path. segments [ 0 ] . ident . to_string ( ) ,
318+ } ,
319+ 2 => {
320+ let struct_name = path. segments [ 0 ] . ident . to_string ( ) ;
321+ Literal :: Path {
322+ associated_to : Some ( ( Path :: new ( & struct_name) , struct_name) ) ,
323+ name : path. segments [ 1 ] . ident . to_string ( ) ,
324+ }
325+ }
326+ _ => return Err ( format ! ( "Unsupported path expression. {:?}" , path) ) ,
327+ } )
270328 }
271329
272330 syn:: Expr :: Paren ( syn:: ExprParen { ref expr, .. } ) => Self :: load ( expr) ,
@@ -295,7 +353,33 @@ impl Literal {
295353 ( "false" , Language :: Cython ) => write ! ( out, "False" ) ,
296354 ( v, _) => write ! ( out, "{}" , v) ,
297355 } ,
298- Literal :: Path ( v) => write ! ( out, "{}" , v) ,
356+ Literal :: Path {
357+ ref associated_to,
358+ ref name,
359+ } => {
360+ if let Some ( ( _, ref export_name) ) = associated_to {
361+ let path_separator = match config. language {
362+ Language :: Cython | Language :: C => "_" ,
363+ Language :: Cxx => {
364+ if config. structure . associated_constants_in_body {
365+ "::"
366+ } else {
367+ "_"
368+ }
369+ }
370+ } ;
371+ write ! ( out, "{}{}" , export_name, path_separator)
372+ }
373+ write ! ( out, "{}" , name)
374+ }
375+ Literal :: FieldAccess {
376+ ref base,
377+ ref field,
378+ } => {
379+ write ! ( out, "(" ) ;
380+ base. write ( config, out) ;
381+ write ! ( out, ").{}" , field) ;
382+ }
299383 Literal :: PostfixUnaryOp { op, ref value } => {
300384 write ! ( out, "{}" , op) ;
301385 value. write ( config, out) ;
0 commit comments