Skip to content

Commit 1d97de8

Browse files
committed
constant: Add support for associated constant expressions.
These are useful for bitflags.
1 parent 20ddfff commit 1d97de8

21 files changed

+171
-24
lines changed

src/bindgen/ir/constant.rs

Lines changed: 106 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,20 @@ use crate::bindgen::library::Library;
2020
use crate::bindgen::writer::{Source, SourceWriter};
2121
use 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)]
2431
pub 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);

tests/expectations/associated_in_body.both.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ typedef struct StyleAlignFlags {
2727
* 'end'
2828
*/
2929
#define StyleAlignFlags_END (StyleAlignFlags){ .bits = (uint8_t)(1 << 2) }
30+
#define StyleAlignFlags_ALIAS (StyleAlignFlags){ .bits = (uint8_t)(StyleAlignFlags_END).bits }
3031
/**
3132
* 'flex-start'
3233
*/
3334
#define StyleAlignFlags_FLEX_START (StyleAlignFlags){ .bits = (uint8_t)(1 << 3) }
35+
#define StyleAlignFlags_MIXED (StyleAlignFlags){ .bits = (uint8_t)(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
36+
#define StyleAlignFlags_MIXED_SELF (StyleAlignFlags){ .bits = (uint8_t)(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
3437

3538
void root(struct StyleAlignFlags flags);

tests/expectations/associated_in_body.both.compat.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ typedef struct StyleAlignFlags {
2727
* 'end'
2828
*/
2929
#define StyleAlignFlags_END (StyleAlignFlags){ .bits = (uint8_t)(1 << 2) }
30+
#define StyleAlignFlags_ALIAS (StyleAlignFlags){ .bits = (uint8_t)(StyleAlignFlags_END).bits }
3031
/**
3132
* 'flex-start'
3233
*/
3334
#define StyleAlignFlags_FLEX_START (StyleAlignFlags){ .bits = (uint8_t)(1 << 3) }
35+
#define StyleAlignFlags_MIXED (StyleAlignFlags){ .bits = (uint8_t)(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
36+
#define StyleAlignFlags_MIXED_SELF (StyleAlignFlags){ .bits = (uint8_t)(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
3437

3538
#ifdef __cplusplus
3639
extern "C" {

tests/expectations/associated_in_body.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ typedef struct {
2727
* 'end'
2828
*/
2929
#define StyleAlignFlags_END (StyleAlignFlags){ .bits = (uint8_t)(1 << 2) }
30+
#define StyleAlignFlags_ALIAS (StyleAlignFlags){ .bits = (uint8_t)(StyleAlignFlags_END).bits }
3031
/**
3132
* 'flex-start'
3233
*/
3334
#define StyleAlignFlags_FLEX_START (StyleAlignFlags){ .bits = (uint8_t)(1 << 3) }
35+
#define StyleAlignFlags_MIXED (StyleAlignFlags){ .bits = (uint8_t)(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
36+
#define StyleAlignFlags_MIXED_SELF (StyleAlignFlags){ .bits = (uint8_t)(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
3437

3538
void root(StyleAlignFlags flags);

tests/expectations/associated_in_body.compat.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ typedef struct {
2727
* 'end'
2828
*/
2929
#define StyleAlignFlags_END (StyleAlignFlags){ .bits = (uint8_t)(1 << 2) }
30+
#define StyleAlignFlags_ALIAS (StyleAlignFlags){ .bits = (uint8_t)(StyleAlignFlags_END).bits }
3031
/**
3132
* 'flex-start'
3233
*/
3334
#define StyleAlignFlags_FLEX_START (StyleAlignFlags){ .bits = (uint8_t)(1 << 3) }
35+
#define StyleAlignFlags_MIXED (StyleAlignFlags){ .bits = (uint8_t)(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
36+
#define StyleAlignFlags_MIXED_SELF (StyleAlignFlags){ .bits = (uint8_t)(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
3437

3538
#ifdef __cplusplus
3639
extern "C" {

tests/expectations/associated_in_body.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ struct StyleAlignFlags {
4141
static const StyleAlignFlags NORMAL;
4242
static const StyleAlignFlags START;
4343
static const StyleAlignFlags END;
44+
static const StyleAlignFlags ALIAS;
4445
static const StyleAlignFlags FLEX_START;
46+
static const StyleAlignFlags MIXED;
47+
static const StyleAlignFlags MIXED_SELF;
4548
};
4649
/// 'auto'
4750
inline const StyleAlignFlags StyleAlignFlags::AUTO = StyleAlignFlags{ /* .bits = */ (uint8_t)0 };
@@ -51,8 +54,11 @@ inline const StyleAlignFlags StyleAlignFlags::NORMAL = StyleAlignFlags{ /* .bits
5154
inline const StyleAlignFlags StyleAlignFlags::START = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 1) };
5255
/// 'end'
5356
inline const StyleAlignFlags StyleAlignFlags::END = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 2) };
57+
inline const StyleAlignFlags StyleAlignFlags::ALIAS = StyleAlignFlags{ /* .bits = */ (uint8_t)(StyleAlignFlags::END).bits };
5458
/// 'flex-start'
5559
inline const StyleAlignFlags StyleAlignFlags::FLEX_START = StyleAlignFlags{ /* .bits = */ (uint8_t)(1 << 3) };
60+
inline const StyleAlignFlags StyleAlignFlags::MIXED = StyleAlignFlags{ /* .bits = */ (uint8_t)(((1 << 4) | (StyleAlignFlags::FLEX_START).bits) | (StyleAlignFlags::END).bits) };
61+
inline const StyleAlignFlags StyleAlignFlags::MIXED_SELF = StyleAlignFlags{ /* .bits = */ (uint8_t)(((1 << 5) | (StyleAlignFlags::FLEX_START).bits) | (StyleAlignFlags::END).bits) };
5662

5763
extern "C" {
5864

tests/expectations/associated_in_body.pyx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ cdef extern from *:
1919
const StyleAlignFlags StyleAlignFlags_START # = <StyleAlignFlags>{ <uint8_t>(1 << 1) }
2020
# 'end'
2121
const StyleAlignFlags StyleAlignFlags_END # = <StyleAlignFlags>{ <uint8_t>(1 << 2) }
22+
const StyleAlignFlags StyleAlignFlags_ALIAS # = <StyleAlignFlags>{ <uint8_t>(StyleAlignFlags_END).bits }
2223
# 'flex-start'
2324
const StyleAlignFlags StyleAlignFlags_FLEX_START # = <StyleAlignFlags>{ <uint8_t>(1 << 3) }
25+
const StyleAlignFlags StyleAlignFlags_MIXED # = <StyleAlignFlags>{ <uint8_t>(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
26+
const StyleAlignFlags StyleAlignFlags_MIXED_SELF # = <StyleAlignFlags>{ <uint8_t>(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
2427

2528
void root(StyleAlignFlags flags);

tests/expectations/associated_in_body.tag.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ struct StyleAlignFlags {
2727
* 'end'
2828
*/
2929
#define StyleAlignFlags_END (StyleAlignFlags){ .bits = (uint8_t)(1 << 2) }
30+
#define StyleAlignFlags_ALIAS (StyleAlignFlags){ .bits = (uint8_t)(StyleAlignFlags_END).bits }
3031
/**
3132
* 'flex-start'
3233
*/
3334
#define StyleAlignFlags_FLEX_START (StyleAlignFlags){ .bits = (uint8_t)(1 << 3) }
35+
#define StyleAlignFlags_MIXED (StyleAlignFlags){ .bits = (uint8_t)(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
36+
#define StyleAlignFlags_MIXED_SELF (StyleAlignFlags){ .bits = (uint8_t)(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
3437

3538
void root(struct StyleAlignFlags flags);

tests/expectations/associated_in_body.tag.compat.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ struct StyleAlignFlags {
2727
* 'end'
2828
*/
2929
#define StyleAlignFlags_END (StyleAlignFlags){ .bits = (uint8_t)(1 << 2) }
30+
#define StyleAlignFlags_ALIAS (StyleAlignFlags){ .bits = (uint8_t)(StyleAlignFlags_END).bits }
3031
/**
3132
* 'flex-start'
3233
*/
3334
#define StyleAlignFlags_FLEX_START (StyleAlignFlags){ .bits = (uint8_t)(1 << 3) }
35+
#define StyleAlignFlags_MIXED (StyleAlignFlags){ .bits = (uint8_t)(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
36+
#define StyleAlignFlags_MIXED_SELF (StyleAlignFlags){ .bits = (uint8_t)(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
3437

3538
#ifdef __cplusplus
3639
extern "C" {

tests/expectations/associated_in_body.tag.pyx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ cdef extern from *:
1919
const StyleAlignFlags StyleAlignFlags_START # = <StyleAlignFlags>{ <uint8_t>(1 << 1) }
2020
# 'end'
2121
const StyleAlignFlags StyleAlignFlags_END # = <StyleAlignFlags>{ <uint8_t>(1 << 2) }
22+
const StyleAlignFlags StyleAlignFlags_ALIAS # = <StyleAlignFlags>{ <uint8_t>(StyleAlignFlags_END).bits }
2223
# 'flex-start'
2324
const StyleAlignFlags StyleAlignFlags_FLEX_START # = <StyleAlignFlags>{ <uint8_t>(1 << 3) }
25+
const StyleAlignFlags StyleAlignFlags_MIXED # = <StyleAlignFlags>{ <uint8_t>(((1 << 4) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
26+
const StyleAlignFlags StyleAlignFlags_MIXED_SELF # = <StyleAlignFlags>{ <uint8_t>(((1 << 5) | (StyleAlignFlags_FLEX_START).bits) | (StyleAlignFlags_END).bits) }
2427

2528
void root(StyleAlignFlags flags);

0 commit comments

Comments
 (0)