summaryrefslogtreecommitdiff
path: root/src/ir/var.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/var.rs')
-rw-r--r--src/ir/var.rs160
1 files changed, 160 insertions, 0 deletions
diff --git a/src/ir/var.rs b/src/ir/var.rs
new file mode 100644
index 00000000..ac59973b
--- /dev/null
+++ b/src/ir/var.rs
@@ -0,0 +1,160 @@
+use super::item::{Item, ItemId};
+use super::context::BindgenContext;
+use super::ty::TypeKind;
+use super::int::IntKind;
+use super::function::cursor_mangling;
+use parse::{ClangItemParser, ClangSubItemParser, ParseResult, ParseError};
+use clang;
+
+#[derive(Debug)]
+pub struct Var {
+ /// The name of the variable.
+ name: String,
+ /// The mangled name of the variable.
+ mangled_name: Option<String>,
+ /// The type of the variable.
+ ty: ItemId,
+ /// TODO: support non-integer constants?
+ /// The integer value of the variable.
+ val: Option<i64>,
+ /// Whether this variable is const.
+ is_const: bool,
+}
+
+impl Var {
+ pub fn new(name: String,
+ mangled: Option<String>,
+ ty: ItemId,
+ val: Option<i64>,
+ is_const: bool) -> Var {
+ assert!(!name.is_empty());
+ Var {
+ name: name,
+ mangled_name: mangled,
+ ty: ty,
+ val: val,
+ is_const: is_const,
+ }
+ }
+
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ pub fn val(&self) -> Option<i64> {
+ self.val
+ }
+
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_ref().map(|n| &**n)
+ }
+}
+
+impl ClangSubItemParser for Var {
+ fn parse(cursor: clang::Cursor,
+ context: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> {
+ use clangll::*;
+ match cursor.kind() {
+ CXCursor_MacroDefinition => {
+ let value = match parse_int_literal_tokens(&cursor, context.translation_unit(), 1) {
+ None => return Err(ParseError::Continue),
+ Some(v) => v,
+ };
+
+ let name = cursor.spelling();
+ if name.is_empty() {
+ warn!("Empty macro name?");
+ return Err(ParseError::Continue);
+ }
+
+ if context.parsed_macro(&name) {
+ warn!("Duplicated macro definition: {}", name);
+ return Err(ParseError::Continue);
+ }
+ context.note_parsed_macro(name.clone());
+
+ let ty = if value.abs() > u32::max_value() as i64 {
+ Item::builtin_type(TypeKind::Int(IntKind::ULongLong), true, context)
+ } else {
+ Item::builtin_type(TypeKind::Int(IntKind::UInt), true, context)
+ };
+
+ Ok(ParseResult::New(Var::new(name, None, ty, Some(value), true), Some(cursor)))
+ }
+ CXCursor_VarDecl => {
+ let name = cursor.spelling();
+ if name.is_empty() {
+ warn!("Empty constant name?");
+ return Err(ParseError::Continue);
+ }
+
+ let ty = cursor.cur_type();
+
+ // XXX this is redundant, remove!
+ let is_const = ty.is_const();
+
+ let ty = Item::from_ty(&ty, Some(cursor), None, context)
+ .expect("Unable to resolve constant type?");
+
+ let mut value = None;
+
+ // Note: Ty might not be totally resolved yet, see
+ // tests/headers/inner_const.hpp
+ //
+ // That's fine because in that case we know it's not a literal.
+ if context.safe_resolve_type(ty).map_or(false, |t| t.is_integer_literal()) {
+ // Try to parse a literal token value
+ cursor.visit(|c, _| {
+ if c.kind() == CXCursor_IntegerLiteral {
+ value =
+ parse_int_literal_tokens(&c,
+ context.translation_unit(),
+ 0);
+ }
+ CXChildVisit_Continue
+ });
+ }
+
+ let mangling = cursor_mangling(&cursor);
+
+ let var = Var::new(name, mangling, ty, value, is_const);
+ Ok(ParseResult::New(var, Some(cursor)))
+
+ }
+ _ => {
+ /* TODO */
+ Err(ParseError::Continue)
+ }
+ }
+ }
+}
+
+fn parse_int_literal_tokens(cursor: &clang::Cursor,
+ unit: &clang::TranslationUnit,
+ which: usize) -> Option<i64> {
+ use clangll::CXToken_Literal;
+ let tokens = match unit.tokens(cursor) {
+ None => return None,
+ Some(tokens) => tokens,
+ };
+
+ if tokens.len() <= which || tokens[which].kind != CXToken_Literal {
+ return None;
+ }
+
+ let s = &tokens[which].spelling;
+ // TODO: try to preserve hex literals?
+ if s.starts_with("0x") {
+ i64::from_str_radix(&s[2..], 16).ok()
+ } else {
+ s.parse().ok()
+ }
+}