use cexpr;
use clang;
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use std::num::Wrapping;
use super::context::{BindgenContext, ItemId};
use super::function::cursor_mangling;
use super::int::IntKind;
use super::item::Item;
use super::ty::{FloatKind, TypeKind};
#[derive(Debug)]
pub enum VarType {
Bool(bool),
Int(i64),
Float(f64),
Char(u8),
String(Vec<u8>),
}
#[derive(Debug)]
pub struct Var {
name: String,
mangled_name: Option<String>,
ty: ItemId,
val: Option<VarType>,
is_const: bool,
}
impl Var {
pub fn new(name: String,
mangled: Option<String>,
ty: ItemId,
val: Option<VarType>,
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<&VarType> {
self.val.as_ref()
}
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,
ctx: &mut BindgenContext)
-> Result<ParseResult<Self>, ParseError> {
use clang_sys::*;
use cexpr::expr::EvalResult;
use cexpr::literal::CChar;
match cursor.kind() {
CXCursor_MacroDefinition => {
let value = parse_macro(ctx, &cursor, ctx.translation_unit());
let (id, value) = match value {
Some(v) => v,
None => return Err(ParseError::Continue),
};
assert!(!id.is_empty(), "Empty macro name?");
let previously_defined = ctx.parsed_macro(&id);
ctx.note_parsed_macro(id.clone(), value.clone());
if previously_defined {
let name = String::from_utf8(id).unwrap();
warn!("Duplicated macro definition: {}", name);
return Err(ParseError::Continue);
}
let name = String::from_utf8(id).unwrap();
let (type_kind, val) = match value {
EvalResult::Invalid => return Err(ParseError::Continue),
EvalResult::Float(f) => {
(TypeKind::Float(FloatKind::Float), VarType::Float(f))
}
EvalResult::Char(c) => {
let c = match c {
CChar::Char(c) => {
assert_eq!(c.len_utf8(), 1);
c as u8
}
CChar::Raw(c) => {
assert!(c <= ::std::u8::MAX as u64);
c as u8
}
};
(TypeKind::Int(IntKind::U8), VarType::Char(c))
}
EvalResult::Str(val) => {
let char_ty =
Item::builtin_type(TypeKind::Int(IntKind::U8),
true,
ctx);
(TypeKind::Pointer(char_ty), VarType::String(val))
}
EvalResult::Int(Wrapping(value)) => {
let kind = ctx.type_chooser()
.and_then(|c| c.int_macro(&name, value))
.unwrap_or_else(|| {
if value < 0 {
if value < i32::min_value() as i64 {
IntKind::LongLong
} else {
IntKind::Int
}
} else if value > u32::max_value() as i64 {
IntKind::ULongLong
} else {
IntKind::UInt
}
});
(TypeKind::Int(kind), VarType::Int(value))
}
};
let ty = Item::builtin_type(type_kind, true, ctx);
Ok(ParseResult::New(Var::new(name, None, ty, Some(val), 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();
let is_const = ty.is_const();
let ty = match Item::from_ty(&ty, Some(cursor), None, ctx) {
Ok(ty) => ty,
Err(e) => {
assert_eq!(ty.kind(), CXType_Auto,
"Couldn't resolve constant type, and it \
wasn't an nondeductible auto type!");
return Err(e);
}
};
let canonical_ty = ctx.safe_resolve_type(ty)
.and_then(|t| t.safe_canonical_type(ctx));
let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
let is_float = canonical_ty.map_or(false, |t| t.is_float());
let value = if is_integer {
let kind = match *canonical_ty.unwrap().kind() {
TypeKind::Int(kind) => kind,
_ => unreachable!(),
};
let mut val = cursor.evaluate()
.and_then(|v| v.as_int())
.map(|val| val as i64);
if val.is_none() || !kind.signedness_matches(val.unwrap()) {
let tu = ctx.translation_unit();
val = get_integer_literal_from_cursor(&cursor, tu);
}
val.map(|val| {
if kind == IntKind::Bool {
VarType::Bool(val != 0)
} else {
VarType::Int(val)
}
})
} else if is_float {
cursor.evaluate()
.and_then(|v| v.as_double())
.map(VarType::Float)
} else {
cursor.evaluate()
.and_then(|v| v.as_literal_string())
.map(VarType::String)
};
let mangling = cursor_mangling(&cursor);
let var = Var::new(name, mangling, ty, value, is_const);
Ok(ParseResult::New(var, Some(cursor)))
}
_ => {
Err(ParseError::Continue)
}
}
}
}
fn parse_macro(ctx: &BindgenContext,
cursor: &clang::Cursor,
unit: &clang::TranslationUnit)
-> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
use cexpr::{expr, nom};
let cexpr_tokens = match unit.cexpr_tokens(cursor) {
None => return None,
Some(tokens) => tokens,
};
let parser = expr::IdentifierParser::new(ctx.parsed_macros());
let result = parser.macro_definition(&cexpr_tokens);
match result {
nom::IResult::Done(_, (id, val)) => Some((id.into(), val)),
_ => None,
}
}
fn parse_int_literal_tokens(cursor: &clang::Cursor,
unit: &clang::TranslationUnit)
-> Option<i64> {
use cexpr::{expr, nom};
use cexpr::expr::EvalResult;
let cexpr_tokens = match unit.cexpr_tokens(cursor) {
None => return None,
Some(tokens) => tokens,
};
match expr::expr(&cexpr_tokens) {
nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val),
_ => None,
}
}
fn get_integer_literal_from_cursor(cursor: &clang::Cursor,
unit: &clang::TranslationUnit)
-> Option<i64> {
use clang_sys::*;
let mut value = None;
cursor.visit(|c| {
match c.kind() {
CXCursor_IntegerLiteral |
CXCursor_UnaryOperator => {
value = parse_int_literal_tokens(&c, unit);
}
CXCursor_UnexposedExpr => {
value = get_integer_literal_from_cursor(&c, unit);
}
_ => (),
}
if value.is_some() {
CXChildVisit_Break
} else {
CXChildVisit_Continue
}
});
value
}