1 //! Intermediate representation of variables.
2
3 use callbacks::MacroParsingBehavior;
4 use super::context::{BindgenContext, TypeId};
5 use super::dot::DotAttributes;
6 use super::function::cursor_mangling;
7 use super::int::IntKind;
8 use super::item::Item;
9 use super::ty::{FloatKind, TypeKind};
10 use cexpr;
11 use clang;
12 use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
13 use std::io;
14 use std::num::Wrapping;
15
16 /// The type for a constant variable.
17 #[derive(Debug)]
18 pub enum VarType {
19 /// A boolean.
20 Bool(bool),
21 /// An integer.
22 Int(i64),
23 /// A floating point number.
24 Float(f64),
25 /// A character.
26 Char(u8),
27 /// A string, not necessarily well-formed utf-8.
28 String(Vec<u8>),
29 }
30
31 /// A `Var` is our intermediate representation of a variable.
32 #[derive(Debug)]
33 pub struct Var {
34 /// The name of the variable.
35 name: String,
36 /// The mangled name of the variable.
37 mangled_name: Option<String>,
38 /// The type of the variable.
39 ty: TypeId,
40 /// The value of the variable, that needs to be suitable for `ty`.
41 val: Option<VarType>,
42 /// Whether this variable is const.
43 is_const: bool,
44 }
45
46 impl Var {
47 /// Construct a new `Var`.
new( name: String, mangled_name: Option<String>, ty: TypeId, val: Option<VarType>, is_const: bool, ) -> Var48 pub fn new(
49 name: String,
50 mangled_name: Option<String>,
51 ty: TypeId,
52 val: Option<VarType>,
53 is_const: bool,
54 ) -> Var {
55 assert!(!name.is_empty());
56 Var {
57 name,
58 mangled_name,
59 ty,
60 val,
61 is_const,
62 }
63 }
64
65 /// Is this variable `const` qualified?
is_const(&self) -> bool66 pub fn is_const(&self) -> bool {
67 self.is_const
68 }
69
70 /// The value of this constant variable, if any.
val(&self) -> Option<&VarType>71 pub fn val(&self) -> Option<&VarType> {
72 self.val.as_ref()
73 }
74
75 /// Get this variable's type.
ty(&self) -> TypeId76 pub fn ty(&self) -> TypeId {
77 self.ty
78 }
79
80 /// Get this variable's name.
name(&self) -> &str81 pub fn name(&self) -> &str {
82 &self.name
83 }
84
85 /// Get this variable's mangled name.
mangled_name(&self) -> Option<&str>86 pub fn mangled_name(&self) -> Option<&str> {
87 self.mangled_name.as_ref().map(|n| &**n)
88 }
89 }
90
91 impl DotAttributes for Var {
dot_attributes<W>( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write,92 fn dot_attributes<W>(
93 &self,
94 _ctx: &BindgenContext,
95 out: &mut W,
96 ) -> io::Result<()>
97 where
98 W: io::Write,
99 {
100 if self.is_const {
101 writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
102 }
103
104 if let Some(ref mangled) = self.mangled_name {
105 writeln!(
106 out,
107 "<tr><td>mangled name</td><td>{}</td></tr>",
108 mangled
109 )?;
110 }
111
112 Ok(())
113 }
114 }
115
116 // TODO(emilio): we could make this more (or less) granular, I guess.
default_macro_constant_type(value: i64) -> IntKind117 fn default_macro_constant_type(value: i64) -> IntKind {
118 if value < 0 {
119 if value < i32::min_value() as i64 {
120 IntKind::I64
121 } else {
122 IntKind::I32
123 }
124 } else if value > u32::max_value() as i64 {
125 IntKind::U64
126 } else {
127 IntKind::U32
128 }
129 }
130
131 impl ClangSubItemParser for Var {
parse( cursor: clang::Cursor, ctx: &mut BindgenContext, ) -> Result<ParseResult<Self>, ParseError>132 fn parse(
133 cursor: clang::Cursor,
134 ctx: &mut BindgenContext,
135 ) -> Result<ParseResult<Self>, ParseError> {
136 use clang_sys::*;
137 use cexpr::expr::EvalResult;
138 use cexpr::literal::CChar;
139 match cursor.kind() {
140 CXCursor_MacroDefinition => {
141 if let Some(callbacks) = ctx.parse_callbacks() {
142 match callbacks.will_parse_macro(&cursor.spelling()) {
143 MacroParsingBehavior::Ignore => {
144 return Err(ParseError::Continue);
145 }
146 MacroParsingBehavior::Default => {}
147 }
148 }
149
150 let value = parse_macro(ctx, &cursor);
151
152 let (id, value) = match value {
153 Some(v) => v,
154 None => return Err(ParseError::Continue),
155 };
156
157 assert!(!id.is_empty(), "Empty macro name?");
158
159 let previously_defined = ctx.parsed_macro(&id);
160
161 // NB: It's important to "note" the macro even if the result is
162 // not an integer, otherwise we might loose other kind of
163 // derived macros.
164 ctx.note_parsed_macro(id.clone(), value.clone());
165
166 if previously_defined {
167 let name = String::from_utf8(id).unwrap();
168 warn!("Duplicated macro definition: {}", name);
169 return Err(ParseError::Continue);
170 }
171
172 // NOTE: Unwrapping, here and above, is safe, because the
173 // identifier of a token comes straight from clang, and we
174 // enforce utf8 there, so we should have already panicked at
175 // this point.
176 let name = String::from_utf8(id).unwrap();
177 let (type_kind, val) = match value {
178 EvalResult::Invalid => return Err(ParseError::Continue),
179 EvalResult::Float(f) => {
180 (TypeKind::Float(FloatKind::Double), VarType::Float(f))
181 }
182 EvalResult::Char(c) => {
183 let c = match c {
184 CChar::Char(c) => {
185 assert_eq!(c.len_utf8(), 1);
186 c as u8
187 }
188 CChar::Raw(c) => {
189 assert!(c <= ::std::u8::MAX as u64);
190 c as u8
191 }
192 };
193
194 (TypeKind::Int(IntKind::U8), VarType::Char(c))
195 }
196 EvalResult::Str(val) => {
197 let char_ty = Item::builtin_type(
198 TypeKind::Int(IntKind::U8),
199 true,
200 ctx,
201 );
202 if let Some(callbacks) = ctx.parse_callbacks() {
203 callbacks.str_macro(&name, &val);
204 }
205 (TypeKind::Pointer(char_ty), VarType::String(val))
206 }
207 EvalResult::Int(Wrapping(value)) => {
208 let kind = ctx.parse_callbacks()
209 .and_then(|c| c.int_macro(&name, value))
210 .unwrap_or_else(|| default_macro_constant_type(value));
211
212 (TypeKind::Int(kind), VarType::Int(value))
213 }
214 };
215
216 let ty = Item::builtin_type(type_kind, true, ctx);
217
218 Ok(ParseResult::New(
219 Var::new(name, None, ty, Some(val), true),
220 Some(cursor),
221 ))
222 }
223 CXCursor_VarDecl => {
224 let name = cursor.spelling();
225 if name.is_empty() {
226 warn!("Empty constant name?");
227 return Err(ParseError::Continue);
228 }
229
230 let ty = cursor.cur_type();
231
232 // XXX this is redundant, remove!
233 let is_const = ty.is_const();
234
235 let ty = match Item::from_ty(&ty, cursor, None, ctx) {
236 Ok(ty) => ty,
237 Err(e) => {
238 assert_eq!(
239 ty.kind(),
240 CXType_Auto,
241 "Couldn't resolve constant type, and it \
242 wasn't an nondeductible auto type!"
243 );
244 return Err(e);
245 }
246 };
247
248 // Note: Ty might not be totally resolved yet, see
249 // tests/headers/inner_const.hpp
250 //
251 // That's fine because in that case we know it's not a literal.
252 let canonical_ty = ctx.safe_resolve_type(ty).and_then(|t| {
253 t.safe_canonical_type(ctx)
254 });
255
256 let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
257 let is_float = canonical_ty.map_or(false, |t| t.is_float());
258
259 // TODO: We could handle `char` more gracefully.
260 // TODO: Strings, though the lookup is a bit more hard (we need
261 // to look at the canonical type of the pointee too, and check
262 // is char, u8, or i8 I guess).
263 let value = if is_integer {
264 let kind = match *canonical_ty.unwrap().kind() {
265 TypeKind::Int(kind) => kind,
266 _ => unreachable!(),
267 };
268
269 let mut val = cursor
270 .evaluate()
271 .and_then(|v| v.as_int());
272 if val.is_none() || !kind.signedness_matches(val.unwrap()) {
273 let tu = ctx.translation_unit();
274 val = get_integer_literal_from_cursor(&cursor, tu);
275 }
276
277 val.map(|val| if kind == IntKind::Bool {
278 VarType::Bool(val != 0)
279 } else {
280 VarType::Int(val)
281 })
282 } else if is_float {
283 cursor.evaluate().and_then(|v| v.as_double()).map(
284 VarType::Float,
285 )
286 } else {
287 cursor.evaluate().and_then(|v| v.as_literal_string()).map(
288 VarType::String,
289 )
290 };
291
292 let mangling = cursor_mangling(ctx, &cursor);
293 let var = Var::new(name, mangling, ty, value, is_const);
294
295 Ok(ParseResult::New(var, Some(cursor)))
296 }
297 _ => {
298 /* TODO */
299 Err(ParseError::Continue)
300 }
301 }
302 }
303 }
304
305 /// Try and parse a macro using all the macros parsed until now.
parse_macro( ctx: &BindgenContext, cursor: &clang::Cursor, ) -> Option<(Vec<u8>, cexpr::expr::EvalResult)>306 fn parse_macro(
307 ctx: &BindgenContext,
308 cursor: &clang::Cursor,
309 ) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
310 use cexpr::expr;
311
312 let mut cexpr_tokens = cursor.cexpr_tokens();
313
314 let parser = expr::IdentifierParser::new(ctx.parsed_macros());
315
316 match parser.macro_definition(&cexpr_tokens) {
317 Ok((_, (id, val))) => {
318 return Some((id.into(), val));
319 }
320 _ => {}
321 }
322
323 // Try without the last token, to workaround a libclang bug in versions
324 // previous to 4.0.
325 //
326 // See:
327 // https://bugs.llvm.org//show_bug.cgi?id=9069
328 // https://reviews.llvm.org/D26446
329 cexpr_tokens.pop()?;
330
331 match parser.macro_definition(&cexpr_tokens) {
332 Ok((_, (id, val))) => Some((id.into(), val)),
333 _ => None,
334 }
335 }
336
parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64>337 fn parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64> {
338 use cexpr::expr;
339 use cexpr::expr::EvalResult;
340
341 let cexpr_tokens = cursor.cexpr_tokens();
342
343 // TODO(emilio): We can try to parse other kinds of literals.
344 match expr::expr(&cexpr_tokens) {
345 Ok((_, EvalResult::Int(Wrapping(val)))) => Some(val),
346 _ => None,
347 }
348 }
349
get_integer_literal_from_cursor( cursor: &clang::Cursor, unit: &clang::TranslationUnit, ) -> Option<i64>350 fn get_integer_literal_from_cursor(
351 cursor: &clang::Cursor,
352 unit: &clang::TranslationUnit,
353 ) -> Option<i64> {
354 use clang_sys::*;
355 let mut value = None;
356 cursor.visit(|c| {
357 match c.kind() {
358 CXCursor_IntegerLiteral |
359 CXCursor_UnaryOperator => {
360 value = parse_int_literal_tokens(&c);
361 }
362 CXCursor_UnexposedExpr => {
363 value = get_integer_literal_from_cursor(&c, unit);
364 }
365 _ => (),
366 }
367 if value.is_some() {
368 CXChildVisit_Break
369 } else {
370 CXChildVisit_Continue
371 }
372 });
373 value
374 }
375