summaryrefslogtreecommitdiff
path: root/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs694
1 files changed, 546 insertions, 148 deletions
diff --git a/src/parser.rs b/src/parser.rs
index 7895aa68..c6fc174f 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,27 +1,30 @@
#![allow(non_upper_case_globals)]
use std::collections::{HashMap, HashSet};
-use std::collections::hash_map;
use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
+use std::path::Path;
use syntax::abi;
use types as il;
use types::*;
use clang as cx;
-use clang::{ast_dump, Cursor, Diagnostic, TranslationUnit, type_to_str};
+use clang::{ast_dump, Comment, Cursor, Diagnostic, TranslationUnit, type_to_str, kind_to_str};
use clangll::*;
use super::Logger;
+#[derive(Clone)]
pub struct ClangParserOptions {
pub builtin_names: HashSet<String>,
pub builtins: bool,
pub match_pat: Vec<String>,
pub emit_ast: bool,
pub fail_on_unknown_type: bool,
+ pub ignore_functions: bool,
+ pub enable_cxx_namespaces: bool,
pub override_enum_ty: Option<il::IKind>,
pub clang_args: Vec<String>,
}
@@ -29,10 +32,26 @@ pub struct ClangParserOptions {
struct ClangParserCtx<'a> {
options: ClangParserOptions,
name: HashMap<Cursor, Global>,
- globals: Vec<Global>,
builtin_defs: Vec<Cursor>,
+ module_map: ModuleMap,
+ current_module_id: ModuleId,
logger: &'a (Logger+'a),
- err_count: i32
+ err_count: i32,
+ anonymous_modules_found: usize,
+}
+
+impl<'a> ClangParserCtx<'a> {
+ fn module(&self, id: &ModuleId) -> &Module {
+ self.module_map.get(id).expect("Module not found!")
+ }
+
+ fn current_module(&self) -> &Module {
+ self.module(&self.current_module_id)
+ }
+
+ fn current_module_mut(&mut self) -> &mut Module {
+ self.module_map.get_mut(&self.current_module_id).expect("Module not found!")
+ }
}
fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool {
@@ -47,76 +66,119 @@ fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool {
return true;
}
- let mut found = false;
- ctx.options.match_pat.iter().all(|pat| {
- if (&name[..]).contains(pat) {
- found = true;
- }
- true
- });
-
- found
+ let name = file.name();
+ ctx.options.match_pat.iter().any(|pat| name.contains(pat))
}
fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
let cursor = cursor.canonical();
- let mut new_decl = false;
let override_enum_ty = ctx.options.override_enum_ty;
- let decl = match ctx.name.entry(cursor) {
- hash_map::Entry::Occupied(ref e) => e.get().clone(),
- hash_map::Entry::Vacant(e) => {
- new_decl = true;
- let spelling = cursor.spelling();
- let ty = cursor.cur_type();
- let layout = Layout::new(ty.size(), ty.align());
+ let new_decl = !ctx.name.contains_key(&cursor);
- let glob_decl = match cursor.kind() {
- CXCursor_StructDecl => {
- let ci = Rc::new(RefCell::new(CompInfo::new(spelling, CompKind::Struct, vec!(), layout)));
- GCompDecl(ci)
- }
- CXCursor_UnionDecl => {
- let ci = Rc::new(RefCell::new(CompInfo::new(spelling, CompKind::Union, vec!(), layout)));
- GCompDecl(ci)
- }
- CXCursor_EnumDecl => {
- let kind = match override_enum_ty {
- Some(t) => t,
- None => match cursor.enum_type().kind() {
- CXType_SChar | CXType_Char_S => ISChar,
- CXType_UChar | CXType_Char_U => IUChar,
- CXType_UShort => IUShort,
- CXType_UInt => IUInt,
- CXType_ULong => IULong,
- CXType_ULongLong => IULongLong,
- CXType_Short => IShort,
- CXType_Int => IInt,
- CXType_Long => ILong,
- CXType_LongLong => ILongLong,
- _ => IInt,
+ let decl = if new_decl {
+ let spelling = cursor.spelling();
+ let comment = cursor.raw_comment();
+ let (file, _, _, _) = cursor.location().location();
+ let ty = cursor.cur_type();
+ let layout = Layout::new(ty.size(), ty.align());
+ let filename = match Path::new(&file.name()).file_name() {
+ Some(name) => name.to_string_lossy().replace(".", "_"),
+ _ => "".to_string()
+ };
+ let glob_decl = match cursor.kind() {
+ CXCursor_StructDecl => {
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout)));
+ GCompDecl(ci)
+ }
+ CXCursor_UnionDecl => {
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Union, vec!(), layout)));
+ GCompDecl(ci)
+ }
+ CXCursor_EnumDecl => {
+ let kind = match override_enum_ty {
+ Some(t) => t,
+ None => match cursor.enum_type().kind() {
+ CXType_SChar | CXType_Char_S => ISChar,
+ CXType_UChar | CXType_Char_U => IUChar,
+ CXType_UShort => IUShort,
+ CXType_UInt => IUInt,
+ CXType_ULong => IULong,
+ CXType_ULongLong => IULongLong,
+ CXType_Short => IShort,
+ CXType_Int => IInt,
+ CXType_Long => ILong,
+ CXType_LongLong => ILongLong,
+ _ => IInt,
+ }
+ };
+
+ let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, ctx.current_module_id, filename, kind, vec!(), layout)));
+ GEnumDecl(ei)
+ }
+ CXCursor_ClassTemplate => {
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout)));
+ GCompDecl(ci)
+ }
+ CXCursor_ClassDecl => {
+ let args = match ty.num_template_args() {
+ -1 => vec!(),
+ len => {
+ let mut list = Vec::with_capacity(len as usize);
+ for i in 0..len {
+ let arg_type = ty.template_arg_type(i);
+ list.push(conv_ty(ctx, &arg_type, &cursor));
}
- };
- let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, kind, vec!(), layout)));
- GEnumDecl(ei)
- }
- CXCursor_TypedefDecl => {
- let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, TVoid)));
- GType(ti)
- }
- CXCursor_VarDecl => {
- let vi = Rc::new(RefCell::new(VarInfo::new(spelling, TVoid)));
- GVar(vi)
- }
- CXCursor_FunctionDecl => {
- let vi = Rc::new(RefCell::new(VarInfo::new(spelling, TVoid)));
- GFunc(vi)
- }
- _ => GOther,
- };
+ list
+ }
+ };
- e.insert(glob_decl.clone());
- glob_decl
- },
+ let module_id = if args.is_empty() {
+ ctx.current_module_id
+ } else {
+ // it's an instantiation of another template,
+ // find the canonical declaration to find the module it belongs to.
+ let parent = cursor.specialized();
+ ctx.name.get(&parent).and_then(|global| {
+ if let GCompDecl(ref ci) = *global {
+ Some(ci.borrow().module_id)
+ } else {
+ None
+ }
+ }).unwrap_or_else(|| {
+ ctx.logger.warn("Template class wasn't declared when parsing specialisation!");
+ ctx.current_module_id
+ })
+ };
+
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, module_id, filename, comment, CompKind::Struct, vec!(), layout)));
+ ci.borrow_mut().args = args;
+ GCompDecl(ci)
+ }
+ CXCursor_TypedefDecl => {
+ let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout)));
+ GType(ti)
+ }
+ CXCursor_VarDecl => {
+ let mangled = cursor.mangling();
+ let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid)));
+ GVar(vi)
+ }
+ CXCursor_MacroDefinition => {
+ let vi = Rc::new(RefCell::new(VarInfo::new(spelling, String::new(), comment, TVoid)));
+ GVar(vi)
+ }
+ CXCursor_FunctionDecl => {
+ let mangled = cursor.mangling();
+ let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid)));
+ GFunc(vi)
+ }
+ _ => GOther,
+ };
+
+ ctx.name.insert(cursor, glob_decl.clone());
+ glob_decl
+ } else {
+ ctx.name.get(&cursor).unwrap().clone()
};
if new_decl && ctx.options.builtin_names.contains(&cursor.spelling()) {
@@ -128,7 +190,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) {
let name = decl_name(ctx, decl);
- ctx.globals.push(name);
+ ctx.current_module_mut().globals.push(name);
}
fn fwd_decl<F:FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) {
@@ -153,45 +215,42 @@ fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi {
}
}
-fn conv_ptr_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor, layout: Layout) -> il::Type {
+fn conv_ptr_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor, is_ref: bool, layout: Layout) -> il::Type {
let is_const = ty.is_const();
match ty.kind() {
CXType_Void => {
- TPtr(Box::new(TVoid), is_const, layout)
+ return TPtr(Box::new(TVoid), is_const, is_ref, layout)
}
CXType_Unexposed |
CXType_FunctionProto |
CXType_FunctionNoProto => {
let ret_ty = ty.ret_type();
- let decl = ty.declaration();
- if ret_ty.kind() != CXType_Invalid {
+ return if ret_ty.kind() != CXType_Invalid {
TFuncPtr(mk_fn_sig(ctx, ty, cursor))
- } else if decl.kind() != CXCursor_NoDeclFound {
- TPtr(Box::new(conv_decl_ty(ctx, &decl)), ty.is_const(), layout)
} else if cursor.kind() == CXCursor_VarDecl {
let can_ty = ty.canonical_type();
conv_ty(ctx, &can_ty, cursor)
} else {
- TPtr(Box::new(TVoid), ty.is_const(), layout)
- }
+ TPtr(Box::new(conv_decl_ty(ctx, ty, cursor)), ty.is_const(), is_ref, layout)
+ };
}
CXType_Typedef => {
let decl = ty.declaration();
let def_ty = decl.typedef_type();
if def_ty.kind() == CXType_FunctionProto ||
def_ty.kind() == CXType_FunctionNoProto {
- TPtr(Box::new(conv_ptr_ty(ctx, &def_ty, cursor, layout)), is_const, layout)
+ return TPtr(Box::new(conv_ptr_ty(ctx, &def_ty, cursor, is_ref, layout)), is_const, is_ref, layout);
} else {
- TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, layout)
+ return TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, is_ref, layout);
}
}
- _ => TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, layout),
+ _ => return TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, is_ref, layout),
}
}
fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::FuncSig {
let args_lst: Vec<(String, il::Type)> = match cursor.kind() {
- CXCursor_FunctionDecl => {
+ CXCursor_FunctionDecl | CXCursor_CXXMethod => {
// For CXCursor_FunctionDecl, cursor.args() is the reliable way to
// get parameter names and types.
cursor.args().iter().map(|arg| {
@@ -218,7 +277,7 @@ fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Fu
// Function is presumed unsafe if it takes a pointer argument.
let is_unsafe = args_lst.iter().any(|arg| match arg.1 {
- TPtr(_, _, _) => true,
+ TPtr(..) => true,
_ => false
});
@@ -231,34 +290,67 @@ fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Fu
}
}
-fn conv_decl_ty(ctx: &mut ClangParserCtx, cursor: &Cursor) -> il::Type {
- match cursor.kind() {
- CXCursor_StructDecl => {
- let decl = decl_name(ctx, cursor);
- let ci = decl.compinfo();
- TComp(ci)
- }
- CXCursor_UnionDecl => {
- let decl = decl_name(ctx, cursor);
+fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type {
+ let ty_decl = &ty.declaration();
+ return match ty_decl.kind() {
+ CXCursor_StructDecl |
+ CXCursor_UnionDecl |
+ CXCursor_ClassTemplate |
+ CXCursor_ClassDecl => {
+ let decl = decl_name(ctx, ty_decl);
+ let args = match ty.num_template_args() {
+ -1 => vec!(),
+ len => {
+ let mut list = Vec::with_capacity(len as usize);
+ for i in 0..len {
+ let arg_type = ty.template_arg_type(i);
+ list.push(conv_ty(ctx, &arg_type, &cursor));
+ }
+ list
+ }
+ };
let ci = decl.compinfo();
+ if !args.is_empty() {
+ ci.borrow_mut().args = args;
+ cursor.visit(|c, _: &Cursor| {
+ if c.kind() != CXCursor_TemplateRef {
+ return CXChildVisit_Continue;
+ }
+ let cref = c.definition();
+ ci.borrow_mut().ref_template = Some(conv_decl_ty(ctx, &cref.cur_type(), &cref));
+ CXChildVisit_Continue
+ });
+ }
TComp(ci)
}
CXCursor_EnumDecl => {
- let decl = decl_name(ctx, cursor);
+ let decl = decl_name(ctx, ty_decl);
let ei = decl.enuminfo();
TEnum(ei)
}
CXCursor_TypedefDecl => {
- let decl = decl_name(ctx, cursor);
+ let decl = decl_name(ctx, ty_decl);
let ti = decl.typeinfo();
TNamed(ti)
}
- _ => TVoid
- }
+ CXCursor_NoDeclFound | CXCursor_TypeAliasDecl => {
+ let layout = Layout::new(ty.size(), ty.align());
+ TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), ctx.current_module_id, TVoid, layout))))
+ }
+ _ => {
+ let fail = ctx.options.fail_on_unknown_type;
+ log_err_warn(ctx,
+ &format!("unsupported decl `{}` ({})",
+ kind_to_str(ty_decl.kind()), ty_decl.location()
+ ),
+ fail
+ );
+ TVoid
+ }
+ };
}
fn conv_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type {
- debug!("conv_ty: ty=`{}` sp=`{}` loc=`{}`", type_to_str(ty.kind()), cursor.spelling(), cursor.location());
let layout = Layout::new(ty.size(), ty.align());
match ty.kind() {
CXType_Void | CXType_Invalid => TVoid,
@@ -267,6 +359,8 @@ fn conv_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type
CXType_Char_S => TInt(ISChar, layout),
CXType_UChar |
CXType_Char_U => TInt(IUChar, layout),
+ CXType_WChar => TInt(IShort, layout),
+ CXType_Char16 |
CXType_UShort => TInt(IUShort, layout),
CXType_UInt => TInt(IUInt, layout),
CXType_ULong => TInt(IULong, layout),
@@ -278,22 +372,23 @@ fn conv_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type
CXType_Float => TFloat(FFloat, layout),
CXType_Double => TFloat(FDouble, layout),
CXType_LongDouble => TFloat(FDouble, layout),
- CXType_Pointer => conv_ptr_ty(ctx, &ty.pointee_type(), cursor, layout),
+ CXType_Pointer => conv_ptr_ty(ctx, &ty.pointee_type(), cursor, false, layout),
+ CXType_LValueReference => conv_ptr_ty(ctx, &ty.pointee_type(), cursor, true, layout),
CXType_VariableArray | CXType_DependentSizedArray | CXType_IncompleteArray => {
- conv_ptr_ty(ctx, &ty.elem_type(), cursor, layout)
+ conv_ptr_ty(ctx, &ty.elem_type(), cursor, false, layout)
}
CXType_FunctionProto => TFuncProto(mk_fn_sig(ctx, ty, cursor)),
CXType_Record |
CXType_Typedef |
CXType_Unexposed |
- CXType_Enum => conv_decl_ty(ctx, &ty.declaration()),
+ CXType_Enum => conv_decl_ty(ctx, ty, cursor),
CXType_ConstantArray => TArray(Box::new(conv_ty(ctx, &ty.elem_type(), cursor)), ty.array_size(), layout),
_ => {
let fail = ctx.options.fail_on_unknown_type;
log_err_warn(ctx,
&format!("unsupported type `{}` ({})",
type_to_str(ty.kind()), cursor.location()
- )[..],
+ ),
fail
);
TVoid
@@ -312,17 +407,64 @@ fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) {
}
}
+struct Annotations {
+ opaque: bool,
+ hide: bool,
+}
+
+impl Annotations {
+ fn new(cursor: &Cursor) -> Annotations {
+ let mut anno = Annotations {
+ opaque: false,
+ hide: false,
+ };
+
+ anno.parse(&cursor.comment());
+ anno
+ }
+
+ fn parse(&mut self, comment: &Comment) {
+ if comment.kind() == CXComment_HTMLStartTag &&
+ comment.get_tag_name() == "div" &&
+ comment.get_num_tag_attrs() > 1 &&
+ comment.get_tag_attr_name(0) == "rustbindgen" {
+ for i in 0..comment.get_num_tag_attrs() {
+ let name = comment.get_tag_attr_name(i);
+
+ match name.as_str() {
+ "opaque" => self.opaque = true,
+ "hide" => self.hide = true,
+ _ => (),
+ }
+ }
+ }
+
+ for i in 0..comment.num_children() {
+ self.parse(&comment.get_child(i));
+ }
+ }
+}
+
/// Recursively visits a cursor that represents a composite (struct or union)
/// type and fills members with CompMember instances representing the fields and
/// nested composites that make up the visited composite.
fn visit_composite(cursor: &Cursor, parent: &Cursor,
ctx: &mut ClangParserCtx,
+<<<<<<< 6f1904e52612db3a2517727c053e7cbc84601b2a
compinfo: &mut CompInfo) -> Enum_CXVisitorResult {
+=======
+ ci: &mut CompInfo) -> Enum_CXVisitorResult {
+
+>>>>>>> SM hacks squash
fn is_bitfield_continuation(field: &il::FieldInfo, ty: &il::Type, width: u32) -> bool {
match (&field.bitfields, ty) {
(&Some(ref bitfields), &il::TInt(_, layout)) if *ty == field.ty => {
bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w) + width <= (layout.size * 8) as u32
},
+ (&Some(ref bitfields), &il::TNamed(ref info)) if *ty == field.ty => {
+ let info = info.borrow();
+ bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w) + width <= (info.layout.size * 8) as u32
+ },
_ => false
}
}
@@ -342,9 +484,14 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
match cursor.kind() {
CXCursor_FieldDecl => {
+ let anno = Annotations::new(cursor);
+ if anno.hide {
+ return CXChildVisit_Continue;
+ }
let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
+ let comment = cursor.raw_comment();
- let (name, bitfields) = match (cursor.bit_width(), members.last_mut()) {
+ let (name, bitfields) = match (cursor.bit_width(), ci.members.last_mut()) {
// The field is a continuation of an exising bitfield
(Some(width), Some(&mut il::CompMember::Field(ref mut field)))
if is_bitfield_continuation(field, &ty, width) => {
@@ -363,7 +510,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
_ => {
let msg = format!("Enums in bitfields are not supported ({}.{}).",
cursor.spelling(), parent.spelling());
- ctx.logger.warn(&msg[..]);
+ ctx.logger.warn(&msg);
}
}
("".to_owned(), Some(vec!((cursor.spelling(), width))))
@@ -400,22 +547,37 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// };
//
+<<<<<<< 6f1904e52612db3a2517727c053e7cbc84601b2a
let is_composite = match (inner_composite(&ty), members.last()) {
+=======
+ fn inner_composite(mut ty: &il::Type) -> Option<&Rc<RefCell<CompInfo>>> {
+ loop {
+ match ty {
+ &TComp(ref comp_ty) => return Some(comp_ty),
+ &TPtr(ref ptr_ty, _, _, _) => ty = &**ptr_ty,
+ &TArray(ref array_ty, _, _) => ty = &**array_ty,
+ _ => return None
+ }
+ }
+ }
+
+ let is_composite = match (inner_composite(&ty), ci.members.last()) {
+>>>>>>> SM hacks squash
(Some(ty_compinfo), Some(&CompMember::Comp(ref c))) => {
c.borrow().deref() as *const _ == ty_compinfo.borrow().deref() as *const _
},
_ => false
};
- let field = FieldInfo::new(name, ty.clone(), bitfields);
+ let field = FieldInfo::new(name, ty.clone(), comment, bitfields);
if is_composite {
- if let Some(CompMember::Comp(c)) = members.pop() {
- members.push(CompMember::CompField(c, field));
+ if let Some(CompMember::Comp(c)) = ci.members.pop() {
+ ci.members.push(CompMember::CompField(c, field));
} else {
unreachable!(); // Checks in is_composite make this unreachable.
}
} else {
- members.push(CompMember::Field(field));
+ ci.members.push(CompMember::Field(field));
}
}
CXCursor_StructDecl | CXCursor_UnionDecl => {
@@ -424,16 +586,150 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// cannot be used elsewhere and so does not need to be added
// to globals otherwise it will be declared later and a global.
let decl = decl_name(ctx_, cursor);
- let ci = decl.compinfo();
+ let ci2 = decl.compinfo();
cursor.visit(|c, p| {
- let mut ci_ = ci.borrow_mut();
+ let mut ci_ = ci2.borrow_mut();
visit_composite(c, p, ctx_, &mut ci_)
});
- members.push(CompMember::Comp(decl.compinfo()));
+ ci.members.push(CompMember::Comp(decl.compinfo()));
});
}
CXCursor_PackedAttr => {
- compinfo.layout.packed = true;
+ ci.layout.packed = true;
+ }
+ CXCursor_TemplateTypeParameter => {
+ let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
+ let layout = Layout::new(ty.size(), ty.align());
+ ci.args.push(TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout)))));
+ }
+ CXCursor_EnumDecl => {
+ let anno = Annotations::new(cursor);
+ fwd_decl(ctx, cursor, |ctx_| {
+ let decl = decl_name(ctx_, cursor);
+ let ei = decl.enuminfo();
+ ei.borrow_mut().comment = cursor.raw_comment();
+ cursor.visit(|c, _: &Cursor| {
+ let mut ei_ = ei.borrow_mut();
+ visit_enum(c, &mut ei_.items)
+ });
+ if anno.opaque {
+ ei.borrow_mut().items = vec!();
+ }
+ ci.members.push(CompMember::Enum(ei));
+ });
+ }
+ CXCursor_CXXBaseSpecifier => {
+ let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
+ let fieldname = if ci.members.len() > 0 {
+ format!("_base{}", ci.members.len())
+ } else {
+ "_base".to_string()
+ };
+ let found_virtual_base = if ci.members.is_empty() {
+ false
+ } else if let CompMember::Field(ref fi) = ci.members[0] {
+ if let TComp(ref ci2) = fi.ty {
+ ci2.borrow().has_vtable
+ } else {
+ false
+ }
+ } else {
+ false
+ };
+ let field = FieldInfo::new(fieldname, ty.clone(), "".to_owned(), None);
+ if !found_virtual_base && cursor.is_virtual_base() {
+ ci.members.insert(0, CompMember::Field(field));
+ ci.has_vtable = true;
+ } else {
+ ci.members.push(CompMember::Field(field));
+ }
+ ci.base_members += 1;
+ }
+ CXCursor_CXXMethod => {
+ if ctx.options.ignore_functions {
+ return CXChildVisit_Continue;
+ }
+
+ let linkage = cursor.linkage();
+ if linkage != CXLinkage_External {
+ return CXChildVisit_Continue;
+ }
+
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ if ci.args.len() > 0 {
+ return CXChildVisit_Continue;
+ }
+
+ if cursor.access_specifier() == CX_CXXPrivate {
+ return CXChildVisit_Continue;
+ }
+
+ let spelling = cursor.spelling();
+ if spelling.len() > 8 &&
+ &(spelling)[..8] == "operator" {
+ return CXChildVisit_Continue;
+ }
+
+ fn is_override(ci: &CompInfo, sig: &Type, name: &str) -> bool {
+ for vm in ci.vmethods.iter() {
+ if vm.name == name && &vm.ty == sig {
+ return true;
+ }
+ }
+ for base in ci.members[..ci.base_members].iter() {
+ let base = match base {
+ &CompMember::Field(ref fi) => {
+ match fi.ty {
+ TComp(ref ci) => ci.clone(),
+ _ => continue,
+ }
+ },
+ _ => unreachable!()
+ };
+ if is_override(&*base.borrow(), sig, name) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if cursor.method_is_virtual() {
+ ci.has_vtable = true;
+ }
+
+ let mut sig = mk_fn_sig(ctx, &cursor.cur_type(), cursor);
+ if !cursor.method_is_static() {
+ // XXX what have i done
+ if cursor.method_is_virtual() {
+ sig.args.insert(0, ("this".to_string(),TPtr(Box::new(TVoid), cursor.cur_type().is_const(), false, Layout::zero())));
+ } else {
+ sig.args.insert(0, ("this".to_string(),
+ TPtr(Box::new(TNamed(Rc::new(RefCell::new(TypeInfo::new(ci.name.clone(), ctx.current_module_id, TVoid, Layout::zero()))))), cursor.cur_type().is_const(), false, Layout::zero())));
+ }
+ }
+
+ // XXX with final classes we can optimize a bit
+ let sig = TFuncPtr(sig);
+ if is_override(ci, &sig, &spelling) {
+ return CXChildVisit_Continue;
+ }
+
+ let mut vi = VarInfo::new(spelling, cursor.mangling(), cursor.raw_comment(), sig);
+ vi.is_static = cursor.method_is_static();
+ vi.is_const = cursor.cur_type().is_const();
+
+ if cursor.method_is_virtual() {
+ ci.vmethods.push(vi);
+ } else {
+ ci.methods.push(vi);
+ }
+ }
+ CXCursor_Destructor => {
+ ci.has_destructor = true;
}
_ => {
// XXX: Some kind of warning would be nice, but this produces far
@@ -453,45 +749,48 @@ fn visit_enum(cursor: &Cursor,
items: &mut Vec<EnumItem>) -> Enum_CXVisitorResult {
if cursor.kind() == CXCursor_EnumConstantDecl {
let name = cursor.spelling();
+ let comment = cursor.raw_comment();
let val = cursor.enum_val();
- let item = EnumItem::new(name, val);
+ let item = EnumItem::new(name, comment, val);
items.push(item);
}
CXChildVisit_Continue
}
-fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> {
- if cursor.kind() == CXCursor_IntegerLiteral {
- match unit.tokens(cursor) {
- None => None,
- Some(tokens) => {
- if tokens.is_empty() || tokens[0].kind != CXToken_Literal {
- None
- } else {
- let s = &tokens[0].spelling;
- let parsed = {
- //TODO: try to preserve hex literals?
- if s.starts_with("0x") {
- i64::from_str_radix(&s[2..], 16)
- } else {
- s.parse()
- }
- };
- match parsed {
- Ok(i) => Some(i),
- Err(_) => None,
+fn parse_int_literal_tokens(cursor: &Cursor, unit: &TranslationUnit, which: usize) -> Option<i64> {
+ match unit.tokens(cursor) {
+ None => None,
+ Some(tokens) => {
+ if tokens.len() <= which || tokens[which].kind != CXToken_Literal {
+ None
+ } else {
+ let ref s = tokens[which].spelling;
+ let parsed = {
+ //TODO: try to preserve hex literals?
+ if s.starts_with("0x") {
+ i64::from_str_radix(&s[2..], 16)
+ } else {
+ s.parse()
}
+ };
+ match parsed {
+ Ok(i) => Some(i),
+ Err(_) => None,
}
}
}
}
- else {
- None
+}
+
+fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> {
+ if cursor.kind() == CXCursor_IntegerLiteral {
+ return parse_int_literal_tokens(cursor, unit, 0);
}
+ return None;
}
fn visit_top(cursor: &Cursor,
- ctx: &mut ClangParserCtx,
+ mut ctx: &mut ClangParserCtx,
unit: &TranslationUnit) -> Enum_CXVisitorResult {
if !match_pattern(ctx, cursor) {
return CXChildVisit_Continue;
@@ -499,9 +798,10 @@ fn visit_top(cursor: &Cursor,
match cursor.kind() {
CXCursor_UnexposedDecl => {
- CXChildVisit_Recurse
+ return CXChildVisit_Recurse;
}
- CXCursor_StructDecl | CXCursor_UnionDecl => {
+ CXCursor_StructDecl | CXCursor_UnionDecl | CXCursor_ClassDecl | CXCursor_ClassTemplate => {
+ let anno = Annotations::new(cursor);
fwd_decl(ctx, cursor, |ctx_| {
let decl = decl_name(ctx_, cursor);
let ci = decl.compinfo();
@@ -509,7 +809,13 @@ fn visit_top(cursor: &Cursor,
let mut ci_ = ci.borrow_mut();
visit_composite(c, p, ctx_, &mut ci_)
});
- ctx_.globals.push(GComp(ci));
+ if anno.opaque {
+ ci.borrow_mut().members = vec!();
+ }
+ if anno.hide {
+ ci.borrow_mut().hide = true;
+ }
+ ctx_.current_module_mut().globals.push(GComp(ci));
});
CXChildVisit_Continue
}
@@ -517,11 +823,12 @@ fn visit_top(cursor: &Cursor,
fwd_decl(ctx, cursor, |ctx_| {
let decl = decl_name(ctx_, cursor);
let ei = decl.enuminfo();
+ ei.borrow_mut().comment = cursor.raw_comment();
cursor.visit(|c, _: &Cursor| {
let mut ei_ = ei.borrow_mut();
visit_enum(c, &mut ei_.items)
});
- ctx_.globals.push(GEnum(ei));
+ ctx_.current_module_mut().globals.push(GEnum(ei));
});
CXChildVisit_Continue
}
@@ -531,12 +838,23 @@ fn visit_top(cursor: &Cursor,
return CXChildVisit_Continue;
}
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ let spelling = cursor.spelling();
+ if spelling.len() > 8 &&
+ &(spelling)[..8] == "operator" {
+ return CXChildVisit_Continue;
+ }
+
let func = decl_name(ctx, cursor);
let vi = func.varinfo();
let mut vi = vi.borrow_mut();
vi.ty = TFuncPtr(mk_fn_sig(ctx, &cursor.cur_type(), cursor));
- ctx.globals.push(func);
+ ctx.current_module_mut().globals.push(func);
CXChildVisit_Continue
}
@@ -546,6 +864,10 @@ fn visit_top(cursor: &Cursor,
return CXChildVisit_Continue;
}
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
let var = decl_name(ctx, cursor);
let vi = var.varinfo();
@@ -556,7 +878,7 @@ fn visit_top(cursor: &Cursor,
vi.val = visit_literal(c, unit);
CXChildVisit_Continue
});
- ctx.globals.push(var);
+ ctx.current_module_mut().globals.push(var);
CXChildVisit_Continue
}
@@ -566,12 +888,17 @@ fn visit_top(cursor: &Cursor,
under_ty = under_ty.canonical_type();
}
+ if cursor.spelling() ==
+ cursor.typedef_type().declaration().spelling() {
+ return CXChildVisit_Continue;
+ }
let ty = conv_ty(ctx, &under_ty, cursor);
let typedef = decl_name(ctx, cursor);
let ti = typedef.typeinfo();
let mut ti = ti.borrow_mut();
ti.ty = ty.clone();
- ctx.globals.push(typedef);
+ ti.comment = cursor.raw_comment();
+ ctx.current_module_mut().globals.push(typedef);
opaque_ty(ctx, &under_ty);
@@ -580,36 +907,107 @@ fn visit_top(cursor: &Cursor,
CXCursor_FieldDecl => {
CXChildVisit_Continue
}
- _ => CXChildVisit_Continue,
+ CXCursor_Namespace => {
+ if !ctx.options.enable_cxx_namespaces {
+ return CXChildVisit_Recurse;
+ }
+
+ let namespace_name = match unit.tokens(cursor) {
+ None => None,
+ Some(tokens) => {
+ if tokens.len() <= 1 {
+ None
+ } else {
+ match &*tokens[1].spelling {
+ "{" => None,
+ s => Some(s.to_owned()),
+ }
+ }
+ }
+ }.unwrap_or_else(|| {
+ ctx.anonymous_modules_found += 1;
+ format!("__anonymous{}", ctx.anonymous_modules_found)
+ });
+
+ // Find an existing namespace children of the current one
+ let mod_id = ctx.current_module()
+ .children_ids.iter()
+ .find(|id| ctx.module_map.get(id).unwrap().name == namespace_name)
+ .map(|id| *id);
+
+ let mod_id = match mod_id {
+ Some(id) => id,
+ None => {
+ let parent_id = ctx.current_module_id;
+ let id = ModuleId::next();
+ ctx.module_map.get_mut(&parent_id).unwrap().children_ids.push(id);
+ ctx.module_map.insert(id, Module::new(namespace_name, Some(parent_id)));
+ id
+ }
+ };
+
+ let previous_id = ctx.current_module_id;
+
+ ctx.current_module_id = mod_id;
+ cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit));
+ ctx.current_module_id = previous_id;
+
+ return CXChildVisit_Continue;
+ }
+ CXCursor_MacroDefinition => {
+ let val = parse_int_literal_tokens(cursor, unit, 1);
+ if val.is_none() {
+ // Not an integer literal.
+ return CXChildVisit_Continue;
+ }
+ let var = decl_name(ctx, cursor);
+ let vi = var.varinfo();
+ let mut vi = vi.borrow_mut();
+ vi.ty = match val {
+ None => TVoid,
+ Some(v) if v.abs() > u32::max_value() as i64 => TInt(IULongLong, Layout::new(8, 8)),
+ _ => TInt(IUInt, Layout::new(4, 4)),
+ };
+ vi.is_const = true;
+ vi.val = val;
+ ctx.current_module_mut().globals.push(var);
+
+ return CXChildVisit_Continue;
+ }
+ _ => return CXChildVisit_Continue,
}
}
fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) {
if is_err {
ctx.err_count += 1;
- ctx.logger.error(msg)
+ ctx.logger.error(msg);
} else {
- ctx.logger.warn(msg)
+ ctx.logger.warn(msg);
}
}
-pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
+pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, ()> {
let mut ctx = ClangParserCtx {
options: options,
name: HashMap::new(),
builtin_defs: vec!(),
- globals: vec!(),
+ module_map: ModuleMap::new(),
+ current_module_id: ROOT_MODULE_ID,
logger: logger,
- err_count: 0
+ err_count: 0,
+ anonymous_modules_found: 0,
};
+ ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None));
+
let ix = cx::Index::create(false, true);
if ix.is_null() {
ctx.logger.error("Clang failed to create index");
return Err(())
}
- let unit = TranslationUnit::parse(&ix, "", &ctx.options.clang_args[..], &[], 0);
+ let unit = TranslationUnit::parse(&ix, "", &ctx.options.clang_args[..], &[], CXTranslationUnit_DetailedPreprocessingRecord);
if unit.is_null() {
ctx.logger.error("No input files given");
return Err(())
@@ -619,7 +1017,7 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<Vec<Global>
for d in &diags {
let msg = d.format(Diagnostic::default_opts());
let is_err = d.severity() >= CXDiagnostic_Error;
- log_err_warn(&mut ctx, &msg[..], is_err);
+ log_err_warn(&mut ctx, &msg, is_err);
}
if ctx.err_count > 0 {
@@ -646,5 +1044,5 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<Vec<Global>
return Err(())
}
- Ok(ctx.globals)
+ Ok(ctx.module_map)
}