Skip to content

Commit 3326621

Browse files
committed
Generate macro string constants.
Signed-off-by: Emilio Cobos Álvarez <ecoal95@gmail.com>
1 parent 9fcee17 commit 3326621

File tree

5 files changed

+82
-16
lines changed

5 files changed

+82
-16
lines changed

src/codegen/helpers.rs

+18
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,22 @@ pub mod ast_ty {
132132
expr.int(val)
133133
}
134134
}
135+
136+
pub fn byte_array_expr(bytes: &[u8]) -> P<ast::Expr> {
137+
let mut vec = Vec::with_capacity(bytes.len() + 1);
138+
for byte in bytes {
139+
vec.push(int_expr(*byte as i64));
140+
}
141+
vec.push(int_expr(0));
142+
143+
let kind = ast::ExprKind::Vec(vec);
144+
145+
aster::AstBuilder::new().expr().build_expr_kind(kind)
146+
}
147+
148+
pub fn cstr_expr(mut string: String) -> P<ast::Expr> {
149+
string.push('\0');
150+
aster::AstBuilder::new().expr().build_lit(
151+
aster::AstBuilder::new().lit().byte_str(string))
152+
}
135153
}

src/codegen/mod.rs

+30-4
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ impl CodeGenerator for Var {
299299
ctx: &BindgenContext,
300300
result: &mut CodegenResult,
301301
item: &Item) {
302+
use ir::var::VarType;
303+
302304
let canonical_name = item.canonical_name(ctx);
303305

304306
if result.seen_var(&canonical_name) {
@@ -313,10 +315,34 @@ impl CodeGenerator for Var {
313315
.item()
314316
.pub_()
315317
.const_(canonical_name)
316-
.expr()
317-
.build(helpers::ast_ty::int_expr(val))
318-
.build(ty);
319-
result.push(const_item)
318+
.expr();
319+
let item = match *val {
320+
VarType::Int(val) => {
321+
const_item
322+
.build(helpers::ast_ty::int_expr(val))
323+
.build(ty)
324+
}
325+
VarType::String(ref bytes) => {
326+
match String::from_utf8(bytes.clone()) {
327+
Ok(string) => {
328+
const_item
329+
.build(helpers::ast_ty::cstr_expr(string))
330+
.build(ty)
331+
}
332+
Err(..) => {
333+
// Account the trailing zero.
334+
let len = bytes.len() + 1;
335+
let ty = quote_ty!(ctx.ext_cx(), [u8; $len]);
336+
337+
const_item
338+
.build(helpers::ast_ty::byte_array_expr(bytes))
339+
.build(ty)
340+
}
341+
}
342+
}
343+
};
344+
345+
result.push(item);
320346
} else {
321347
let mut attrs = vec![];
322348
if let Some(mangled) = self.mangled_name() {

src/ir/var.rs

+23-12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ use super::int::IntKind;
1010
use super::item::{Item, ItemId};
1111
use super::ty::TypeKind;
1212

13+
#[derive(Debug)]
14+
pub enum VarType {
15+
Int(i64),
16+
String(Vec<u8>),
17+
}
18+
1319
/// A `Var` is our intermediate representation of a variable.
1420
#[derive(Debug)]
1521
pub struct Var {
@@ -19,9 +25,8 @@ pub struct Var {
1925
mangled_name: Option<String>,
2026
/// The type of the variable.
2127
ty: ItemId,
22-
/// TODO: support non-integer constants?
23-
/// The integer value of the variable.
24-
val: Option<i64>,
28+
/// The value of the variable, that needs to be suitable for `ty`.
29+
val: Option<VarType>,
2530
/// Whether this variable is const.
2631
is_const: bool,
2732
}
@@ -31,7 +36,7 @@ impl Var {
3136
pub fn new(name: String,
3237
mangled: Option<String>,
3338
ty: ItemId,
34-
val: Option<i64>,
39+
val: Option<VarType>,
3540
is_const: bool)
3641
-> Var {
3742
assert!(!name.is_empty());
@@ -50,8 +55,8 @@ impl Var {
5055
}
5156

5257
/// The value of this constant variable, if any.
53-
pub fn val(&self) -> Option<i64> {
54-
self.val
58+
pub fn val(&self) -> Option<&VarType> {
59+
self.val.as_ref()
5560
}
5661

5762
/// Get this variable's type.
@@ -105,13 +110,18 @@ impl ClangSubItemParser for Var {
105110
// enforce utf8 there, so we should have already panicked at
106111
// this point.
107112
let name = String::from_utf8(id).unwrap();
108-
let (int_kind, val) = match value {
113+
let (type_kind, val) = match value {
109114
// TODO(emilio): Handle the non-invalid ones!
110115
EvalResult::Float(..) |
111116
EvalResult::Char(..) |
112-
EvalResult::Str(..) |
113117
EvalResult::Invalid => return Err(ParseError::Continue),
114118

119+
EvalResult::Str(val) => {
120+
let char_ty =
121+
Item::builtin_type(TypeKind::Int(IntKind::U8),
122+
true, ctx);
123+
(TypeKind::Pointer(char_ty), VarType::String(val))
124+
}
115125
EvalResult::Int(Wrapping(value)) => {
116126
let kind = ctx.options()
117127
.type_chooser
@@ -131,11 +141,11 @@ impl ClangSubItemParser for Var {
131141
}
132142
});
133143

134-
(kind, value)
144+
(TypeKind::Int(kind), VarType::Int(value))
135145
}
136146
};
137147

138-
let ty = Item::builtin_type(TypeKind::Int(int_kind), true, ctx);
148+
let ty = Item::builtin_type(type_kind, true, ctx);
139149

140150
Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true),
141151
Some(cursor)))
@@ -159,6 +169,8 @@ impl ClangSubItemParser for Var {
159169
// tests/headers/inner_const.hpp
160170
//
161171
// That's fine because in that case we know it's not a literal.
172+
//
173+
// TODO: Strings, stuff like that.
162174
let is_integer = ctx.safe_resolve_type(ty)
163175
.and_then(|t| t.safe_canonical_type(ctx))
164176
.map(|t| t.is_integer())
@@ -171,7 +183,7 @@ impl ClangSubItemParser for Var {
171183
.or_else(|| {
172184
let tu = ctx.translation_unit();
173185
get_integer_literal_from_cursor(&cursor, tu)
174-
})
186+
}).map(VarType::Int)
175187
} else {
176188
None
177189
};
@@ -181,7 +193,6 @@ impl ClangSubItemParser for Var {
181193

182194
let var = Var::new(name, mangling, ty, value, is_const);
183195
Ok(ParseResult::New(var, Some(cursor)))
184-
185196
}
186197
_ => {
187198
/* TODO */

tests/expectations/tests/macro_str.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub const foo: *const u8 = b"bar\x00";
8+
pub const BOO: [u8; 5usize] = [240, 40, 140, 40, 0];

tests/headers/macro_str.h

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#define foo "bar"
2+
3+
#define BOO "\xf0\x28\x8c\x28"

0 commit comments

Comments
 (0)