summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/bindgen.rs48
-rw-r--r--src/clang.rs170
-rw-r--r--src/clangll.rs26
-rw-r--r--src/gen.rs1573
-rw-r--r--src/lib.rs57
-rw-r--r--src/parser.rs694
-rw-r--r--src/types.rs154
7 files changed, 2044 insertions, 678 deletions
diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs
index c049f9a1..b0a3c8e8 100644
--- a/src/bin/bindgen.rs
+++ b/src/bin/bindgen.rs
@@ -2,7 +2,8 @@
#![crate_type = "bin"]
extern crate bindgen;
-#[macro_use] extern crate log;
+#[macro_use]
+extern crate log;
use bindgen::{Bindings, BindgenOptions, LinkType, Logger};
use std::io;
@@ -16,17 +17,17 @@ struct StdLogger;
impl Logger for StdLogger {
fn error(&self, msg: &str) {
- error!("{}", msg);
+ println!("{}", msg);
}
fn warn(&self, msg: &str) {
- warn!("{}", msg);
+ println!("{}", msg);
}
}
enum ParseResult {
CmdUsage,
- ParseOk(BindgenOptions, Box<io::Write+'static>),
+ ParseOk(BindgenOptions, Box<io::Write>),
ParseErr(String)
}
@@ -34,7 +35,6 @@ fn parse_args(args: &[String]) -> ParseResult {
let args_len = args.len();
let mut options: BindgenOptions = Default::default();
- options.derive_debug = false;
let mut out = Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>;
if args_len == 0 {
@@ -47,7 +47,7 @@ fn parse_args(args: &[String]) -> ParseResult {
options.links.push((args[ix][2..].to_string(), LinkType::Default));
ix += 1;
} else {
- match &args[ix][..] {
+ match &*args[ix] {
"--help" | "-h" => {
return ParseResult::CmdUsage;
}
@@ -98,12 +98,8 @@ fn parse_args(args: &[String]) -> ParseResult {
options.builtins = true;
ix += 1;
}
- "-no-rust-enums" => {
- options.rust_enums = false;
- ix += 1;
- }
- "-derive-debug" => {
- options.derive_debug = true;
+ "-ignore-functions" => {
+ options.ignore_functions = true;
ix += 1;
}
"-allow-unknown-types" => {
@@ -117,6 +113,14 @@ fn parse_args(args: &[String]) -> ParseResult {
options.override_enum_ty = args[ix + 1].clone();
ix += 2;
}
+ "-enable-cxx-namespaces" => {
+ options.enable_cxx_namespaces = true;
+ ix += 1;
+ }
+ "-no-type-renaming" => {
+ options.rename_types = false;
+ ix += 1;
+ }
_ => {
options.clang_args.push(args[ix].clone());
ix += 1;
@@ -129,7 +133,7 @@ fn parse_args(args: &[String]) -> ParseResult {
}
fn print_usage(bin: String) {
- let mut s = format!("Usage: {} [options] input.h", &bin[..]);
+ let mut s = format!("Usage: {} [options] input.h", &bin);
s.push_str(
"
Options:
@@ -145,6 +149,10 @@ Options:
matching any rule are bound to.
-builtins Output bindings for builtin definitions
(for example __builtin_va_list)
+ -ignore-functions Don't generate bindings for functions and methods.
+ This is useful when you only care about struct layouts.
+ -enable-cxx-namespaces Enable support for C++ namespaces.
+ -no-type-renaming Don't rename types.
-allow-unknown-types Don't fail if we encounter types we do not support,
instead treat them as void
-emit-clang-ast Output the ast (for debugging purposes)
@@ -163,14 +171,22 @@ Options:
Options other than stated above are passed to clang.
"
);
- print!("{}", &s[..]);
+ println!("{}", &s);
}
pub fn main() {
let mut bind_args: Vec<_> = env::args().collect();
let bin = bind_args.remove(0);
- match parse_args(&bind_args[..]) {
+ match bindgen::get_include_dir() {
+ Some(path) => {
+ bind_args.push("-I".to_owned());
+ bind_args.push(path);
+ }
+ None => (),
+ }
+
+ match parse_args(&bind_args) {
ParseResult::ParseErr(e) => panic!(e),
ParseResult::CmdUsage => print_usage(bin),
ParseResult::ParseOk(options, out) => {
@@ -179,7 +195,7 @@ pub fn main() {
Ok(bindings) => match bindings.write(out) {
Ok(()) => (),
Err(e) => {
- logger.error(&format!("Unable to write bindings to file. {}", e)[..]);
+ logger.error(&format!("Unable to write bindings to file. {}", e));
exit(-1);
}
},
diff --git a/src/clang.rs b/src/clang.rs
index a8c4aace..be07a0e3 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -3,11 +3,9 @@
use std::os::raw::{c_uint, c_char, c_int, c_ulong};
use std::{mem, ptr};
use std::fmt;
-use std::str;
-use std::ffi::CStr;
use std::hash::Hash;
use std::hash::Hasher;
-use std::ffi::CString;
+use std::ffi::{CString, CStr};
use clangll::*;
@@ -27,12 +25,40 @@ impl Cursor {
}
}
+ pub fn mangling(&self) -> String {
+ let mut mangling = unsafe {
+ String_ { x: clang_Cursor_getMangling(self.x) }.to_string()
+ };
+
+ // Try to undo backend mangling
+ if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
+ mangling.remove(0);
+ }
+ mangling
+ }
+
+ pub fn semantic_parent(&self) -> Cursor {
+ unsafe {
+ Cursor { x: clang_getCursorSemanticParent(self.x) }
+ }
+ }
+
pub fn kind(&self) -> Enum_CXCursorKind {
unsafe {
clang_getCursorKind(self.x)
}
}
+ pub fn is_template(&self) -> bool {
+ self.specialized().is_valid()
+ }
+
+ pub fn is_valid(&self) -> bool {
+ unsafe {
+ clang_isInvalid(self.kind()) == 0
+ }
+ }
+
pub fn location(&self) -> SourceLocation {
unsafe {
SourceLocation { x: clang_getCursorLocation(self.x) }
@@ -45,6 +71,18 @@ impl Cursor {
}
}
+ pub fn raw_comment(&self) -> String {
+ unsafe {
+ String_ { x: clang_Cursor_getRawCommentText(self.x) }.to_string()
+ }
+ }
+
+ pub fn comment(&self) -> Comment {
+ unsafe {
+ Comment { x: clang_Cursor_getParsedComment(self.x) }
+ }
+ }
+
pub fn cur_type(&self) -> Type {
unsafe {
Type { x: clang_getCursorType(self.x) }
@@ -63,6 +101,12 @@ impl Cursor {
}
}
+ pub fn specialized(&self) -> Cursor {
+ unsafe {
+ Cursor { x: clang_getSpecializedCursorTemplate(self.x) }
+ }
+ }
+
pub fn visit<F>(&self, func:F)
where F: for<'a, 'b> FnMut(&'a Cursor, &'b Cursor) -> Enum_CXChildVisitResult
{
@@ -112,6 +156,12 @@ impl Cursor {
}
}
+ pub fn visibility(&self) -> Enum_CXVisibilityKind {
+ unsafe {
+ clang_getCursorVisibility(self.x)
+ }
+ }
+
// function
pub fn args(&self) -> Vec<Cursor> {
unsafe {
@@ -135,6 +185,33 @@ impl Cursor {
clang_Cursor_getNumArguments(self.x)
}
}
+
+ // CXX member
+ pub fn access_specifier(&self) -> Enum_CX_CXXAccessSpecifier {
+ unsafe {
+ clang_getCXXAccessSpecifier(self.x)
+ }
+ }
+
+ // CXX method
+ pub fn method_is_static(&self) -> bool {
+ unsafe {
+ clang_CXXMethod_isStatic(self.x) != 0
+ }
+ }
+
+ pub fn method_is_virtual(&self) -> bool {
+ unsafe {
+ clang_CXXMethod_isVirtual(self.x) != 0
+ }
+ }
+
+ // CXX base
+ pub fn is_virtual_base(&self) -> bool {
+ unsafe {
+ clang_isVirtualBase(self.x) != 0
+ }
+ }
}
extern fn visit_children(cur: CXCursor, parent: CXCursor,
@@ -184,6 +261,12 @@ impl Type {
}
}
+ pub fn spelling(&self) -> String {
+ unsafe {
+ String_ { x: clang_getTypeSpelling(self.x) }.to_string()
+ }
+ }
+
pub fn is_const(&self) -> bool {
unsafe {
clang_isConstQualifiedType(self.x) == 1
@@ -204,6 +287,18 @@ impl Type {
}
}
+ pub fn num_template_args(&self) -> c_int {
+ unsafe {
+ clang_Type_getNumTemplateArguments(self.x)
+ }
+ }
+
+ pub fn template_arg_type(&self, i: c_int) -> Type {
+ unsafe {
+ Type { x: clang_Type_getTemplateArgumentAsType(self.x, i) }
+ }
+ }
+
// pointer
pub fn pointee_type(&self) -> Type {
unsafe {
@@ -291,6 +386,56 @@ impl fmt::Display for SourceLocation {
}
}
+// Comment
+pub struct Comment {
+ x: CXComment
+}
+
+impl Comment {
+ pub fn kind(&self) -> Enum_CXCommentKind {
+ unsafe {
+ clang_Comment_getKind(self.x)
+ }
+ }
+
+ pub fn num_children(&self) -> c_uint {
+ unsafe {
+ clang_Comment_getNumChildren(self.x)
+ }
+ }
+
+ pub fn get_child(&self, idx: c_uint) -> Comment {
+ unsafe {
+ Comment { x: clang_Comment_getChild(self.x, idx) }
+ }
+ }
+
+ // HTML
+ pub fn get_tag_name(&self) -> String {
+ unsafe {
+ String_ { x: clang_HTMLTagComment_getTagName(self.x) }.to_string()
+ }
+ }
+
+ pub fn get_num_tag_attrs(&self) -> c_uint {
+ unsafe {
+ clang_HTMLStartTag_getNumAttrs(self.x)
+ }
+ }
+
+ pub fn get_tag_attr_name(&self, idx: c_uint) -> String {
+ unsafe {
+ String_ { x: clang_HTMLStartTag_getAttrName(self.x, idx) }.to_string()
+ }
+ }
+
+ pub fn get_tag_attr_value(&self, idx: c_uint) -> String {
+ unsafe {
+ String_ { x: clang_HTMLStartTag_getAttrValue(self.x, idx) }.to_string()
+ }
+ }
+}
+
// File
pub struct File {
x: CXFile
@@ -320,7 +465,7 @@ impl fmt::Display for String_ {
unsafe {
let c_str = clang_getCString(self.x) as *const c_char;
let p = c_str as *const _;
- str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned().fmt(f)
+ f.write_str(&String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()))
}
}
}
@@ -361,14 +506,13 @@ pub struct TranslationUnit {
impl TranslationUnit {
pub fn parse(ix: &Index, file: &str, cmd_args: &[String],
- unsaved: &[UnsavedFile], opts: c_uint) -> TranslationUnit {
- let fname = CString::new(file.as_bytes()).unwrap();
- let fname = fname.as_ptr();
- let c_args: Vec<CString> = cmd_args.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect();
- let c_args: Vec<*const c_char> = c_args.iter().map(|s| s.as_ptr()).collect();
+ unsaved: &[UnsavedFile], opts: ::libc::c_uint) -> TranslationUnit {
+ let fname = CString::new(file).unwrap();
+ let _c_args: Vec<CString> = cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect();
+ let c_args: Vec<*const c_char> = _c_args.iter().map(|s| s.as_ptr()).collect();
let mut c_unsaved: Vec<Struct_CXUnsavedFile> = unsaved.iter().map(|f| f.x).collect();
let tu = unsafe {
- clang_parseTranslationUnit(ix.x, fname,
+ clang_parseTranslationUnit(ix.x, fname.as_ptr(),
c_args.as_ptr(),
c_args.len() as c_int,
c_unsaved.as_mut_ptr(),
@@ -478,8 +622,8 @@ pub struct UnsavedFile {
impl UnsavedFile {
pub fn new(name: &str, contents: &str) -> UnsavedFile {
- let name = CString::new(name.as_bytes()).unwrap();
- let contents = CString::new(contents.as_bytes()).unwrap();
+ let name = CString::new(name).unwrap();
+ let contents = CString::new(contents).unwrap();
let x = Struct_CXUnsavedFile {
Filename: name.as_ptr(),
Contents: contents.as_ptr(),
@@ -729,7 +873,7 @@ pub fn ast_dump(c: &Cursor, depth: isize)-> Enum_CXVisitorResult {
print_indent(depth, &format!("({} {} {}",
kind_to_str(c.kind()),
c.spelling(),
- type_to_str(ct))[..]
+ type_to_str(ct))
);
c.visit(| s, _: &Cursor| {
ast_dump(s, depth + 1)
diff --git a/src/clangll.rs b/src/clangll.rs
index 208df235..bd1652f0 100644
--- a/src/clangll.rs
+++ b/src/clangll.rs
@@ -328,12 +328,17 @@ pub struct CXComment {
pub ASTNode: *const c_void,
pub TranslationUnit: CXTranslationUnit,
}
-pub type Enum_CXLinkageKind = c_uint;
-pub const CXLinkage_Invalid: c_uint = 0;
-pub const CXLinkage_NoLinkage: c_uint = 1;
-pub const CXLinkage_Internal: c_uint = 2;
-pub const CXLinkage_UniqueExternal: c_uint = 3;
-pub const CXLinkage_External: c_uint = 4;
+pub type Enum_CXLinkageKind = ::libc::c_uint;
+pub const CXLinkage_Invalid: ::libc::c_uint = 0;
+pub const CXLinkage_NoLinkage: ::libc::c_uint = 1;
+pub const CXLinkage_Internal: ::libc::c_uint = 2;
+pub const CXLinkage_UniqueExternal: ::libc::c_uint = 3;
+pub const CXLinkage_External: ::libc::c_uint = 4;
+pub type Enum_CXVisibilityKind = ::libc::c_uint;
+pub const CXVisibility_Invalid: ::libc::c_uint = 0;
+pub const CXVisibility_Hidden: ::libc::c_uint = 1;
+pub const CXVisibility_Protected: ::libc::c_uint = 2;
+pub const CXVisibility_Default: ::libc::c_uint = 3;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Struct_CXPlatformAvailability {
@@ -1005,6 +1010,7 @@ extern "C" {
pub fn clang_isPreprocessing(arg1: Enum_CXCursorKind) -> c_uint;
pub fn clang_isUnexposed(arg1: Enum_CXCursorKind) -> c_uint;
pub fn clang_getCursorLinkage(cursor: CXCursor) -> Enum_CXLinkageKind;
+ pub fn clang_getCursorVisibility(cursor: CXCursor) -> Enum_CXVisibilityKind;
pub fn clang_getCursorAvailability(cursor: CXCursor) ->
Enum_CXAvailabilityKind;
pub fn clang_getCursorPlatformAvailability(cursor: CXCursor,
@@ -1081,8 +1087,11 @@ extern "C" {
c_longlong;
pub fn clang_Type_getCXXRefQualifier(T: CXType) ->
Enum_CXRefQualifierKind;
- pub fn clang_Cursor_isBitField(C: CXCursor) -> c_uint;
- pub fn clang_isVirtualBase(arg1: CXCursor) -> c_uint;
+ pub fn clang_Type_getNumTemplateArguments(T: CXType) -> ::libc::c_int;
+ pub fn clang_Type_getTemplateArgumentAsType(T: CXType, i: ::libc::c_int) ->
+ CXType;
+ pub fn clang_Cursor_isBitField(C: CXCursor) -> ::libc::c_uint;
+ pub fn clang_isVirtualBase(arg1: CXCursor) -> ::libc::c_uint;
pub fn clang_getCXXAccessSpecifier(arg1: CXCursor) ->
Enum_CX_CXXAccessSpecifier;
pub fn clang_getNumOverloadedDecls(cursor: CXCursor) -> c_uint;
@@ -1130,6 +1139,7 @@ extern "C" {
pub fn clang_Cursor_getCommentRange(C: CXCursor) -> CXSourceRange;
pub fn clang_Cursor_getRawCommentText(C: CXCursor) -> CXString;
pub fn clang_Cursor_getBriefCommentText(C: CXCursor) -> CXString;
+ pub fn clang_Cursor_getMangling(C: CXCursor) -> CXString;
pub fn clang_Cursor_getParsedComment(C: CXCursor) -> CXComment;
pub fn clang_Cursor_getModule(C: CXCursor) -> CXModule;
pub fn clang_Module_getASTFile(Module: CXModule) -> CXFile;
diff --git a/src/gen.rs b/src/gen.rs
index da55ca72..93d2c989 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -3,9 +3,7 @@ use std::cell::RefCell;
use std::vec::Vec;
use std::rc::Rc;
use std::collections::HashMap;
-use std::collections::hash_map::Entry;
-
-use syntax::abi;
+use syntax::abi::Abi;
use syntax::ast;
use syntax::codemap::{Span, Spanned, respan, ExpnInfo, NameAndSpan, MacroBang};
use syntax::ext::base;
@@ -15,18 +13,45 @@ use syntax::ext::quote::rt::ToTokens;
use syntax::feature_gate::Features;
use syntax::owned_slice::OwnedSlice;
use syntax::parse;
-use syntax::parse::token::InternedString;
+use syntax::parse::token::{InternedString, intern};
use syntax::attr::mk_attr_id;
use syntax::ptr::P;
use syntax::print::pprust::tts_to_string;
-use super::{BindgenOptions, LinkType};
+use super::BindgenOptions;
+use super::LinkType;
use types::*;
struct GenCtx<'r> {
ext_cx: base::ExtCtxt<'r>,
- unnamed_ty: usize,
- span: Span
+ options: BindgenOptions,
+ span: Span,
+ module_map: ModuleMap,
+ current_module_id: ModuleId,
+}
+
+impl<'r> GenCtx<'r> {
+ fn full_path_for_module(&self, id: ModuleId) -> Vec<String> {
+ if !self.options.enable_cxx_namespaces {
+ return vec![];
+ }
+
+ let mut ret = vec![];
+
+ let mut current_id = Some(id);
+ while let Some(current) = current_id {
+ let module = &self.module_map.get(&current).unwrap();
+ ret.push(module.name.clone());
+ current_id = module.parent_id;
+ }
+
+ if self.current_module_id == ROOT_MODULE_ID {
+ ret.pop(); // The root module doens'n need a root:: in the pattern
+ }
+
+ ret.reverse();
+ ret
+ }
}
fn first<A, B>((val, _): (A, B)) -> A {
@@ -37,11 +62,6 @@ fn ref_eq<T>(thing: &T, other: &T) -> bool {
(thing as *const T) == (other as *const T)
}
-fn to_intern_str(ctx: &mut GenCtx, s: String) -> parse::token::InternedString {
- let id = ctx.ext_cx.ident_of(&s[..]);
- id.name.as_str()
-}
-
fn empty_generics() -> ast::Generics {
ast::Generics {
lifetimes: Vec::new(),
@@ -53,73 +73,191 @@ fn empty_generics() -> ast::Generics {
}
}
-fn rust_id(ctx: &mut GenCtx, name: String) -> (String, bool) {
- let token = parse::token::Ident(ctx.ext_cx.ident_of(&name[..]), parse::token::Plain);
- if token.is_any_keyword() || "bool" == &name[..] {
- let mut s = "_".to_owned();
- s.push_str(&name[..]);
+fn rust_id(ctx: &mut GenCtx, name: &str) -> (String, bool) {
+ let token = parse::token::Ident(ctx.ext_cx.ident_of(name), parse::token::Plain);
+ if token.is_any_keyword() || "bool" == name {
+ let mut s = "_".to_string();
+ s.push_str(name);
(s, true)
} else {
- (name, false)
+ (name.to_owned(), false)
}
}
-fn rust_type_id(ctx: &mut GenCtx, name: String) -> String {
- if "bool" == &name[..] ||
- "uint" == &name[..] ||
- "u8" == &name[..] ||
- "u16" == &name[..] ||
- "u32" == &name[..] ||
- "f32" == &name[..] ||
- "f64" == &name[..] ||
- "i8" == &name[..] ||
- "i16" == &name[..] ||
- "i32" == &name[..] ||
- "i64" == &name[..] ||
- "Self" == &name[..] ||
- "str" == &name[..] {
- let mut s = "_".to_owned();
- s.push_str(&name[..]);
- s
- } else {
- let (n, _) = rust_id(ctx, name);
- n
+fn rust_type_id(ctx: &mut GenCtx, name: &str) -> String {
+ match name {
+ "bool" | "uint" | "u8" | "u16" |
+ "u32" | "f32" | "f64" | "i8" |
+ "i16" | "i32" | "i64" | "Self" |
+ "str" => {
+ let mut s = "_".to_string();
+ s.push_str(name);
+ s
+ }
+ _ => first(rust_id(ctx, name))
}
}
-fn unnamed_name(ctx: &mut GenCtx, name: String) -> String {
- if name.is_empty() {
- ctx.unnamed_ty += 1;
- format!("Unnamed{}", ctx.unnamed_ty)
- } else {
- name
+fn comp_name(ctx: &GenCtx, kind: CompKind, name: &str) -> String {
+ match kind {
+ CompKind::Struct => struct_name(ctx, name),
+ CompKind::Union => union_name(ctx, name),
}
}
-fn comp_name(kind: CompKind, name: &str) -> String {
- match kind {
- CompKind::Struct => struct_name(name),
- CompKind::Union => union_name(name),
+fn struct_name(ctx: &GenCtx, name: &str) -> String {
+ if ctx.options.rename_types {
+ format!("Struct_{}", name)
+ } else {
+ name.to_owned()
}
}
-fn struct_name(name: &str) -> String {
- format!("Struct_{}", name)
+fn union_name(ctx: &GenCtx, name: &str) -> String {
+ if ctx.options.rename_types {
+ format!("Union_{}", name)
+ } else {
+ name.to_owned()
+ }
}
-fn union_name(name: &str) -> String {
- format!("Union_{}", name)
+fn enum_name(ctx: &GenCtx, name: &str) -> String {
+ if ctx.options.rename_types {
+ format!("Enum_{}", name)
+ } else {
+ name.to_owned()
+ }
}
-fn enum_name(name: &str) -> String {
- format!("Enum_{}", name)
+fn gen_unmangle_method(ctx: &mut GenCtx,
+ v: &VarInfo,
+ counts: &mut HashMap<String, isize>,
+ self_kind: ast::SelfKind)
+ -> ast::ImplItem {
+ let fndecl;
+ let mut args = vec!();
+
+ match self_kind {
+ ast::SelfKind::Static => (),
+ ast::SelfKind::Region(_, mutable, _) => {
+ let selfexpr = match mutable {
+ ast::Mutability::Immutable => quote_expr!(&ctx.ext_cx, &*self),
+ ast::Mutability::Mutable => quote_expr!(&ctx.ext_cx, &mut *self),
+ };
+ args.push(selfexpr);
+ },
+ _ => unreachable!()
+ }
+
+ match v.ty {
+ TFuncPtr(ref sig) => {
+ fndecl = cfuncty_to_rs(ctx,
+ &*sig.ret_ty, sig.args.as_slice(),
+ false);
+ let mut unnamed: usize = 0;
+ let iter = if args.len() > 0 {
+ sig.args[1..].iter()
+ } else {
+ sig.args.iter()
+ };
+ for arg in iter {
+ let (ref n, _) = *arg;
+ let argname = if n.is_empty() {
+ unnamed += 1;
+ format!("arg{}", unnamed)
+ } else {
+ first(rust_id(ctx, &n))
+ };
+ let expr = ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ExprKind::Path(None, ast::Path {
+ span: ctx.span,
+ global: false,
+ segments: vec!(ast::PathSegment {
+ identifier: ctx.ext_cx.ident_of(&argname),
+ parameters: ast::PathParameters::none()
+ })
+ }),
+ span: ctx.span,
+ attrs: None,
+ };
+ args.push(P(expr));
+ }
+ },
+ _ => unreachable!()
+ };
+
+ let sig = ast::MethodSig {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: Abi::Rust,
+ decl: P(fndecl),
+ generics: empty_generics(),
+ explicit_self: respan(ctx.span, self_kind),
+ constness: ast::Constness::NotConst,
+ };
+
+ let block = ast::Block {
+ stmts: vec!(),
+ expr: Some(P(ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ExprKind::Call(
+ P(ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ExprKind::Path(None, ast::Path {
+ span: ctx.span,
+ global: false,
+ segments: vec!(ast::PathSegment {
+ identifier: ctx.ext_cx.ident_of(&v.mangled),
+ parameters: ast::PathParameters::none()
+ })
+ }),
+ span: ctx.span,
+ attrs: None,
+ }),
+ args
+ ),
+ span: ctx.span,
+ attrs: None,
+ })),
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::BlockCheckMode::Default,
+ span: ctx.span
+ };
+
+ let mut name = v.name.clone();
+ let mut count = 0;
+ match counts.get(&v.name) {
+ Some(x) => {
+ count = *x;
+ name.push_str(&x.to_string());
+ },
+ None => ()
+ }
+ count += 1;
+ counts.insert(v.name.clone(), count);
+
+ let mut attrs = mk_doc_attr(ctx, &v.comment);
+ attrs.push(respan(ctx.span, ast::Attribute_ {
+ id: mk_attr_id(),
+ style: ast::AttrStyle::Outer,
+ value: P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("inline")))),
+ is_sugared_doc: false
+ }));
+
+ ast::ImplItem {
+ id: ast::DUMMY_NODE_ID,
+ ident: ctx.ext_cx.ident_of(&name),
+ vis: ast::Visibility::Public,
+ attrs: attrs,
+ node: ast::ImplItemKind::Method(sig, P(block)),
+ span: ctx.span
+ }
}
-pub fn gen_mod(
- options: &BindgenOptions,
- globs: Vec<Global>,
- span: Span)
- -> Vec<P<ast::Item>> {
+pub fn gen_mods(links: &[(String, LinkType)],
+ map: ModuleMap,
+ options: BindgenOptions,
+ span: Span) -> Vec<P<ast::Item>> {
// Create a dummy ExtCtxt. We only need this for string interning and that uses TLS.
let mut features = Features::new();
features.allow_quote = true;
@@ -130,25 +268,132 @@ pub fn gen_mod(
trace_mac: false,
};
let sess = &parse::ParseSess::new();
- let mut feature_gated_cfgs = Vec::new();
+ let mut feature_gated_cfgs = vec![];
let mut ctx = GenCtx {
- ext_cx: base::ExtCtxt::new(
- sess,
- Vec::new(),
- cfg,
- &mut feature_gated_cfgs,
- ),
- unnamed_ty: 0,
- span: span
+ ext_cx: base::ExtCtxt::new(sess, Vec::new(), cfg, &mut feature_gated_cfgs),
+ options: options,
+ span: span,
+ module_map: map,
+ current_module_id: ROOT_MODULE_ID,
};
+
ctx.ext_cx.bt_push(ExpnInfo {
call_site: ctx.span,
callee: NameAndSpan {
- format: MacroBang(parse::token::intern("")),
+ format: MacroBang(intern("")),
allow_internal_unstable: false,
span: None
}
});
+
+ if let Some(root_mod) = gen_mod(&mut ctx, ROOT_MODULE_ID, links, span) {
+ if !ctx.options.enable_cxx_namespaces {
+ match root_mod.node {
+ // XXX This clone might be really expensive, but doing:
+ // ast::ItemMod(ref mut root) => {
+ // return ::std::mem::replace(&mut root.items, vec![]);
+ // }
+ // fails with "error: cannot borrow immutable anonymous field as mutable".
+ // So...
+ ast::ItemKind::Mod(ref root) => {
+ return root.items.clone()
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ let root_export = P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec![],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Use(P(
+ Spanned {
+ node: ast::ViewPathGlob(ast::Path {
+ span: span.clone(),
+ global: false,
+ segments: vec![ast::PathSegment {
+ identifier: root_mod.ident,
+ parameters: ast::PathParameters::none(),
+ }]
+ }),
+ span: span.clone(),
+ })),
+ vis: ast::Visibility::Public,
+ span: span.clone(),
+ });
+
+ vec![root_export, root_mod]
+ } else {
+ vec![]
+ }
+}
+
+fn gen_mod(mut ctx: &mut GenCtx,
+ module_id: ModuleId,
+ links: &[(String, LinkType)],
+ span: Span) -> Option<P<ast::Item>> {
+
+ // XXX avoid this clone
+ let module = ctx.module_map.get(&module_id).unwrap().clone();
+
+ // Import just the root to minimise name conflicts
+ let mut globals = if module_id != ROOT_MODULE_ID {
+ // XXX Pass this previously instead of looking it up always?
+ let root = ctx.ext_cx.ident_of(&ctx.module_map.get(&ROOT_MODULE_ID).unwrap().name);
+ vec![P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec![],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Use(P(
+ Spanned {
+ node: ast::ViewPathSimple(root.clone(),
+ ast::Path {
+ span: span.clone(),
+ global: false,
+ segments: vec![ast::PathSegment {
+ identifier: root,
+ parameters: ast::PathParameters::none(),
+ }]
+ }),
+ span: span.clone(),
+ })),
+ vis: ast::Visibility::Public,
+ span: span.clone(),
+ })]
+ } else {
+ vec![]
+ };
+
+ ctx.current_module_id = module_id;
+
+ globals.extend(gen_globals(&mut ctx, links, &module.globals).into_iter());
+
+ globals.extend(module.children_ids.iter().filter_map(|id| {
+ gen_mod(ctx, *id, links, span.clone())
+ }));
+
+ if !globals.is_empty() {
+ Some(P(ast::Item {
+ ident: ctx.ext_cx.ident_of(&module.name),
+ attrs: vec![],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Mod(ast::Mod {
+ inner: span,
+ items: globals,
+ }),
+ vis: ast::Visibility::Public,
+ span: span.clone(),
+ }))
+ } else {
+ None
+ }
+}
+
+
+
+fn gen_globals(mut ctx: &mut GenCtx,
+ links: &[(String, LinkType)],
+ globs: &[Global]) -> Vec<P<ast::Item>> {
let uniq_globs = tag_dup_decl(globs);
let mut fs = vec!();
@@ -184,70 +429,51 @@ pub fn gen_mod(
for g in gs.into_iter() {
match g {
GType(ti) => {
- let t = ti.borrow();
- defs.extend(ctypedef_to_rs(
- &mut ctx,
- options.rust_enums,
- options.derive_debug,
- t.name.clone(), &t.ty))
+ let t = ti.borrow().clone();
+ defs.push(ctypedef_to_rs(&mut ctx, t))
},
GCompDecl(ci) => {
- {
- let mut c = ci.borrow_mut();
- c.name = unnamed_name(&mut ctx, c.name.clone());
- }
let c = ci.borrow().clone();
- defs.push(opaque_to_rs(&mut ctx, comp_name(c.kind, &c.name)));
+ let name = comp_name(&ctx, c.kind, &c.name);
+
+ defs.push(opaque_to_rs(&mut ctx, &name));
},
GComp(ci) => {
- {
- let mut c = ci.borrow_mut();
- c.name = unnamed_name(&mut ctx, c.name.clone());
- }
let c = ci.borrow().clone();
- defs.extend(comp_to_rs(&mut ctx, c.kind, comp_name(c.kind, &c.name),
- options.derive_debug,
- c.layout, c.members).into_iter())
+ let name = comp_name(&ctx, c.kind, &c.name);
+ defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter())
},
GEnumDecl(ei) => {
- {
- let mut e = ei.borrow_mut();
- e.name = unnamed_name(&mut ctx, e.name.clone());
- }
let e = ei.borrow().clone();
- defs.push(opaque_to_rs(&mut ctx, enum_name(&e.name)));
+ let name = enum_name(&ctx, &e.name);
+
+ defs.push(opaque_to_rs(&mut ctx, &name));
},
GEnum(ei) => {
- {
- let mut e = ei.borrow_mut();
- e.name = unnamed_name(&mut ctx, e.name.clone());
- }
- let e = ei.borrow();
- defs.extend(cenum_to_rs(
- &mut ctx,
- options.rust_enums,
- options.derive_debug,
- enum_name(&e.name), e.kind, e.layout, &e.items));
+ let e = ei.borrow().clone();
+ let name = enum_name(&ctx, &e.name);
+ defs.extend(cenum_to_rs(&mut ctx, name, e.kind, e.comment, &e.items, e.layout).into_iter())
},
GVar(vi) => {
let v = vi.borrow();
- let ty = cty_to_rs(&mut ctx, &v.ty);
+ let ty = cty_to_rs(&mut ctx, &v.ty, v.is_const, true);
defs.push(const_to_rs(&mut ctx, v.name.clone(), v.val.unwrap(), ty));
},
_ => { }
}
}
- let vars = vs.into_iter().map(|v| {
+ let vars: Vec<_> = vs.into_iter().map(|v| {
match v {
GVar(vi) => {
let v = vi.borrow();
- cvar_to_rs(&mut ctx, v.name.clone(), &v.ty, v.is_const)
+ cvar_to_rs(&mut ctx, v.name.clone(), v.mangled.clone(), &v.ty, v.is_const)
},
_ => unreachable!()
}
}).collect();
+ let mut unmangle_count: HashMap<String, isize> = HashMap::new();
let funcs = {
let func_list = fs.into_iter().map(|f| {
match f {
@@ -255,9 +481,21 @@ pub fn gen_mod(
let v = vi.borrow();
match v.ty {
TFuncPtr(ref sig) => {
- let decl = cfunc_to_rs(&mut ctx, v.name.clone(),
+ let mut name = v.name.clone();
+ let mut count = 0;
+ match unmangle_count.get(&v.name) {
+ Some(x) => {
+ count = *x;
+ name.push_str(&x.to_string());
+ },
+ None => ()
+ }
+ count += 1;
+ unmangle_count.insert(v.name.clone(), count);
+
+ let decl = cfunc_to_rs(&mut ctx, name, v.mangled.clone(), v.comment.clone(),
&*sig.ret_ty, &sig.args[..],
- sig.is_variadic);
+ sig.is_variadic, ast::Visibility::Public);
(sig.abi, decl)
}
_ => unreachable!()
@@ -267,26 +505,19 @@ pub fn gen_mod(
}
});
- let mut map: HashMap<abi::Abi, Vec<_>> = HashMap::new();
+ let mut map: HashMap<Abi, Vec<_>> = HashMap::new();
for (abi, func) in func_list {
- match map.entry(abi) {
- Entry::Occupied(mut occ) => {
- occ.get_mut().push(func);
- }
- Entry::Vacant(vac) => {
- vac.insert(vec!(func));
- }
- }
+ map.entry(abi).or_insert(vec![]).push(func);
}
map
};
- if !Vec::is_empty(&vars) {
- defs.push(mk_extern(&mut ctx, &options.links, vars, abi::Abi::C));
+ if !vars.is_empty() {
+ defs.push(mk_extern(&mut ctx, links, vars, Abi::C));
}
for (abi, funcs) in funcs.into_iter() {
- defs.push(mk_extern(&mut ctx, &options.links, funcs, abi));
+ defs.push(mk_extern(&mut ctx, &links, funcs, abi));
}
//let attrs = vec!(mk_attr_list(&mut ctx, "allow", ["dead_code", "non_camel_case_types", "uppercase_variables"]));
@@ -296,44 +527,34 @@ pub fn gen_mod(
fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)],
foreign_items: Vec<ast::ForeignItem>,
- abi: abi::Abi) -> P<ast::Item> {
- let attrs = if links.is_empty() {
- Vec::new()
- } else {
- links.iter().map(|&(ref l, ref k)| {
- let k = match *k {
- LinkType::Default => None,
- LinkType::Static => Some("static"),
- LinkType::Framework => Some("framework")
- };
- let link_name = P(respan(ctx.span, ast::MetaItemKind::NameValue(
- to_intern_str(ctx, "name".to_owned()),
- respan(ctx.span, ast::LitKind::Str(
- to_intern_str(ctx, l.to_owned()),
- ast::StrStyle::Cooked
- ))
- )));
- let link_args = match k {
- None => vec!(link_name),
- Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaItemKind::NameValue(
- to_intern_str(ctx, "kind".to_owned()),
- respan(ctx.span, ast::LitKind::Str(
- to_intern_str(ctx, (*k).to_owned()),
- ast::StrStyle::Cooked
- ))
- ))))
- };
- respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: P(respan(ctx.span, ast::MetaItemKind::List(
- to_intern_str(ctx, "link".to_owned()),
- link_args)
- )),
- is_sugared_doc: false
- })
- }).collect()
- };
+ abi: Abi) -> P<ast::Item> {
+ let attrs: Vec<_> = links.iter().map(|&(ref l, ref k)| {
+ let k = match *k {
+ LinkType::Default => None,
+ LinkType::Static => Some("static"),
+ LinkType::Framework => Some("framework")
+ };
+ let link_name = P(respan(ctx.span, ast::MetaItemKind::NameValue(
+ InternedString::new("name"),
+ respan(ctx.span, ast::LitKind::Str(intern(l).as_str(), ast::StrStyle::Cooked))
+ )));
+ let link_args = match k {
+ None => vec!(link_name),
+ Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaItemKind::NameValue(
+ InternedString::new("kind"),
+ respan(ctx.span, ast::LitKind::Str(intern(k).as_str(), ast::StrStyle::Cooked))
+ ))))
+ };
+ respan(ctx.span, ast::Attribute_ {
+ id: mk_attr_id(),
+ style: ast::AttrStyle::Outer,
+ value: P(respan(ctx.span, ast::MetaItemKind::List(
+ InternedString::new("link"),
+ link_args)
+ )),
+ is_sugared_doc: false
+ })
+ }).collect();
let mut items = Vec::new();
items.extend(foreign_items.into_iter());
@@ -352,6 +573,28 @@ fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)],
})
}
+fn mk_impl(ctx: &mut GenCtx, ty: P<ast::Ty>,
+ items: Vec<ast::ImplItem>)
+ -> P<ast::Item> {
+ let ext = ast::ItemKind::Impl(
+ ast::Unsafety::Normal,
+ ast::ImplPolarity::Positive,
+ empty_generics(),
+ None,
+ ty,
+ items
+ );
+
+ P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec!(),
+ id: ast::DUMMY_NODE_ID,
+ node: ext,
+ vis: ast::Visibility::Inherited,
+ span: ctx.span
+ })
+}
+
fn remove_redundant_decl(gs: Vec<Global>) -> Vec<Global> {
fn check_decl(a: &Global, ty: &Type) -> bool {
match *a {
@@ -383,7 +626,7 @@ fn remove_redundant_decl(gs: Vec<Global>) -> Vec<Global> {
).collect()
}
-fn tag_dup_decl(gs: Vec<Global>) -> Vec<Global> {
+fn tag_dup_decl(gs: &[Global]) -> Vec<Global> {
fn check(name1: &str, name2: &str) -> bool {
!name1.is_empty() && name1 == name2
}
@@ -393,75 +636,118 @@ fn tag_dup_decl(gs: Vec<Global>) -> Vec<Global> {
(&GType(ref ti1), &GType(ref ti2)) => {
let a = ti1.borrow();
let b = ti2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GComp(ref ci1), &GComp(ref ci2)) => {
let a = ci1.borrow();
let b = ci2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GCompDecl(ref ci1), &GCompDecl(ref ci2)) => {
let a = ci1.borrow();
let b = ci2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GEnum(ref ei1), &GEnum(ref ei2)) => {
let a = ei1.borrow();
let b = ei2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GEnumDecl(ref ei1), &GEnumDecl(ref ei2)) => {
let a = ei1.borrow();
let b = ei2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GVar(ref vi1), &GVar(ref vi2)) => {
let a = vi1.borrow();
let b = vi2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name) &&
+ check(&a.mangled, &b.mangled)
},
(&GFunc(ref vi1), &GFunc(ref vi2)) => {
let a = vi1.borrow();
let b = vi2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name) &&
+ check(&a.mangled, &b.mangled)
},
_ => false
}
}
+ fn check_opaque_dup(g1: &Global, g2: &Global) -> bool {
+ match (g1, g2) {
+ (&GCompDecl(ref ci1), &GComp(ref ci2)) => {
+ let a = ci1.borrow();
+ let b = ci2.borrow();
+ check(&a.name, &b.name)
+ },
+ (&GEnumDecl(ref ei1), &GEnum(ref ei2)) => {
+ let a = ei1.borrow();
+ let b = ei2.borrow();
+ check(&a.name, &b.name)
+ },
+ _ => false,
+ }
+ }
+
if gs.is_empty() {
- return gs;
+ return vec![];
}
- let mut res: Vec<Global> = vec!();
- res.push(gs[0].clone());
+ let mut step: Vec<Global> = vec!();
+ step.push(gs[0].clone());
- for (i, gsi) in gs.iter().enumerate().skip(1) {
+ for (i, _gsi) in gs.iter().enumerate().skip(1) {
let mut dup = false;
- for gsj in gs.iter().take(i) {
- if check_dup(&gsi, &gsj) {
+ for j in 0..i {
+ if i == j {
+ continue;
+ }
+ if check_dup(&gs[i], &gs[j]) {
dup = true;
break;
}
}
if !dup {
- res.push(gsi.clone());
+ step.push(gs[i].clone());
+ }
+ }
+
+ let len = step.len();
+ let mut res: Vec<Global> = vec!();
+ for i in 0..len {
+ let mut dup = false;
+ match &step[i] {
+ &GCompDecl(_) | &GEnumDecl(_) => {
+ for j in 0..len {
+ if i == j {
+ continue;
+ }
+ if check_opaque_dup(&step[i], &step[j]) {
+ dup = true;
+ break;
+ }
+ }
+ },
+ _ => (),
+ }
+
+ if !dup {
+ res.push(step[i].clone());
}
}
res
}
-fn ctypedef_to_rs(
- ctx: &mut GenCtx,
- rust_enums: bool,
- derive_debug: bool,
- name: String,
- ty: &Type)
- -> Vec<P<ast::Item>> {
- fn mk_item(ctx: &mut GenCtx, name: String, ty: &Type) -> P<ast::Item> {
+fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> P<ast::Item> {
+ fn mk_item(ctx: &mut GenCtx, name: &str, comment: &str, ty: &Type) -> P<ast::Item> {
let rust_name = rust_type_id(ctx, name);
- let rust_ty = cty_to_rs(ctx, ty);
+ let rust_ty = if cty_is_translatable(ty) {
+ cty_to_rs(ctx, ty, true, true)
+ } else {
+ cty_to_rs(ctx, &TVoid, true, true)
+ };
let base = ast::ItemKind::Ty(
P(ast::Ty {
id: ast::DUMMY_NODE_ID,
@@ -472,8 +758,8 @@ fn ctypedef_to_rs(
);
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&rust_name[..]),
- attrs: Vec::new(),
+ ident: ctx.ext_cx.ident_of(&rust_name),
+ attrs: mk_doc_attr(ctx, comment),
id: ast::DUMMY_NODE_ID,
node: base,
vis: ast::Visibility::Public,
@@ -481,43 +767,32 @@ fn ctypedef_to_rs(
})
}
- match *ty {
+ match ty.ty {
TComp(ref ci) => {
- let is_empty = ci.borrow().name.is_empty();
- if is_empty {
- ci.borrow_mut().name = name.clone();
- let c = ci.borrow().clone();
- comp_to_rs(ctx, c.kind, name, derive_debug, c.layout, c.members)
- } else {
- vec!(mk_item(ctx, name, ty))
- }
+ assert!(!ci.borrow().name.is_empty());
+ mk_item(ctx, &ty.name, &ty.comment, &ty.ty)
},
TEnum(ref ei) => {
- let is_empty = ei.borrow().name.is_empty();
- if is_empty {
- ei.borrow_mut().name = name.clone();
- let e = ei.borrow();
- cenum_to_rs(ctx, rust_enums, derive_debug, name, e.kind, e.layout, &e.items)
- } else {
- vec!(mk_item(ctx, name, ty))
- }
+ assert!(!ei.borrow().name.is_empty());
+ mk_item(ctx, &ty.name, &ty.comment, &ty.ty)
},
- _ => vec!(mk_item(ctx, name, ty))
+ _ => mk_item(ctx, &ty.name, &ty.comment, &ty.ty),
}
}
-fn comp_to_rs(ctx: &mut GenCtx, kind: CompKind, name: String,
- derive_debug: bool,
- layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
- match kind {
- CompKind::Struct => cstruct_to_rs(ctx, name, derive_debug, layout, members),
- CompKind::Union => cunion_to_rs(ctx, name, derive_debug, layout, members),
+fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo)
+ -> Vec<P<ast::Item>> {
+ match ci.kind {
+ CompKind::Struct => cstruct_to_rs(ctx, name, ci),
+ CompKind::Union => cunion_to_rs(ctx, name, ci.layout, ci.members),
}
}
-fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
- derive_debug: bool,
- layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
+fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> {
+ let layout = ci.layout;
+ let members = &ci.members;
+ let template_args = &ci.args;
+ let methodlist = &ci.methods;
let mut fields = vec!();
let mut methods = vec!();
// Nested composites may need to emit declarations and implementations as
@@ -527,40 +802,198 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
let mut unnamed: u32 = 0;
let mut bitfields: u32 = 0;
- // Debug is only defined on little arrays
- let mut can_derive_debug = derive_debug;
+ if ci.hide ||
+ template_args.iter().any(|f| f == &TVoid) {
+ return vec!();
+ }
- for m in &members {
- let (opt_rc_c, opt_f) = match *m {
- CompMember::Field(ref f) => { (None, Some(f)) }
- CompMember::Comp(ref rc_c) => { (Some(rc_c), None) }
- CompMember::CompField(ref rc_c, ref f) => { (Some(rc_c), Some(f)) }
+ let id = rust_type_id(ctx, name);
+ let id_ty = P(mk_ty(ctx, false, &[id.clone()]));
+
+ if ci.has_vtable {
+ let mut vffields = vec!();
+ let base_vftable = if !members.is_empty() {
+ if let CompMember::Field(ref fi) = members[0] {
+ match fi.ty {
+ TComp(ref ci2) => {
+ let ci2 = ci2.borrow();
+ if ci2.has_vtable {
+ Some(format!("_vftable_{}", ci2.name))
+ } else {
+ None
+ }
+ },
+ _ => None
+ }
+ } else {
+ None
+ }
+ } else {
+ None
};
+ if let Some(ref base) = base_vftable {
+ let field = ast::StructField_ {
+ kind: ast::NamedField(ctx.ext_cx.ident_of("_base"), ast::Visibility::Public),
+ id: ast::DUMMY_NODE_ID,
+ ty: P(mk_ty(ctx, false, &[base.clone()])),
+ attrs: vec!(),
+ };
+ vffields.push(respan(ctx.span, field));
+ }
+
+ for vm in ci.vmethods.iter() {
+ let ty = match vm.ty {
+ TFuncPtr(ref sig) => {
+ let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, sig.args.as_slice(), sig.is_variadic);
+ mk_fn_proto_ty(ctx, &decl, sig.abi)
+ },
+ _ => unreachable!()
+ };
+ let field = ast::StructField_ {
+ kind: ast::NamedField(ctx.ext_cx.ident_of(&vm.name), ast::Visibility::Public),
+ id: ast::DUMMY_NODE_ID,
+ ty: P(ty),
+ attrs: vec!(),
+ };
+ vffields.push(respan(ctx.span, field));
+ }
+
+ let vf_name = format!("_vftable_{}", name);
+ let item = P(ast::Item {
+ ident: ctx.ext_cx.ident_of(&vf_name),
+ attrs: vec!(mk_repr_attr(ctx, layout)),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Struct(
+ ast::VariantData::Struct(vffields, ast::DUMMY_NODE_ID),
+ empty_generics()
+ ),
+ vis: ast::Visibility::Public,
+ span: ctx.span,
+ });
+ extra.push(item);
+
+ if base_vftable.is_none() {
+ let vf_type = mk_ty(ctx, false, &[vf_name]);
+ fields.push(respan(ctx.span, ast::StructField_ {
+ kind: ast::NamedField(ctx.ext_cx.ident_of("_vftable"), ast::Visibility::Public),
+ id: ast::DUMMY_NODE_ID,
+ ty: P(mk_ptrty(ctx, &vf_type, true)),
+ attrs: Vec::new()
+ }));
+ }
+ }
+
+ if members.is_empty() {
+ let mut phantom_count = 0;
+ for arg in template_args {
+ let f_name = format!("_phantom{}", phantom_count);
+ phantom_count += 1;
+ let inner_type = P(cty_to_rs(ctx, &arg, true, false));
+ fields.push(respan(ctx.span, ast::StructField_ {
+ kind: ast::NamedField(
+ ctx.ext_cx.ident_of(&f_name),
+ ast::Visibility::Public,
+ ),
+ id: ast::DUMMY_NODE_ID,
+ ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>),
+ attrs: vec!(),
+ }));
+ }
+ }
+
+ let mut anon_enum_count = 0;
+ let mut setters = vec!();
+ let mut has_destructor = ci.has_destructor;
+ for m in members.iter() {
+ if let &CompMember::Enum(ref ei) = m {
+ let e = ei.borrow().clone();
+ let ename = if e.name.is_empty() {
+ let ename = format!("{}_enum{}", name, anon_enum_count);
+ anon_enum_count += 1;
+ ename
+ } else {
+ e.name.clone()
+ };
+ extra.extend(cenum_to_rs(ctx, ename, e.kind, e.comment, &e.items, e.layout).into_iter());
+ continue;
+ }
+
+ fn comp_fields(m: &CompMember)
+ -> (Option<Rc<RefCell<CompInfo>>>, Option<FieldInfo>) {
+ match m {
+ &CompMember::Field(ref f) => { (None, Some(f.clone())) }
+ &CompMember::Comp(ref rc_c) => {
+ let c = rc_c.borrow();
+ if c.members.len() == 1 {
+ comp_fields(&c.members[0])
+ } else {
+ (Some(rc_c.clone()), None)
+ }
+ }
+ &CompMember::CompField(ref rc_c, ref f) => { (Some(rc_c.clone()), Some(f.clone())) }
+ _ => unreachable!()
+ }
+ }
+
+ let (opt_rc_c, opt_f) = comp_fields(m);
+
if let Some(f) = opt_f {
+ if cty_has_destructor(&f.ty) {
+ has_destructor = true;
+ }
+ if !cty_is_translatable(&f.ty) {
+ continue;
+ }
let f_name = match f.bitfields {
Some(_) => {
bitfields += 1;
- format!("_bindgen_bitfield_{}_", bitfields)
+ format!("_bitfield_{}", bitfields)
}
- None => rust_type_id(ctx, f.name.clone())
+ None => rust_type_id(ctx, &f.name)
};
- if !f.ty.can_derive_debug() {
- can_derive_debug = false;
+ let mut offset: u32 = 0;
+ if let Some(ref bitfields) = f.bitfields {
+ for &(ref bf_name, bf_size) in bitfields.iter() {
+ setters.push(gen_bitfield_method(ctx, &f_name, bf_name, &f.ty, offset as usize, bf_size));
+ offset += bf_size;
+ }
+ setters.push(gen_fullbitfield_method(ctx, &f_name, &f.ty, bitfields))
}
- let f_ty = P(cty_to_rs(ctx, &f.ty));
+ let mut bypass = false;
+ let f_ty = if let Some(ref rc_c) = opt_rc_c {
+ if rc_c.borrow().members.len() == 1 {
+ if let CompMember::Field(ref inner_f) = rc_c.borrow().members[0] {
+ bypass = true;
+ inner_f.ty.clone()
+ } else {
+ f.ty.clone()
+ }
+ } else {
+ f.ty.clone()
+ }
+ } else {
+ f.ty.clone()
+ };
+
+ // If the member is not a template argument, it needs the full path.
+ let needs_full_path = !template_args.iter().any(|arg| *arg == f_ty);
+ let f_ty = P(cty_to_rs(ctx, &f_ty, f.bitfields.is_none(), needs_full_path));
fields.push(respan(ctx.span, ast::StructField_ {
kind: ast::NamedField(
- ctx.ext_cx.ident_of(&f_name[..]),
+ ctx.ext_cx.ident_of(&f_name),
ast::Visibility::Public,
),
id: ast::DUMMY_NODE_ID,
ty: f_ty,
- attrs: Vec::new()
+ attrs: mk_doc_attr(ctx, &f.comment)
}));
+ if bypass {
+ continue;
+ }
}
if let Some(rc_c) = opt_rc_c {
@@ -568,47 +1001,92 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
if c.name.is_empty() {
unnamed += 1;
let field_name = format!("_bindgen_data_{}_", unnamed);
- fields.push(mk_blob_field(ctx, &field_name[..], c.layout));
- methods.extend(gen_comp_methods(ctx, &field_name[..], 0, c.kind, &c.members, &mut extra, derive_debug).into_iter());
+ fields.push(mk_blob_field(ctx, &field_name, c.layout));
+ methods.extend(gen_comp_methods(ctx, &field_name, 0, c.kind, &c.members, &mut extra).into_iter());
} else {
- extra.extend(comp_to_rs(ctx, c.kind, comp_name(c.kind, &c.name),
- derive_debug,
- c.layout, c.members.clone()).into_iter());
+ let name = comp_name(&ctx, c.kind, &c.name);
+ extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter());
}
}
}
+ if !setters.is_empty() {
+ extra.push(P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec!(),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Impl(
+ ast::Unsafety::Normal,
+ ast::ImplPolarity::Positive,
+ empty_generics(),
+ None,
+ id_ty.clone(),
+ setters
+ ),
+ vis: ast::Visibility::Inherited,
+ span: ctx.span
+ }));
+ }
+
+ let variant_data = if fields.is_empty() {
+ ast::VariantData::Unit(ast::DUMMY_NODE_ID)
+ } else {
+ ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID)
+ };
+ let ty_params = template_args.iter().map(|gt| {
+ let name = match gt {
+ &TNamed(ref ti) => {
+ ctx.ext_cx.ident_of(&ti.borrow().name)
+ },
+ _ => ctx.ext_cx.ident_of("")
+ };
+ ast::TyParam {
+ ident: name,
+ id: ast::DUMMY_NODE_ID,
+ bounds: OwnedSlice::empty(),
+ default: None,
+ span: ctx.span
+ }
+ }).collect();
let def = ast::ItemKind::Struct(
- ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID),
- empty_generics()
+ variant_data,
+ ast::Generics {
+ lifetimes: vec!(),
+ ty_params: OwnedSlice::from_vec(ty_params),
+ where_clause: ast::WhereClause {
+ id: ast::DUMMY_NODE_ID,
+ predicates: vec!()
+ }
+ }
);
- let id = rust_type_id(ctx, name.clone());
- let mut attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false));
- if can_derive_debug {
- attrs.push(mk_deriving_debug_attr(ctx));
+ let mut attrs = mk_doc_attr(ctx, &ci.comment);
+ attrs.push(mk_repr_attr(ctx, layout));
+ if !has_destructor {
+ attrs.push(mk_deriving_copy_attr(ctx));
}
- let struct_def = P(ast::Item { ident: ctx.ext_cx.ident_of(&id[..]),
+ let struct_def = ast::Item {
+ ident: ctx.ext_cx.ident_of(&id),
attrs: attrs,
id: ast::DUMMY_NODE_ID,
node: def,
vis: ast::Visibility::Public,
span: ctx.span
- });
+ };
- let mut items = vec!(struct_def);
+ let mut items = vec!(P(struct_def));
if !methods.is_empty() {
let impl_ = ast::ItemKind::Impl(
ast::Unsafety::Normal,
ast::ImplPolarity::Positive,
empty_generics(),
None,
- P(mk_ty(ctx, false, vec!(id))),
+ id_ty.clone(),
methods
);
items.push(
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&name[..]),
+ ident: ctx.ext_cx.ident_of(&name),
attrs: vec!(),
id: ast::DUMMY_NODE_ID,
node: impl_,
@@ -616,13 +1094,39 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
span: ctx.span}));
}
- items.push(mk_clone_impl(ctx, &name[..]));
- items.push(mk_default_impl(ctx, &name[..]));
items.extend(extra.into_iter());
+
+ let mut mangledlist = vec!();
+ let mut unmangledlist = vec!();
+ let mut unmangle_count: HashMap<String, isize> = HashMap::new();
+ for v in methodlist {
+ let v = v.clone();
+ match v.ty {
+ TFuncPtr(ref sig) => {
+ let name = v.mangled.clone();
+ let explicit_self = if v.is_static {
+ ast::SelfKind::Static
+ } else if v.is_const {
+ ast::SelfKind::Region(None, ast::Mutability::Immutable, ctx.ext_cx.ident_of("self"))
+ } else {
+ ast::SelfKind::Region(None, ast::Mutability::Mutable, ctx.ext_cx.ident_of("self"))
+ };
+ unmangledlist.push(gen_unmangle_method(ctx, &v, &mut unmangle_count, explicit_self));
+ mangledlist.push(cfunc_to_rs(ctx, name, String::new(), String::new(),
+ &*sig.ret_ty, sig.args.as_slice(),
+ sig.is_variadic, ast::Visibility::Inherited));
+ }
+ _ => unreachable!()
+ }
+ }
+ if mangledlist.len() > 0 {
+ items.push(mk_extern(ctx, &vec!(), mangledlist, Abi::C));
+ items.push(mk_impl(ctx, id_ty, unmangledlist));
+ }
items
}
-fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P<ast::Item> {
+fn opaque_to_rs(ctx: &mut GenCtx, name: &str) -> P<ast::Item> {
let def = ast::ItemKind::Enum(
ast::EnumDef {
variants: vec!()
@@ -632,7 +1136,7 @@ fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P<ast::Item> {
let id = rust_type_id(ctx, name);
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&id[..]),
+ ident: ctx.ext_cx.ident_of(&id),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
node: def,
@@ -641,11 +1145,11 @@ fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P<ast::Item> {
})
}
-fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
+fn cunion_to_rs(ctx: &mut GenCtx, name: &str, layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
fn mk_item(ctx: &mut GenCtx, name: String, item: ast::ItemKind, vis:
ast::Visibility, attrs: Vec<ast::Attribute>) -> P<ast::Item> {
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&name[..]),
+ ident: ctx.ext_cx.ident_of(&name),
attrs: attrs,
id: ast::DUMMY_NODE_ID,
node: item,
@@ -654,8 +1158,9 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
})
}
- let ci = Rc::new(RefCell::new(CompInfo::new(name.clone(), CompKind::Union, members.clone(), layout)));
- let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.clone(), TComp(ci)))));
+ // XXX what module id is correct?
+ let ci = Rc::new(RefCell::new(CompInfo::new(name.to_owned(), ROOT_MODULE_ID, name.to_owned(), "".to_owned(), CompKind::Union, members.clone(), layout)));
+ let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.to_owned(), ROOT_MODULE_ID, TComp(ci), layout))));
// Nested composites may need to emit declarations and implementations as
// they are encountered. The declarations end up in 'extra' and are emitted
@@ -666,27 +1171,22 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
let data_field = mk_blob_field(ctx, data_field_name, layout);
let def = ast::ItemKind::Struct(
- ast::VariantData::Struct(
- vec!(data_field),
- ast::DUMMY_NODE_ID),
+ ast::VariantData::Struct(vec![data_field], ast::DUMMY_NODE_ID),
empty_generics()
);
- let union_id = rust_type_id(ctx, name.clone());
- let union_attrs = {
- let mut attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false));
- if derive_debug {
- let can_derive_debug = members.iter()
- .all(|member| match *member {
- CompMember::Field(ref f) |
- CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
- _ => true
- });
- if can_derive_debug {
- attrs.push(mk_deriving_debug_attr(ctx))
- }
- }
- attrs
- };
+ let union_id = rust_type_id(ctx, name);
+ let mut union_attrs = vec!(mk_repr_attr(ctx, layout));
+ let can_derive_debug = members.iter()
+ .all(|member| match *member {
+ CompMember::Field(ref f) |
+ CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
+ _ => true
+ });
+ union_attrs.push(if can_derive_debug {
+ mk_deriving_copy_and_maybe_debug_attr(ctx)
+ } else {
+ mk_deriving_copy_attr(ctx)
+ });
let union_def = mk_item(ctx, union_id, def, ast::Visibility::Public, union_attrs);
@@ -695,8 +1195,8 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
ast::ImplPolarity::Positive,
empty_generics(),
None,
- P(cty_to_rs(ctx, &union)),
- gen_comp_methods(ctx, data_field_name, 0, CompKind::Union, &members, &mut extra, derive_debug),
+ P(cty_to_rs(ctx, &union, true, true)),
+ gen_comp_methods(ctx, data_field_name, 0, CompKind::Union, &members, &mut extra),
);
let mut items = vec!(
@@ -704,8 +1204,6 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
mk_item(ctx, "".to_owned(), union_impl, ast::Visibility::Inherited, Vec::new())
);
- items.push(mk_clone_impl(ctx, &name[..]));
- items.push(mk_default_impl(ctx, &name[..]));
items.extend(extra.into_iter());
items
}
@@ -726,7 +1224,7 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a
value
);
- let id = first(rust_id(ctx, name.clone()));
+ let id = first(rust_id(ctx, &name));
P(ast::Item {
ident: ctx.ext_cx.ident_of(&id[..]),
attrs: Vec::new(),
@@ -737,6 +1235,16 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a
})
}
+fn enum_size_to_unsigned_max_value(size: usize) -> u64 {
+ match size {
+ 1 => std::u8::MAX as u64,
+ 2 => std::u16::MAX as u64,
+ 4 => std::u32::MAX as u64,
+ 8 => std::u64::MAX,
+ _ => unreachable!("invalid enum size: {}", size)
+ }
+}
+
fn enum_size_to_rust_type_name(signed: bool, size: usize) -> &'static str {
match (signed, size) {
(true, 1) => "i8",
@@ -751,81 +1259,60 @@ fn enum_size_to_rust_type_name(signed: bool, size: usize) -> &'static str {
}
}
-fn enum_size_to_unsigned_max_value(size: usize) -> u64 {
- match size {
- 1 => std::u8::MAX as u64,
- 2 => std::u16::MAX as u64,
- 4 => std::u32::MAX as u64,
- 8 => std::u64::MAX,
- _ => unreachable!("invalid enum size: {}", size)
- }
-}
-
-fn cenum_value_to_int_lit(
- ctx: &mut GenCtx,
- enum_is_signed: bool,
- size: usize,
- value: i64)
- -> P<ast::Expr> {
+fn cenum_value_to_int_lit(ctx: &mut GenCtx,
+ enum_is_signed: bool,
+ size: usize,
+ value: i64) -> P<ast::Expr> {
if enum_is_signed {
- let int_lit =
- ast::LitKind::Int(value.abs() as u64, ast::LitIntType::Unsuffixed);
+ let int_lit = ast::LitKind::Int(value.abs() as u64, ast::LitIntType::Unsuffixed);
let expr = ctx.ext_cx.expr_lit(ctx.span, int_lit);
+
if value < 0 {
- ctx.ext_cx.expr(
- ctx.span, ast::ExprKind::Unary(ast::UnOp::Neg, expr))
+ ctx.ext_cx.expr(ctx.span, ast::ExprKind::Unary(ast::UnOp::Neg, expr))
} else {
expr
}
} else {
- let u64_value =
- value as u64 & enum_size_to_unsigned_max_value(size);
- let int_lit =
- ast::LitKind::Int(u64_value, ast::LitIntType::Unsuffixed);
+ let u64_value = value as u64 & enum_size_to_unsigned_max_value(size);
+ let int_lit = ast::LitKind::Int(u64_value, ast::LitIntType::Unsuffixed);
ctx.ext_cx.expr_lit(ctx.span, int_lit)
}
}
-fn cenum_to_rs(
- ctx: &mut GenCtx,
- rust_enums: bool,
- derive_debug: bool,
- name: String,
- kind: IKind,
- layout: Layout,
- enum_items: &[EnumItem])
- -> Vec<P<ast::Item>> {
+fn cenum_to_rs(ctx: &mut GenCtx,
+ name: String,
+ kind: IKind,
+ comment: String,
+ enum_items: &[EnumItem],
+ layout: Layout) -> Vec<P<ast::Item>> {
let enum_name = ctx.ext_cx.ident_of(&name);
let enum_ty = ctx.ext_cx.ty_ident(ctx.span, enum_name);
let enum_is_signed = kind.is_signed();
let enum_repr = enum_size_to_rust_type_name(enum_is_signed, layout.size);
+
+ // Rust is not happy with univariant enums
+ // if items.len() < 2 {
+ // return vec!();
+ // }
+ //
let mut items = vec![];
- if !rust_enums {
- items.push(ctx.ext_cx.item_ty(
- ctx.span,
- enum_name,
- ctx.ext_cx.ty_ident(
- ctx.span,
- ctx.ext_cx.ident_of(enum_repr))));
+ if !ctx.options.rust_enums {
+ items.push(ctx.ext_cx.item_ty(ctx.span,
+ enum_name,
+ ctx.ext_cx.ty_ident(ctx.span,
+ ctx.ext_cx.ident_of(enum_repr))));
for item in enum_items {
- let value = cenum_value_to_int_lit(
- ctx, enum_is_signed, layout.size, item.val);
- items.push(ctx.ext_cx.item_const(
- ctx.span,
- ctx.ext_cx.ident_of(&item.name),
- enum_ty.clone(),
- value));
+ let value = cenum_value_to_int_lit(ctx, enum_is_signed, layout.size, item.val);
+ items.push(ctx.ext_cx.item_const(ctx.span, ctx.ext_cx.ident_of(&item.name), enum_ty.clone(), value));
}
return items;
}
let mut variants = vec![];
let mut found_values = HashMap::new();
-
for item in enum_items {
let name = ctx.ext_cx.ident_of(&item.name);
-
if let Some(orig) = found_values.get(&item.val) {
let value = ctx.ext_cx.expr_path(
ctx.ext_cx.path(ctx.span, vec![enum_name, *orig]));
@@ -841,7 +1328,6 @@ fn cenum_to_rs(
}
found_values.insert(item.val, name);
-
let value = cenum_value_to_int_lit(
ctx, enum_is_signed, layout.size, item.val);
@@ -857,20 +1343,16 @@ fn cenum_to_rs(
let repr_arg = ctx.ext_cx.meta_word(ctx.span, enum_repr);
let repr_list = ctx.ext_cx.meta_list(ctx.span, InternedString::new("repr"), vec![repr_arg]);
- let repr_attr = respan(ctx.span, ast::Attribute_ {
+
+ let mut attrs = mk_doc_attr(ctx, &comment);
+ attrs.push(respan(ctx.span, ast::Attribute_ {
id: mk_attr_id(),
style: ast::AttrStyle::Outer,
value: repr_list,
is_sugared_doc: false,
- });
+ }));
- let attrs = {
- let mut v = vec![mk_deriving_copy_attr(ctx, true), repr_attr];
- if derive_debug {
- v.push(mk_deriving_debug_attr(ctx));
- }
- v
- };
+ attrs.push(mk_deriving_copy_and_maybe_debug_attr(ctx));
items.push(P(ast::Item {
ident: enum_name,
@@ -890,15 +1372,14 @@ fn cenum_to_rs(
/// These are emitted into `extra`.
fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
kind: CompKind, members: &[CompMember],
- extra: &mut Vec<P<ast::Item>>,
- derive_debug: bool) -> Vec<ast::ImplItem> {
+ extra: &mut Vec<P<ast::Item>>) -> Vec<ast::ImplItem> {
let mk_field_method = |ctx: &mut GenCtx, f: &FieldInfo, offset: usize| {
// TODO: Implement bitfield accessors
if f.bitfields.is_some() { return None; }
- let (f_name, _) = rust_id(ctx, f.name.clone());
- let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, Layout::zero())));
+ let f_name = first(rust_id(ctx, &f.name));
+ let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, false, Layout::zero()), true, true));
// When the offset is zero, generate slightly prettier code.
let method = {
@@ -912,7 +1393,7 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
", f_name, tts_to_string(&ret_ty.to_tokens(&ctx.ext_cx)[..]), data_field, offset);
parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(),
- ctx.ext_cx.cfg(), "".to_owned(), impl_str).parse_item().unwrap().unwrap()
+ ctx.ext_cx.cfg(), "".to_string(), impl_str).parse_item().unwrap().unwrap()
};
method.and_then(|i| {
@@ -936,18 +1417,18 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
CompMember::Comp(ref rc_c) => {
let c = &rc_c.borrow();
methods.extend(gen_comp_methods(ctx, data_field, offset, c.kind,
- &c.members, extra, derive_debug).into_iter());
+ &c.members, extra).into_iter());
c.layout.size
}
CompMember::CompField(ref rc_c, ref f) => {
methods.extend(mk_field_method(ctx, f, offset).into_iter());
let c = rc_c.borrow();
- extra.extend(comp_to_rs(ctx, c.kind, comp_name(c.kind, &c.name),
- derive_debug,
- c.layout, c.members.clone()).into_iter());
+ let name = comp_name(&ctx, c.kind, &c.name);
+ extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter());
f.ty.size()
}
+ CompMember::Enum(_) => 0
};
match kind {
CompKind::Struct => { offset += advance_by; }
@@ -957,28 +1438,121 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
methods
}
-// Implements std::default::Default using std::mem::zeroed.
-fn mk_default_impl(ctx: &GenCtx, ty_name: &str) -> P<ast::Item> {
- let impl_str = format!(r"
- impl ::std::default::Default for {} {{
- fn default() -> Self {{ unsafe {{ ::std::mem::zeroed() }} }}
- }}
- ", ty_name);
+fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32) -> ast::Ty {
+ let input_type = if width > 16 {
+ "u32"
+ } else if width > 8 {
+ "u16"
+ } else if width > 1 {
+ "u8"
+ } else {
+ "bool"
+ };
+ mk_ty(ctx, false, &[input_type.to_owned()])
+}
- parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(),
- ctx.ext_cx.cfg(), "".to_owned(), impl_str).parse_item().unwrap().unwrap()
+fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
+ field_name: &String, field_type: &Type,
+ offset: usize, width: u32) -> ast::ImplItem {
+ let input_type = type_for_bitfield_width(ctx, width);
+ let field_type = cty_to_rs(ctx, &field_type, false, true);
+ let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", field_name));
+ let bindgen_ident = ctx.ext_cx.ident_of(&*bindgen_name);
+
+ let node = &quote_item!(&ctx.ext_cx,
+ impl X {
+ pub fn $setter_name(&mut self, val: $input_type) {
+ self.$bindgen_ident &= !(((1 << $width) - 1) << $offset);
+ self.$bindgen_ident |= (val as $field_type) << $offset;
+ }
+ }
+ ).unwrap().node;
+ match node {
+ &ast::ItemKind::Impl(_, _, _, _, _, ref items) => items[0].clone(),
+ _ => unreachable!()
+ }
}
-// Implements std::clone::Clone using dereferencing
-fn mk_clone_impl(ctx: &GenCtx, ty_name: &str) -> P<ast::Item> {
- let impl_str = format!(r"
- impl ::std::clone::Clone for {} {{
- fn clone(&self) -> Self {{ *self }}
- }}
- ", ty_name);
+fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
+ field_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem {
+ let field_type = cty_to_rs(ctx, field_type, false, true);
+ let mut args = vec!();
+ let mut unnamed: usize = 0;
+ for &(ref name, width) in bitfields.iter() {
+ let ident = if name.is_empty() {
+ unnamed += 1;
+ let dummy = format!("unnamed_bitfield{}", unnamed);
+ ctx.ext_cx.ident_of(&dummy)
+ } else {
+ ctx.ext_cx.ident_of(name)
+ };
+ args.push(ast::Arg {
+ ty: P(type_for_bitfield_width(ctx, width)),
+ pat: P(ast::Pat {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::PatKind::Ident(
+ ast::BindingMode::ByValue(ast::Mutability::Immutable),
+ respan(ctx.span, ident),
+ None
+ ),
+ span: ctx.span
+ }),
+ id: ast::DUMMY_NODE_ID,
+ });
+ }
+
+ let fndecl = ast::FnDecl {
+ inputs: args,
+ output: ast::FunctionRetTy::Ty(P(field_type.clone())),
+ variadic: false
+ };
+
+ let stmts = Vec::with_capacity(bitfields.len() + 1);
- parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(),
- ctx.ext_cx.cfg(), "".to_owned(), impl_str).parse_item().unwrap().unwrap()
+ let mut offset = 0;
+ let mut exprs = quote_expr!(&ctx.ext_cx, 0);
+ let mut unnamed: usize = 0;
+ for &(ref name, width) in bitfields.iter() {
+ let name_ident = if name.is_empty() {
+ unnamed += 1;
+ let dummy = format!("unnamed_bitfield{}", unnamed);
+ ctx.ext_cx.ident_of(&dummy)
+ } else {
+ ctx.ext_cx.ident_of(name)
+ };
+ exprs = quote_expr!(&ctx.ext_cx,
+ $exprs | (($name_ident as $field_type) << $offset)
+ );
+ offset += width;
+ }
+
+ let block = ast::Block {
+ stmts: stmts,
+ expr: Some(exprs),
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::BlockCheckMode::Default,
+ span: ctx.span
+ };
+
+ let node = ast::ImplItemKind::Method(
+ ast::MethodSig {
+ unsafety: ast::Unsafety::Normal,
+ abi: Abi::Rust,
+ decl: P(fndecl),
+ generics: empty_generics(),
+ explicit_self: respan(ctx.span, ast::SelfKind::Static),
+ constness: ast::Constness::Const,
+ }, P(block)
+ );
+
+ ast::ImplItem {
+ id: ast::DUMMY_NODE_ID,
+ ident: ctx.ext_cx.ident_of(&format!("new{}", bindgen_name)),
+ vis: ast::Visibility::Public,
+ attrs: vec!(),
+ node: node,
+ span: ctx.span,
+ }
}
fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::StructField_> {
@@ -989,8 +1563,13 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::Struc
1 | _ => "u8",
};
let data_len = if ty_name == "u8" { layout.size } else { layout.size / layout.align };
- let base_ty = mk_ty(ctx, false, vec!(ty_name.to_owned()));
- let data_ty = P(mk_arrty(ctx, &base_ty, data_len));
+
+ let base_ty = mk_ty(ctx, false, &[ty_name.to_owned()]);
+ let data_ty = if data_len == 1 {
+ P(base_ty)
+ } else {
+ P(mk_arrty(ctx, &base_ty, data_len))
+ };
respan(ctx.span, ast::StructField_ {
kind: ast::NamedField(
ctx.ext_cx.ident_of(name),
@@ -1003,12 +1582,9 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::Struc
}
fn mk_link_name_attr(ctx: &mut GenCtx, name: String) -> ast::Attribute {
- let lit = respan(ctx.span, ast::LitKind::Str(
- to_intern_str(ctx, name),
- ast::StrStyle::Cooked
- ));
+ let lit = respan(ctx.span, ast::LitKind::Str(intern(&name).as_str(), ast::StrStyle::Cooked));
let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue(
- to_intern_str(ctx, "link_name".to_owned()), lit
+ InternedString::new("link_name"), lit
)));
let attr = ast::Attribute_ {
id: mk_attr_id(),
@@ -1020,12 +1596,12 @@ fn mk_link_name_attr(ctx: &mut GenCtx, name: String) -> ast::Attribute {
}
fn mk_repr_attr(ctx: &mut GenCtx, layout: Layout) -> ast::Attribute {
- let mut values = vec!(P(respan(ctx.span, ast::MetaItemKind::Word(to_intern_str(ctx, "C".to_owned())))));
+ let mut values = vec!(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("C")))));
if layout.packed {
- values.push(P(respan(ctx.span, ast::MetaItemKind::Word(to_intern_str(ctx, "packed".to_owned())))));
+ values.push(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("packed")))));
}
let attr_val = P(respan(ctx.span, ast::MetaItemKind::List(
- to_intern_str(ctx, "repr".to_owned()),
+ InternedString::new("repr"),
values
)));
@@ -1037,14 +1613,25 @@ fn mk_repr_attr(ctx: &mut GenCtx, layout: Layout) -> ast::Attribute {
})
}
-fn mk_deriving_copy_attr(ctx: &mut GenCtx, clone: bool) -> ast::Attribute {
- let mut words = vec!();
- if clone {
- words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Clone")));
+fn mk_deriving_copy_attr(ctx: &mut GenCtx) -> ast::Attribute {
+ mk_deriving_attr(ctx, &["Copy", "Clone"])
+}
+
+fn mk_deriving_copy_and_maybe_debug_attr(ctx: &mut GenCtx) -> ast::Attribute {
+ if ctx.options.derive_debug {
+ mk_deriving_attr(ctx, &["Copy", "Clone", "Debug"])
+ } else {
+ mk_deriving_copy_attr(ctx)
}
- words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Copy")));
+}
- let attr_val = ctx.ext_cx.meta_list(ctx.span, InternedString::new("derive"), words);
+fn mk_deriving_attr(ctx: &mut GenCtx, attrs: &[&'static str]) -> ast::Attribute {
+ let attr_val = P(respan(ctx.span, ast::MetaItemKind::List(
+ InternedString::new("derive"),
+ attrs.iter().map(|attr| {
+ P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new(attr))))
+ }).collect()
+ )));
respan(ctx.span, ast::Attribute_ {
id: mk_attr_id(),
@@ -1054,33 +1641,40 @@ fn mk_deriving_copy_attr(ctx: &mut GenCtx, clone: bool) -> ast::Attribute {
})
}
-fn mk_deriving_debug_attr(ctx: &mut GenCtx) -> ast::Attribute {
- let words = vec!(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Debug")));
+fn mk_doc_attr(ctx: &mut GenCtx, doc: &str) -> Vec<ast::Attribute> {
+ if doc.is_empty() {
+ return vec!();
+ }
- let attr_val = ctx.ext_cx.meta_list(ctx.span, InternedString::new("derive"), words);
+ let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue(
+ InternedString::new("doc"),
+ respan(ctx.span, ast::LitKind::Str(intern(doc).as_str(), ast::StrStyle::Cooked))
+ )));
- respan(ctx.span, ast::Attribute_ {
+ vec!(respan(ctx.span, ast::Attribute_ {
id: mk_attr_id(),
style: ast::AttrStyle::Outer,
value: attr_val,
- is_sugared_doc: false
- })
+ is_sugared_doc: true
+ }))
}
fn cvar_to_rs(ctx: &mut GenCtx, name: String,
- ty: &Type,
- is_const: bool) -> ast::ForeignItem {
- let (rust_name, was_mangled) = rust_id(ctx, name.clone());
+ mangled: String, ty: &Type,
+ is_const: bool) -> ast::ForeignItem {
+ let (rust_name, was_mangled) = rust_id(ctx, &name);
let mut attrs = Vec::new();
- if was_mangled {
+ if !mangled.is_empty() {
+ attrs.push(mk_link_name_attr(ctx, mangled));
+ } else if was_mangled {
attrs.push(mk_link_name_attr(ctx, name));
}
- let val_ty = P(cty_to_rs(ctx, ty));
+ let val_ty = P(cty_to_rs(ctx, ty, true, true));
ast::ForeignItem {
- ident: ctx.ext_cx.ident_of(&rust_name[..]),
+ ident: ctx.ext_cx.ident_of(&rust_name),
attrs: attrs,
node: ast::ForeignItemKind::Static(val_ty, !is_const),
id: ast::DUMMY_NODE_ID,
@@ -1096,7 +1690,10 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
let ret = match *rty {
TVoid => ast::FunctionRetTy::Default(ctx.span),
- _ => ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, rty)))
+ // Disable references in returns for now
+ TPtr(ref t, is_const, _, ref layout) =>
+ ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, &TPtr(t.clone(), is_const, false, layout.clone()), true, true))),
+ _ => ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, rty, true, true)))
};
let mut unnamed: usize = 0;
@@ -1107,7 +1704,7 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
unnamed += 1;
format!("arg{}", unnamed)
} else {
- first(rust_id(ctx, n.clone()))
+ first(rust_id(ctx, &n))
};
// From the C90 standard (http://c0x.coding-guidelines.com/6.7.5.3.html)
@@ -1116,8 +1713,8 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
// (if any) are those specified within the [ and ] of the array type
// derivation.
let arg_ty = P(match *t {
- TArray(ref typ, _, l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, l)),
- _ => cty_to_rs(ctx, t),
+ TArray(ref typ, _, l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, false, l), true, true),
+ _ => cty_to_rs(ctx, t, true, true),
});
ast::Arg {
@@ -1126,7 +1723,7 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
id: ast::DUMMY_NODE_ID,
node: ast::PatKind::Ident(
ast::BindingMode::ByValue(ast::Mutability::Immutable),
- respan(ctx.span, ctx.ext_cx.ident_of(&arg_name[..])),
+ respan(ctx.span, ctx.ext_cx.ident_of(&arg_name)),
None
),
span: ctx.span
@@ -1143,33 +1740,40 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
}
}
-fn cfunc_to_rs(ctx: &mut GenCtx, name: String, rty: &Type,
+fn cfunc_to_rs(ctx: &mut GenCtx,
+ name: String,
+ mangled: String,
+ comment: String,
+ rty: &Type,
aty: &[(String, Type)],
- var: bool) -> ast::ForeignItem {
+ var: bool,
+ vis: ast::Visibility) -> ast::ForeignItem {
let var = !aty.is_empty() && var;
let decl = ast::ForeignItemKind::Fn(
P(cfuncty_to_rs(ctx, rty, aty, var)),
empty_generics()
);
- let (rust_name, was_mangled) = rust_id(ctx, name.clone());
+ let (rust_name, was_mangled) = rust_id(ctx, &name);
- let mut attrs = Vec::new();
- if was_mangled {
+ let mut attrs = mk_doc_attr(ctx, &comment);
+ if !mangled.is_empty() {
+ attrs.push(mk_link_name_attr(ctx, mangled));
+ } else if was_mangled {
attrs.push(mk_link_name_attr(ctx, name));
}
ast::ForeignItem {
- ident: ctx.ext_cx.ident_of(&rust_name[..]),
+ ident: ctx.ext_cx.ident_of(&rust_name),
attrs: attrs,
node: decl,
id: ast::DUMMY_NODE_ID,
span: ctx.span,
- vis: ast::Visibility::Public,
+ vis: vis,
}
}
-fn cty_to_rs(ctx: &mut GenCtx, ty: &Type) -> ast::Ty {
+fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool) -> ast::Ty {
let prefix = vec!["std".to_owned(), "os".to_owned(), "raw".to_owned()];
let raw = |fragment: &str| {
let mut path = prefix.clone();
@@ -1178,79 +1782,147 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type) -> ast::Ty {
};
match *ty {
- TVoid => mk_ty(ctx, true, raw("c_void")),
+ TVoid => mk_ty(ctx, true, &raw("c_void")),
TInt(i, ref layout) => match i {
IBool => {
let ty_name = match layout.size {
- 8 => "u64",
- 4 => "u32",
+ 1 if allow_bool => "bool",
2 => "u16",
- 1 | _ => "u8",
+ 4 => "u32",
+ 8 => "u64",
+ _ => "u8",
};
- mk_ty(ctx, false, vec!(ty_name.to_owned()))
+ mk_ty(ctx, false, &[ty_name.to_owned()])
},
- ISChar => mk_ty(ctx, true, raw("c_char")),
- IUChar => mk_ty(ctx, true, raw("c_uchar")),
- IInt => mk_ty(ctx, true, raw("c_int")),
- IUInt => mk_ty(ctx, true, raw("c_uint")),
- IShort => mk_ty(ctx, true, raw("c_short")),
- IUShort => mk_ty(ctx, true, raw("c_ushort")),
- ILong => mk_ty(ctx, true, raw("c_long")),
- IULong => mk_ty(ctx, true, raw("c_ulong")),
- ILongLong => mk_ty(ctx, true, raw("c_longlong")),
- IULongLong => mk_ty(ctx, true, raw("c_ulonglong"))
+ ISChar => mk_ty(ctx, true, &raw("c_char")),
+ IUChar => mk_ty(ctx, true, &raw("c_uchar")),
+ IInt => mk_ty(ctx, true, &raw("c_int")),
+ IUInt => mk_ty(ctx, true, &raw("c_uint")),
+ IShort => mk_ty(ctx, true, &raw("c_short")),
+ IUShort => mk_ty(ctx, true, &raw("c_ushort")),
+ ILong => mk_ty(ctx, true, &raw("c_long")),
+ IULong => mk_ty(ctx, true, &raw("c_ulong")),
+ ILongLong => mk_ty(ctx, true, &raw("c_longlong")),
+ IULongLong => mk_ty(ctx, true, &raw("c_ulonglong"))
},
TFloat(f, _) => match f {
- FFloat => mk_ty(ctx, true, raw("c_float")),
- FDouble => mk_ty(ctx, true, raw("c_double"))
+ FFloat => mk_ty(ctx, false, &["f32".to_owned()]),
+ FDouble => mk_ty(ctx, false, &["f64".to_owned()])
},
- TPtr(ref t, is_const, _) => {
- let id = cty_to_rs(ctx, &**t);
+ TPtr(ref t, is_const, _is_ref, _) => {
+ let id = cty_to_rs(ctx, &**t, allow_bool, use_full_path);
mk_ptrty(ctx, &id, is_const)
},
TArray(ref t, s, _) => {
- let ty = cty_to_rs(ctx, &**t);
+ let ty = cty_to_rs(ctx, &**t, allow_bool, use_full_path);
mk_arrty(ctx, &ty, s)
},
TFuncPtr(ref sig) => {
let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, &sig.args[..], sig.is_variadic);
- let unsafety = if sig.is_safe { ast::Unsafety::Normal } else { ast::Unsafety::Unsafe };
- mk_fnty(ctx, &decl, unsafety, sig.abi)
+ mk_fnty(ctx, &decl, sig.abi)
},
TFuncProto(ref sig) => {
let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, &sig.args[..], sig.is_variadic);
- let unsafety = if sig.is_safe { ast::Unsafety::Normal } else { ast::Unsafety::Unsafe };
- mk_fn_proto_ty(ctx, &decl, unsafety, sig.abi)
+ mk_fn_proto_ty(ctx, &decl, sig.abi)
},
TNamed(ref ti) => {
- let id = rust_type_id(ctx, ti.borrow().name.clone());
- mk_ty(ctx, false, vec!(id))
+ let id = rust_type_id(ctx, &ti.borrow().name);
+
+ if use_full_path {
+ let mut path = ctx.full_path_for_module(ti.borrow().module_id);
+ path.push(id);
+ mk_ty(ctx, false, &path)
+ } else {
+ mk_ty(ctx, false, &[id])
+ }
},
TComp(ref ci) => {
- let mut c = ci.borrow_mut();
- c.name = unnamed_name(ctx, c.name.clone());
- mk_ty(ctx, false, vec!(comp_name(c.kind, &c.name)))
+ let c = ci.borrow();
+ let id = comp_name(&ctx, c.kind, &c.name);
+
+ let args = c.args.iter().map(|gt| {
+ P(cty_to_rs(ctx, gt, allow_bool, false))
+ }).collect();
+
+ if use_full_path {
+ let mut path = ctx.full_path_for_module(c.module_id);
+ path.push(id);
+ mk_ty_args(ctx, false, &path, args)
+ } else {
+ mk_ty_args(ctx, false, &[id], args)
+ }
+
},
TEnum(ref ei) => {
- let mut e = ei.borrow_mut();
- e.name = unnamed_name(ctx, e.name.clone());
- mk_ty(ctx, false, vec!(enum_name(&e.name)))
+ let e = ei.borrow();
+ let id = enum_name(&ctx, &e.name);
+
+ if use_full_path {
+ let mut path = ctx.full_path_for_module(e.module_id);
+ path.push(id);
+ mk_ty(ctx, false, &path)
+ } else {
+ mk_ty(ctx, false, &[id])
+ }
+ }
+ }
+}
+
+fn cty_is_translatable(ty: &Type) -> bool {
+ match ty {
+ &TVoid => false,
+ &TArray(ref t, _, _) => {
+ cty_is_translatable(&**t)
+ },
+ &TComp(ref ci) => {
+ let c = ci.borrow();
+ !c.args.iter().any(|gt| gt == &TVoid)
+ },
+ _ => true,
+ }
+}
+
+fn cty_has_destructor(ty: &Type) -> bool {
+ match ty {
+ &TArray(ref t, _, _) => {
+ cty_has_destructor(&**t)
}
+ &TComp(ref ci) => {
+ let c = ci.borrow();
+ if c.has_destructor || c.members.iter().any(|f| match f {
+ &CompMember::Field(ref f) |
+ &CompMember::CompField(_, ref f) =>
+ cty_has_destructor(&f.ty),
+ _ => false,
+ }) {
+ return true;
+ }
+ c.ref_template.is_some()
+ },
+ &TNamed(ref ti) => {
+ cty_has_destructor(&ti.borrow().ty)
+ },
+ _ => false,
}
}
-fn mk_ty(ctx: &GenCtx, global: bool, segments: Vec<String>) -> ast::Ty {
+fn mk_ty(ctx: &GenCtx, global: bool, segments: &[String]) -> ast::Ty {
+ mk_ty_args(ctx, global, segments, vec!())
+}
+
+fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec<P<ast::Ty>>) -> ast::Ty {
+ let segment_count = segments.len();
let ty = ast::TyKind::Path(
None,
ast::Path {
span: ctx.span,
global: global,
- segments: segments.iter().map(|s| {
+ segments: segments.iter().enumerate().map(|(i, s)| {
ast::PathSegment {
- identifier: ctx.ext_cx.ident_of(&s[..]),
+ identifier: ctx.ext_cx.ident_of(s),
parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
+ lifetimes: vec!(),
+ types: OwnedSlice::from_vec(if i == segment_count - 1 { args.clone() } else { vec![] }),
bindings: OwnedSlice::empty(),
}),
}
@@ -1278,6 +1950,23 @@ fn mk_ptrty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty {
}
}
+#[allow(dead_code)]
+fn mk_refty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty {
+ let ty = ast::TyKind::Rptr(
+ None,
+ ast::MutTy {
+ ty: P(base.clone()),
+ mutbl: if is_const { ast::Mutability::Immutable } else { ast::Mutability::Mutable }
+ }
+ );
+
+ ast::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: ty,
+ span: ctx.span
+ }
+}
+
fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty {
let int_lit = ast::LitKind::Int(n as u64, ast::LitIntType::Unsigned(ast::UintTy::Us));
let sz = ast::ExprKind::Lit(P(respan(ctx.span, int_lit)));
@@ -1300,10 +1989,9 @@ fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty {
fn mk_fn_proto_ty(ctx: &mut GenCtx,
decl: &ast::FnDecl,
- unsafety: ast::Unsafety,
- abi: abi::Abi) -> ast::Ty {
+ abi: Abi) -> ast::Ty {
let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
- unsafety: unsafety,
+ unsafety: ast::Unsafety::Unsafe,
abi: abi,
lifetimes: Vec::new(),
decl: P(decl.clone())
@@ -1316,12 +2004,9 @@ fn mk_fn_proto_ty(ctx: &mut GenCtx,
}
}
-fn mk_fnty(ctx: &mut GenCtx,
- decl: &ast::FnDecl,
- unsafety: ast::Unsafety,
- abi: abi::Abi) -> ast::Ty {
+fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty {
let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
- unsafety: unsafety,
+ unsafety: ast::Unsafety::Unsafe,
abi: abi,
lifetimes: Vec::new(),
decl: P(decl.clone())
diff --git a/src/lib.rs b/src/lib.rs
index b10546da..fadf41d8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,12 +1,14 @@
#![crate_name = "bindgen"]
#![crate_type = "dylib"]
+#![feature(quote)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
extern crate syntex_syntax as syntax;
extern crate libc;
-#[macro_use] extern crate log;
+#[macro_use]
+extern crate log;
use std::collections::HashSet;
use std::default::Default;
@@ -21,7 +23,7 @@ use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;
-use types::Global;
+use types::ModuleMap;
mod types;
mod clangll;
@@ -84,6 +86,11 @@ impl<'a> Builder<'a> {
self
}
+ pub fn rename_types(&mut self, value: bool) -> &mut Self {
+ self.options.rename_types = value;
+ self
+ }
+
pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
self.logger = Some(logger);
self
@@ -111,10 +118,13 @@ pub struct BindgenOptions {
pub rust_enums: bool,
pub links: Vec<(String, LinkType)>,
pub emit_ast: bool,
+ pub ignore_functions: bool,
pub fail_on_unknown_type: bool,
+ pub enable_cxx_namespaces: bool,
+ pub rename_types: bool,
+ pub derive_debug: bool,
pub override_enum_ty: String,
pub clang_args: Vec<String>,
- pub derive_debug: bool,
}
impl Default for BindgenOptions {
@@ -125,18 +135,18 @@ impl Default for BindgenOptions {
rust_enums: true,
links: Vec::new(),
emit_ast: false,
- fail_on_unknown_type: false,
- override_enum_ty: "".to_owned(),
- clang_args: match get_include_dir() {
- Some(path) => vec!("-idirafter".to_owned(), path),
- None => Vec::new()
- },
- derive_debug: true
+ ignore_functions: false,
+ fail_on_unknown_type: true,
+ rename_types: true,
+ derive_debug: true,
+ enable_cxx_namespaces: false,
+ override_enum_ty: "".to_string(),
+ clang_args: Vec::new()
}
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
Default,
Static,
@@ -148,7 +158,7 @@ pub trait Logger {
fn warn(&self, msg: &str);
}
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub struct Bindings {
module: ast::Mod
}
@@ -157,21 +167,18 @@ impl Bindings {
/// Deprecated - use a `Builder` instead
pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option<Span>) -> Result<Bindings, ()> {
let l = DummyLogger;
- let logger = match logger {
- Some(l) => l,
- None => &l as &Logger
- };
+ let logger = logger.unwrap_or(&l as &Logger);
- let span = match span {
- Some(s) => s,
- None => DUMMY_SP
- };
+ let span = span.unwrap_or(DUMMY_SP);
- let globals = try!(parse_headers(options, logger));
+ let module_map = try!(parse_headers(options, logger));
let module = ast::Mod {
inner: span,
- items: gen::gen_mod(options, globals, span)
+ items: gen::gen_mods(&options.links[..],
+ module_map,
+ options.clone(),
+ span)
};
Ok(Bindings {
@@ -217,7 +224,7 @@ impl Logger for DummyLogger {
fn warn(&self, _msg: &str) { }
}
-fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
+fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<ModuleMap, ()> {
fn str_to_ikind(s: &str) -> Option<types::IKind> {
match s {
"uchar" => Some(types::IUChar),
@@ -239,8 +246,10 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global
builtins: options.builtins,
match_pat: options.match_pat.clone(),
emit_ast: options.emit_ast,
+ ignore_functions: options.ignore_functions,
fail_on_unknown_type: options.fail_on_unknown_type,
- override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
+ enable_cxx_namespaces: options.enable_cxx_namespaces,
+ override_enum_ty: str_to_ikind(&options.override_enum_ty),
clang_args: options.clang_args.clone(),
};
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)
}
diff --git a/src/types.rs b/src/types.rs
index d36b3835..7846c7c9 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,6 +1,8 @@
use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
+use std::collections::HashMap;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use syntax::abi;
@@ -9,6 +11,45 @@ pub use self::Type::*;
pub use self::IKind::*;
pub use self::FKind::*;
+static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
+pub struct ModuleId(usize);
+pub static ROOT_MODULE_ID: ModuleId = ModuleId(0);
+
+impl ModuleId {
+ pub fn next() -> ModuleId {
+ ModuleId(NEXT_MODULE_ID.fetch_add(1, Ordering::SeqCst) + 1)
+ }
+}
+
+pub type ModuleMap = HashMap<ModuleId, Module>;
+
+#[derive(Clone)]
+pub struct Module {
+ pub name: String,
+ pub globals: Vec<Global>,
+ pub parent_id: Option<ModuleId>,
+ // Just for convenience
+ pub children_ids: Vec<ModuleId>,
+}
+
+impl Module {
+ pub fn new(name: String, parent_id: Option<ModuleId>) -> Self {
+ Module {
+ name: name,
+ globals: vec![],
+ parent_id: parent_id,
+ children_ids: vec![],
+ }
+ }
+
+ #[allow(dead_code)]
+ pub fn add_global(&mut self, g: Global) {
+ self.globals.push(g)
+ }
+}
+
#[derive(Clone)]
pub enum Global {
GType(Rc<RefCell<TypeInfo>>),
@@ -83,7 +124,7 @@ pub enum Type {
TVoid,
TInt(IKind, Layout),
TFloat(FKind, Layout),
- TPtr(Box<Type>, bool, Layout),
+ TPtr(Box<Type>, bool, bool, Layout),
TArray(Box<Type>, usize, Layout),
TFuncProto(FuncSig),
TFuncPtr(FuncSig),
@@ -95,26 +136,26 @@ pub enum Type {
impl Type {
pub fn size(&self) -> usize {
match *self {
- TInt(_, l)
- | TFloat(_, l)
- | TPtr(_, _, l)
- | TArray(_, _, l) => l.size,
+ TInt(_, l) => l.size,
+ TFloat(_, l) => l.size,
+ TPtr(_, _, _, l) => l.size,
+ TArray(_, _, l) => l.size,
TNamed(ref ti) => ti.borrow().ty.size(),
TComp(ref ci) => ci.borrow().layout.size,
TEnum(ref ei) => ei.borrow().layout.size,
- TVoid
- | TFuncProto(..)
- | TFuncPtr(..) => 0,
+ TVoid => 0,
+ TFuncProto(..) => 0,
+ TFuncPtr(..) => 0,
}
}
#[allow(dead_code)]
pub fn align(&self) -> usize {
match *self {
- TInt(_, l)
- | TFloat(_, l)
- | TPtr(_, _, l)
- | TArray(_, _, l) => l.align,
+ TInt(_, l) => l.align,
+ TFloat(_, l) => l.align,
+ TPtr(_, _, _, l) => l.align,
+ TArray(_, _, l) => l.align,
TNamed(ref ti) => ti.borrow().ty.align(),
TComp(ref ci) => ci.borrow().layout.align,
TEnum(ref ei) => ei.borrow().layout.align,
@@ -124,6 +165,7 @@ impl Type {
}
}
+ #[allow(dead_code)]
pub fn can_derive_debug(&self) -> bool {
match *self {
TArray(_, size, _) => size <= 32,
@@ -175,6 +217,7 @@ pub enum IKind {
}
impl IKind {
+ #[allow(dead_code)]
pub fn is_signed(self) -> bool {
match self {
IBool => false,
@@ -203,6 +246,7 @@ pub enum CompMember {
Field(FieldInfo),
Comp(Rc<RefCell<CompInfo>>),
CompField(Rc<RefCell<CompInfo>>, FieldInfo),
+ Enum(Rc<RefCell<EnumInfo>>),
}
#[derive(Copy, Clone, PartialEq)]
@@ -215,16 +259,49 @@ pub enum CompKind {
pub struct CompInfo {
pub kind: CompKind,
pub name: String,
+ pub module_id: ModuleId,
+ pub filename: String,
+ pub comment: String,
pub members: Vec<CompMember>,
+ pub args: Vec<Type>,
+ pub methods: Vec<VarInfo>,
+ pub vmethods: Vec<VarInfo>,
+ pub ref_template: Option<Type>,
+ pub has_vtable: bool,
+ pub has_destructor: bool,
+ pub hide: bool,
+ pub base_members: usize,
pub layout: Layout,
}
+static mut UNNAMED_COUNTER: u32 = 0;
+
+fn unnamed_name(name: String, filename: &String) -> String {
+ return if name.is_empty() {
+ let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER };
+ format!("{}_unnamed_{}", filename, n)
+ } else {
+ name
+ };
+}
+
impl CompInfo {
- pub fn new(name: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
+ pub fn new(name: String, module_id: ModuleId, filename: String, comment: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
CompInfo {
kind: kind,
- name: name,
+ module_id: module_id,
+ name: unnamed_name(name, &filename),
+ filename: filename,
+ comment: comment,
members: members,
+ args: vec!(),
+ methods: vec!(),
+ vmethods: vec!(),
+ ref_template: None,
+ has_vtable: false,
+ has_destructor: false,
+ hide: false,
+ base_members: 0,
layout: layout,
}
}
@@ -240,14 +317,16 @@ impl fmt::Debug for CompInfo {
pub struct FieldInfo {
pub name: String,
pub ty: Type,
+ pub comment: String,
pub bitfields: Option<Vec<(String, u32)>>,
}
impl FieldInfo {
- pub fn new(name: String, ty: Type, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
+ pub fn new(name: String, ty: Type, comment: String, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
FieldInfo {
name: name,
ty: ty,
+ comment: comment,
bitfields: bitfields,
}
}
@@ -256,15 +335,21 @@ impl FieldInfo {
#[derive(Clone, PartialEq)]
pub struct EnumInfo {
pub name: String,
+ pub module_id: ModuleId,
+ pub comment: String,
+ pub filename: String,
pub items: Vec<EnumItem>,
pub kind: IKind,
pub layout: Layout,
}
impl EnumInfo {
- pub fn new(name: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
+ pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
EnumInfo {
- name: name,
+ name: unnamed_name(name, &filename),
+ module_id: module_id,
+ comment: String::new(),
+ filename: filename,
items: items,
kind: kind,
layout: layout,
@@ -281,13 +366,15 @@ impl fmt::Debug for EnumInfo {
#[derive(Clone, PartialEq)]
pub struct EnumItem {
pub name: String,
+ pub comment: String,
pub val: i64
}
impl EnumItem {
- pub fn new(name: String, val: i64) -> EnumItem {
+ pub fn new(name: String, comment: String, val: i64) -> EnumItem {
EnumItem {
name: name,
+ comment: comment,
val: val
}
}
@@ -296,14 +383,20 @@ impl EnumItem {
#[derive(Clone, PartialEq)]
pub struct TypeInfo {
pub name: String,
- pub ty: Type
+ pub module_id: ModuleId,
+ pub comment: String,
+ pub ty: Type,
+ pub layout: Layout,
}
impl TypeInfo {
- pub fn new(name: String, ty: Type) -> TypeInfo {
+ pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo {
TypeInfo {
name: name,
- ty: ty
+ module_id: module_id,
+ comment: String::new(),
+ ty: ty,
+ layout: layout,
}
}
}
@@ -314,22 +407,33 @@ impl fmt::Debug for TypeInfo {
}
}
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
pub struct VarInfo {
pub name: String,
+ pub mangled: String,
+ pub comment: String,
pub ty: Type,
//TODO: support non-integer constants
pub val: Option<i64>,
- pub is_const: bool
+ pub is_const: bool,
+ pub is_static: bool,
}
impl VarInfo {
- pub fn new(name: String, ty: Type) -> VarInfo {
+ pub fn new(name: String, mangled: String, comment: String, ty: Type) -> VarInfo {
+ let mangled = if name == mangled {
+ String::new()
+ } else {
+ mangled
+ };
VarInfo {
name: name,
+ mangled: mangled,
+ comment: comment,
ty: ty,
val: None,
- is_const: false
+ is_const: false,
+ is_static: false,
}
}
}