diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-09-07 14:02:09 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-07 14:02:09 -0500 |
commit | b13f0766e28cf75dd04f358bf64d87ea96b111c3 (patch) | |
tree | d8686bf93e5fa8c52ff6d085008a6b25c2cba42e /src/codegen/mod.rs | |
parent | dcd8385a41f6fd6d8f5208931c418cbc745672b4 (diff) | |
parent | 46f74c189c95fc6a41daf8ded741e0cf5f5bed92 (diff) |
Auto merge of #940 - fitzgen:no-syntex, r=emilio
No more syntex
There are a few commits in this PR, but the big one is the commit that goes `syntex` -> `quote` for code generation. I've included a copy of its commit message below.
I tried to verify that it works with the stylo build still, but there were some issues, and then I checked with master, and that wasn't working either. So now I'm C-Reducing the failures on master and figured that this is at least ready for feedback in the meantime.
r? @emilio
----------------------------
The `syntex` crate is unmaintained. It is slow to build, and additionally it requires that we pre-process `src/codegen/mod.rs` before we build the `bindgen` crate.
The `quote` crate provides similar quasi-quoting functionality, is maintained, and builds faster. It doesn't have a typed API or builders, however; it only deals with tokens.
Before this commit:
```
$ cargo clean; cargo build
<snip>
Finished dev [unoptimized + debuginfo] target(s) in 98.75 secs
```
After this commit:
```
$ cargo clean; cargo build
<snip>
Finished dev [unoptimized + debuginfo] target(s) in 46.26 secs
```
Build time is cut in half! But what about run time?
Before this commit:
```
Generated Stylo bindings in: Duration { secs: 3, nanos: 521105668 }
```
After this commit:
```
Generated Stylo bindings in: Duration { secs: 3, nanos: 548797242 }
```
So it appears to be about 20ms slower at generating Stylo bindings, but I suspect this is well within the noise.
Finally, this also lets us remove that nasty `mem::transmute` inside `bindgen::ir::BindgenContext::gen` that was used for the old `syntex` context. Now `BindgenContext` doesn't have a lifetime parameter either. This should make it easier to revisit doing our analyses in parallel with `rayon`, since that context was one of the things that made it hard for `BindgenContext` to implement `Sync`.
Fixes #925
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r-- | src/codegen/mod.rs | 2133 |
1 files changed, 954 insertions, 1179 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 4697ba21..f13bd65a 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -6,9 +6,6 @@ pub mod struct_layout; use self::helpers::attributes; use self::struct_layout::StructLayoutTracker; -use aster; -use aster::struct_field::StructFieldBuilder; - use ir::annotations::FieldAccessorKind; use ir::comment; use ir::comp::{Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field, @@ -29,36 +26,33 @@ use ir::template::{AsTemplateParam, TemplateInstantiation, TemplateParameters}; use ir::ty::{Type, TypeKind}; use ir::var::Var; +use quote; + use std::borrow::Cow; use std::cell::Cell; use std::collections::{HashSet, VecDeque}; use std::collections::hash_map::{Entry, HashMap}; use std::fmt::Write; +use std::iter; use std::mem; use std::ops; -use syntax::abi; -use syntax::ast; -use syntax::codemap::{DUMMY_SP, Span, respan}; -use syntax::ptr::P; // Name of type defined in constified enum module pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &'static str = "Type"; -fn top_level_path(ctx: &BindgenContext, item: &Item) -> Vec<ast::Ident> { - let mut path = vec![ctx.rust_ident_raw("self")]; +fn top_level_path(ctx: &BindgenContext, item: &Item) -> Vec<quote::Tokens> { + let mut path = vec![quote! { self }]; if ctx.options().enable_cxx_namespaces { - let super_ = ctx.rust_ident_raw("super"); - for _ in 0..item.codegen_depth(ctx) { - path.push(super_.clone()); + path.push(quote! { super }); } } path } -fn root_import(ctx: &BindgenContext, module: &Item) -> P<ast::Item> { +fn root_import(ctx: &BindgenContext, module: &Item) -> quote::Tokens { assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); assert!(module.is_module()); @@ -66,20 +60,20 @@ fn root_import(ctx: &BindgenContext, module: &Item) -> P<ast::Item> { let root = ctx.root_module().canonical_name(ctx); let root_ident = ctx.rust_ident(&root); - path.push(root_ident); + path.push(quote! { #root_ident }); + - let use_root = aster::AstBuilder::new() - .item() - .use_() - .ids(path) - .build() - .build(); + let mut tokens = quote! {}; + tokens.append_separated(path, "::"); - quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap() + quote! { + #[allow(unused_imports)] + use #tokens ; + } } struct CodegenResult<'a> { - items: Vec<P<ast::Item>>, + items: Vec<quote::Tokens>, /// A monotonic counter used to add stable unique id's to stuff that doesn't /// need to be referenced by anything. @@ -190,7 +184,7 @@ impl<'a> CodegenResult<'a> { self.vars_seen.insert(name.into()); } - fn inner<F>(&mut self, cb: F) -> Vec<P<ast::Item>> + fn inner<F>(&mut self, cb: F) -> Vec<quote::Tokens> where F: FnOnce(&mut Self), { @@ -207,7 +201,7 @@ impl<'a> CodegenResult<'a> { } impl<'a> ops::Deref for CodegenResult<'a> { - type Target = Vec<P<ast::Item>>; + type Target = Vec<quote::Tokens>; fn deref(&self) -> &Self::Target { &self.items @@ -220,70 +214,85 @@ impl<'a> ops::DerefMut for CodegenResult<'a> { } } -struct ForeignModBuilder { - inner: ast::ForeignMod, +/// A trait to convert a rust type into a pointer, optionally const, to the same +/// type. +trait ToPtr { + fn to_ptr(self, is_const: bool) -> quote::Tokens; } -impl ForeignModBuilder { - fn new(abi: abi::Abi) -> Self { - ForeignModBuilder { - inner: ast::ForeignMod { - abi: abi, - items: vec![], - }, +impl ToPtr for quote::Tokens { + fn to_ptr(self, is_const: bool) -> quote::Tokens { + if is_const { + quote! { *const #self } + } else { + quote! { *mut #self } } } - - fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { - self.inner.items.push(item); - self - } - - #[allow(dead_code)] - fn with_foreign_items<I>(mut self, items: I) -> Self - where - I: IntoIterator<Item = ast::ForeignItem>, - { - self.inner.items.extend(items.into_iter()); - self - } - - fn build(self, ctx: &BindgenContext) -> P<ast::Item> { - P(ast::Item { - ident: ctx.rust_ident(""), - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::ForeignMod(self.inner), - vis: ast::Visibility::Public, - attrs: vec![], - span: DUMMY_SP, - }) - } } -/// A trait to convert a rust type into a pointer, optionally const, to the same -/// type. -/// -/// This is done due to aster's lack of pointer builder, I guess I should PR -/// there. -trait ToPtr { - fn to_ptr(self, is_const: bool, span: Span) -> P<ast::Ty>; +/// An extension trait for `quote::Tokens` that lets us append any implicit +/// template parameters that exist for some type, if necessary. +trait AppendImplicitTemplateParams { + fn append_implicit_template_params( + &mut self, + ctx: &BindgenContext, + item: &Item, + ); } -impl ToPtr for P<ast::Ty> { - fn to_ptr(self, is_const: bool, span: Span) -> Self { - let ty = ast::TyKind::Ptr(ast::MutTy { - ty: self, - mutbl: if is_const { - ast::Mutability::Immutable - } else { - ast::Mutability::Mutable - }, - }); - P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ty, - span: span, - }) +impl AppendImplicitTemplateParams for quote::Tokens { + fn append_implicit_template_params( + &mut self, + ctx: &BindgenContext, + item: &Item, + ) { + let item = item.id() + .into_resolver() + .through_type_refs() + .resolve(ctx); + + match *item.expect_type().kind() { + TypeKind::UnresolvedTypeRef(..) => { + unreachable!("already resolved unresolved type refs") + } + TypeKind::ResolvedTypeRef(..) => { + unreachable!("we resolved item through type refs") + } + + // None of these types ever have implicit template parameters. + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Pointer(..) | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) | + TypeKind::Array(..) | + TypeKind::TypeParam | + TypeKind::Opaque | + TypeKind::Function(..) | + TypeKind::Enum(..) | + TypeKind::BlockPointer | + TypeKind::ObjCId | + TypeKind::ObjCSel | + TypeKind::TemplateInstantiation(..) => return, + + _ => {}, + } + + if let Some(params) = item.used_template_params(ctx) { + if params.is_empty() { + return; + } + + let params = params.into_iter().map(|p| { + p.try_to_rust_ty(ctx, &()) + .expect("template params cannot fail to be a rust type") + }); + + self.append(quote! { + < #( #params ),* > + }); + } } } @@ -376,7 +385,7 @@ impl CodeGenerator for Module { utils::prepend_incomplete_array_types(ctx, &mut *result); } if ctx.need_bindegen_complex_type() { - utils::prepend_complex_type(ctx, &mut *result); + utils::prepend_complex_type(&mut *result); } if result.saw_objc { utils::prepend_objc_header(ctx, &mut *result); @@ -403,27 +412,23 @@ impl CodeGenerator for Module { return; } - let module = ast::ItemKind::Mod(ast::Mod { - inner: ctx.span(), - items: inner_items, - }); - let name = item.canonical_name(ctx); - let item_builder = aster::AstBuilder::new().item().pub_(); - let item = if name == "root" { - let attrs = &[ - "non_snake_case", - "non_camel_case_types", - "non_upper_case_globals", - ]; - item_builder - .with_attr(attributes::allow(attrs)) - .build_item_kind(name, module) - } else { - item_builder.build_item_kind(name, module) - }; - result.push(item); + result.push(if name == "root" { + quote! { + #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] + pub mod root { + #( #inner_items )* + } + } + } else { + let ident = ctx.rust_ident(name); + quote! { + pub mod #ident { + #( #inner_items )* + } + } + }); } } @@ -446,6 +451,8 @@ impl CodeGenerator for Var { } result.saw_var(&canonical_name); + let canonical_ident = ctx.rust_ident(&canonical_name); + // We can't generate bindings to static variables of templates. The // number of actual variables for a single declaration are open ended // and we don't know what instantiations do or don't exist. @@ -459,17 +466,17 @@ impl CodeGenerator for Var { let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); if let Some(val) = self.val() { - let const_item = aster::AstBuilder::new() - .item() - .pub_() - .const_(canonical_name) - .expr(); - let item = match *val { + match *val { VarType::Bool(val) => { - const_item.build(helpers::ast_ty::bool_expr(val)).build(ty) + result.push(quote! { + pub const #canonical_ident : #ty = #val ; + }); } VarType::Int(val) => { - const_item.build(helpers::ast_ty::int_expr(val)).build(ty) + let val = helpers::ast_ty::int_expr(val); + result.push(quote! { + pub const #canonical_ident : #ty = #val ; + }); } VarType::String(ref bytes) => { // Account the trailing zero. @@ -477,35 +484,39 @@ impl CodeGenerator for Var { // TODO: Here we ignore the type we just made up, probably // we should refactor how the variable type and ty id work. let len = bytes.len() + 1; - let ty = quote_ty!(ctx.ext_cx(), [u8; $len]); + let ty = quote! { + [u8; #len] + }; match String::from_utf8(bytes.clone()) { Ok(string) => { - const_item - .build(helpers::ast_ty::cstr_expr(string)) - .build(quote_ty!(ctx.ext_cx(), &'static $ty)) + let cstr = helpers::ast_ty::cstr_expr(string); + result.push(quote! { + pub const #canonical_ident : &'static #ty = #cstr ; + }); } Err(..) => { - const_item - .build(helpers::ast_ty::byte_array_expr(bytes)) - .build(ty) + let bytes = helpers::ast_ty::byte_array_expr(bytes); + result.push(quote! { + pub const #canonical_ident : #ty = #bytes ; + }); } } } VarType::Float(f) => { match helpers::ast_ty::float_expr(ctx, f) { - Ok(expr) => const_item.build(expr).build(ty), + Ok(expr) => result.push(quote! { + pub const #canonical_ident : #ty = #expr ; + }), Err(..) => return, } } VarType::Char(c) => { - const_item - .build(aster::AstBuilder::new().expr().lit().byte(c)) - .build(ty) + result.push(quote! { + pub const #canonical_ident : #ty = #c ; + }); } - }; - - result.push(item); + } } else { let mut attrs = vec![]; if let Some(mangled) = self.mangled_name() { @@ -514,19 +525,21 @@ impl CodeGenerator for Var { attrs.push(attributes::link_name(self.name())); } - let item = ast::ForeignItem { - ident: ctx.rust_ident_raw(&canonical_name), - attrs: attrs, - node: ast::ForeignItemKind::Static(ty, !self.is_const()), - id: ast::DUMMY_NODE_ID, - span: ctx.span(), - vis: ast::Visibility::Public, + let mut tokens = quote! { + extern "C" }; + tokens.append("{\n"); + if !attrs.is_empty() { + tokens.append_separated(attrs, "\n"); + tokens.append("\n"); + } + tokens.append("pub static mut "); + tokens.append(quote! { #canonical_ident }); + tokens.append(" : "); + tokens.append(quote! { #ty }); + tokens.append(";\n}"); - let item = ForeignModBuilder::new(abi::Abi::C) - .with_foreign_item(item) - .build(ctx); - result.push(item); + result.push(tokens); } } } @@ -567,7 +580,9 @@ impl CodeGenerator for Type { TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item), TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => { - let inner_item = ctx.resolve_item(inner); + let inner_item = inner.into_resolver() + .through_type_refs() + .resolve(ctx); let name = item.canonical_name(ctx); // Try to catch the common pattern: @@ -587,17 +602,25 @@ impl CodeGenerator for Type { return; } - let mut used_template_params = item.used_template_params(ctx); + let mut outer_params = item.used_template_params(ctx) + .and_then(|ps| if ps.is_empty() { + None + } else { + Some(ps) + }); + let inner_rust_type = if item.is_opaque(ctx, &()) { - used_template_params = None; + outer_params = None; self.to_opaque(ctx, item) } else { // Its possible that we have better layout information than // the inner type does, so fall back to an opaque blob based // on our layout if converting the inner item fails. - inner_item + let mut inner_ty = inner_item .try_to_rust_ty_or_opaque(ctx, &()) - .unwrap_or_else(|_| self.to_opaque(ctx, item)) + .unwrap_or_else(|_| self.to_opaque(ctx, item)); + inner_ty.append_implicit_template_params(ctx, inner_item); + inner_ty }; { @@ -625,68 +648,71 @@ impl CodeGenerator for Type { } let rust_name = ctx.rust_ident(&name); - let mut typedef = aster::AstBuilder::new().item().pub_(); - if let Some(comment) = item.comment(ctx) { - typedef = typedef.with_attr(attributes::doc(comment)); - } + let mut tokens = if let Some(comment) = item.comment(ctx) { + attributes::doc(comment) + } else { + quote! {} + }; // We prefer using `pub use` over `pub type` because of: // https://github.com/rust-lang/rust/issues/26264 - let simple_enum_path = match inner_rust_type.node { - ast::TyKind::Path(None, ref p) => { - if used_template_params.is_none() && - inner_item - .expect_type() - .canonical_type(ctx) - .is_enum() && - p.segments.iter().all(|p| p.parameters.is_none()) - { - Some(p.clone()) - } else { - None - } - } - _ => None, - }; + if inner_rust_type.as_str() + .chars() + .all(|c| match c { + // These are the only characters allowed in simple + // paths, eg `good::dogs::Bront`. + 'A'...'Z' | 'a'...'z' | '0'...'9' | ':' | '_' | ' ' => true, + _ => false, + }) && + outer_params.is_none() && + inner_item.expect_type().canonical_type(ctx).is_enum() + { + tokens.append(quote! { + pub use + }); + let path = top_level_path(ctx, item); + tokens.append_separated(path, "::"); + tokens.append(quote! { + :: #inner_rust_type as #rust_name ; + }); + result.push(tokens); + return; + } - let typedef = if let Some(mut p) = simple_enum_path { - for ident in top_level_path(ctx, item).into_iter().rev() { - p.segments.insert( - 0, - ast::PathSegment { - identifier: ident, - parameters: None, - }, + tokens.append(quote! { + pub type #rust_name + }); + + if let Some(params) = outer_params { + let params: Vec<_> = params.into_iter() + .filter_map(|p| p.as_template_param(ctx, &())) + .collect(); + if params.iter().any(|p| ctx.resolve_type(*p).is_invalid_type_param()) { + warn!( + "Item contained invalid template \ + parameter: {:?}", + item ); + return; } - typedef.use_().build(p).as_(rust_name) - } else { - let mut generics = typedef.type_(rust_name).generics(); - if let Some(ref params) = used_template_params { - for template_param in params { - if let Some(id) = template_param - .as_template_param(ctx, &()) - { - let template_param = ctx.resolve_type(id); - if template_param.is_invalid_type_param() { - warn!( - "Item contained invalid template \ - parameter: {:?}", - item - ); - return; - } - generics = - generics.ty_param_id( - template_param.name().unwrap(), - ); - } - } - } - generics.build().build_ty(inner_rust_type) - }; - result.push(typedef) + + let params = params.iter() + .map(|p| { + p.try_to_rust_ty(ctx, &()) + .expect("type parameters can always convert to rust ty OK") + }); + + tokens.append(quote! { + < #( #params ),* > + }); + } + + tokens.append(quote! { + = #inner_rust_type ; + }); + + result.push(tokens); } TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item), TypeKind::ObjCId | TypeKind::ObjCSel => { @@ -738,17 +764,12 @@ impl<'a> CodeGenerator for Vtable<'a> { // For now, generate an empty struct, later we should generate function // pointers and whatnot. - let attributes = vec![attributes::repr("C")]; - - let vtable = aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .tuple_struct(self.canonical_name(ctx)) - .field() - .build_ty(helpers::ast_ty::raw_type(ctx, "c_void")) - .build(); - result.push(vtable); + let name = ctx.rust_ident(&self.canonical_name(ctx)); + let void = helpers::ast_ty::raw_type(ctx, "c_void"); + result.push(quote! { + #[repr(C)] + pub struct #name ( #void ); + }); } } @@ -765,8 +786,11 @@ impl<'a> TryToRustTy for Vtable<'a> { &self, ctx: &BindgenContext, _: &(), - ) -> error::Result<P<ast::Ty>> { - Ok(aster::ty::TyBuilder::new().id(self.canonical_name(ctx))) + ) -> error::Result<quote::Tokens> { + let name = ctx.rust_ident(self.canonical_name(ctx)); + Ok(quote! { + #name + }) } } @@ -812,26 +836,28 @@ impl CodeGenerator for TemplateInstantiation { write!(&mut fn_name, "_{}", times_seen).unwrap(); } - let fn_name = ctx.rust_ident_raw(&fn_name); + let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); let ident = item.to_rust_ty_or_opaque(ctx, &()); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$ident>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$ident>()); + let size_of_expr = quote! { + ::#prefix::mem::size_of::<#ident>() + }; + let align_of_expr = quote! { + ::#prefix::mem::align_of::<#ident>() + }; - let item = quote_item!( - ctx.ext_cx(), + let item = quote! { #[test] - fn $fn_name() { - assert_eq!($size_of_expr, $size, + fn #fn_name() { + assert_eq!(#size_of_expr, #size, concat!("Size of template specialization: ", - stringify!($ident))); - assert_eq!($align_of_expr, $align, + stringify!(#ident))); + assert_eq!(#align_of_expr, #align, concat!("Alignment of template specialization: ", - stringify!($ident))); - }).unwrap(); + stringify!(#ident))); + } + }; result.push(item); } @@ -874,8 +900,8 @@ trait FieldCodegen<'a> { methods: &mut M, extra: Self::Extra, ) where - F: Extend<ast::StructField>, - M: Extend<ast::ImplItem>; + F: Extend<quote::Tokens>, + M: Extend<quote::Tokens>; } impl<'a> FieldCodegen<'a> for Field { @@ -895,8 +921,8 @@ impl<'a> FieldCodegen<'a> for Field { methods: &mut M, _: (), ) where - F: Extend<ast::StructField>, - M: Extend<ast::ImplItem>, + F: Extend<quote::Tokens>, + M: Extend<quote::Tokens>, { match *self { Field::DataMember(ref data) => { @@ -950,22 +976,27 @@ impl<'a> FieldCodegen<'a> for FieldData { methods: &mut M, _: (), ) where - F: Extend<ast::StructField>, - M: Extend<ast::ImplItem>, + F: Extend<quote::Tokens>, + M: Extend<quote::Tokens>, { // Bitfields are handled by `FieldCodegen` implementations for // `BitfieldUnit` and `Bitfield`. assert!(self.bitfield().is_none()); - let field_ty = ctx.resolve_type(self.ty()); - let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); + let field_item = self.ty().into_resolver().through_type_refs().resolve(ctx); + let field_ty = field_item.expect_type(); + let mut ty = self.ty().to_rust_ty_or_opaque(ctx, &()); // NB: If supported, we use proper `union` types. let ty = if parent.is_union() && !parent.can_be_rust_union(ctx) { if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>) + quote! { + root::__BindgenUnionField<#ty> + } } else { - quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) + quote! { + __BindgenUnionField<#ty> + } } } else if let Some(item) = field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); @@ -973,20 +1004,25 @@ impl<'a> FieldCodegen<'a> for FieldData { let inner = item.to_rust_ty_or_opaque(ctx, &()); if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) + quote! { + root::__IncompleteArrayField<#inner> + } } else { - quote_ty!(ctx.ext_cx(), __IncompleteArrayField<$inner>) + quote! { + __IncompleteArrayField<#inner> + } } } else { + ty.append_implicit_template_params(ctx, field_item); ty }; - let mut attrs = vec![]; + let mut field = quote! {}; if ctx.options().generate_comments { if let Some(raw_comment) = self.comment() { let comment = comment::preprocess(raw_comment, codegen_depth + 1); - attrs.push(attributes::doc(comment)) + field = attributes::doc(comment); } } @@ -994,6 +1030,7 @@ impl<'a> FieldCodegen<'a> for FieldData { self.name() .map(|name| ctx.rust_mangle(name).into_owned()) .unwrap_or_else(|| anon_field_names.next().unwrap()); + let field_ident = ctx.rust_ident_raw(field_name.as_str()); if !parent.is_union() { if let Some(padding_field) = @@ -1010,14 +1047,16 @@ impl<'a> FieldCodegen<'a> for FieldData { let accessor_kind = self.annotations().accessor_kind().unwrap_or(accessor_kind); - let mut field = StructFieldBuilder::named(&field_name); - - if !is_private { - field = field.pub_(); + if is_private { + field.append(quote! { + #field_ident : #ty , + }); + } else { + field.append(quote! { + pub #field_ident : #ty , + }); } - let field = field.with_attrs(attrs).build_ty(ty.clone()); - fields.extend(Some(field)); // TODO: Factor the following code out, please! @@ -1025,98 +1064,58 @@ impl<'a> FieldCodegen<'a> for FieldData { return; } - let getter_name = ctx.rust_ident_raw(&format!("get_{}", field_name)); + let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name)); let mutable_getter_name = - ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); - let field_name = ctx.rust_ident_raw(&field_name); + ctx.rust_ident_raw(format!("get_{}_mut", field_name)); + let field_name = ctx.rust_ident_raw(field_name); - let accessor_methods_impl = match accessor_kind { + methods.extend(Some(match accessor_kind { FieldAccessorKind::None => unreachable!(), FieldAccessorKind::Regular => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub fn $getter_name(&self) -> &$ty { - &self.$field_name - } + quote! { + #[inline] + pub fn #getter_name(&self) -> & #ty { + &self.#field_name + } - #[inline] - pub fn $mutable_getter_name(&mut self) -> &mut $ty { - &mut self.$field_name - } + #[inline] + pub fn #mutable_getter_name(&mut self) -> &mut #ty { + &mut self.#field_name } - ) + } } FieldAccessorKind::Unsafe => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub unsafe fn $getter_name(&self) -> &$ty { - &self.$field_name - } + quote! { + #[inline] + pub unsafe fn #getter_name(&self) -> & #ty { + &self.#field_name + } - #[inline] - pub unsafe fn $mutable_getter_name(&mut self) - -> &mut $ty { - &mut self.$field_name - } + #[inline] + pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty { + &mut self.#field_name } - ) + } } FieldAccessorKind::Immutable => { - quote_item!(ctx.ext_cx(), - impl X { - #[inline] - pub fn $getter_name(&self) -> &$ty { - &self.$field_name - } + quote! { + #[inline] + pub fn #getter_name(&self) -> & #ty { + &self.#field_name } - ) - } - }; - - match accessor_methods_impl.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => { - methods.extend(items.clone()) + } } - _ => unreachable!(), - } + })); } } impl BitfieldUnit { /// Get the constructor name for this bitfield unit. - fn ctor_name(&self, ctx: &BindgenContext) -> ast::Ident { - let ctor_name = format!("new_bitfield_{}", self.nth()); - ctx.ext_cx().ident_of(&ctor_name) - } - - /// Get the initial bitfield unit constructor that just returns 0. This will - /// then be extended by each bitfield in the unit. See `extend_ctor_impl` - /// below. - fn initial_ctor_impl( - &self, - ctx: &BindgenContext, - unit_field_int_ty: &P<ast::Ty>, - ) -> P<ast::Item> { - let ctor_name = self.ctor_name(ctx); - - // If supported, add the const. - let fn_prefix = if ctx.options().rust_features().const_fn() { - quote_tokens!(ctx.ext_cx(), pub const fn) - } else { - quote_tokens!(ctx.ext_cx(), pub fn) - }; - - quote_item!( - ctx.ext_cx(), - impl XxxUnused { - #[inline] - $fn_prefix $ctor_name() -> $unit_field_int_ty { - 0 - } - } - ).unwrap() + fn ctor_name(&self) -> quote::Tokens { + let ctor_name = quote::Ident::new(format!("new_bitfield_{}", self.nth())); + quote! { + #ctor_name + } } } @@ -1131,57 +1130,26 @@ impl Bitfield { fn extend_ctor_impl( &self, ctx: &BindgenContext, - parent: &CompInfo, - ctor_impl: P<ast::Item>, - ctor_name: &ast::Ident, - unit_field_int_ty: &P<ast::Ty>, - ) -> P<ast::Item> { - let items = match ctor_impl.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, items) => items, - _ => unreachable!(), - }; - - assert_eq!(items.len(), 1); - let (sig, body) = match items[0].node { - ast::ImplItemKind::Method(ref sig, ref body) => (sig, body), - _ => unreachable!(), - }; - - let params = sig.decl.clone().unwrap().inputs; - let param_name = bitfield_getter_name(ctx, parent, self.name()); - - let bitfield_ty_item = ctx.resolve_item(self.ty()); - let bitfield_ty = bitfield_ty_item.expect_type(); + param_name: quote::Tokens, + ctor_impl: quote::Tokens, + unit_field_int_ty: "e::Tokens, + ) -> quote::Tokens { + let bitfield_ty = ctx.resolve_type(self.ty()); let bitfield_ty_layout = bitfield_ty.layout(ctx).expect( "Bitfield without layout? Gah!", ); let bitfield_int_ty = helpers::blob(bitfield_ty_layout); - let bitfield_ty = - bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); let offset = self.offset_into_unit(); let mask = self.mask(); - // If supported, add the const. - let fn_prefix = if ctx.options().rust_features().const_fn() { - quote_tokens!(ctx.ext_cx(), pub const fn) - } else { - quote_tokens!(ctx.ext_cx(), pub fn) - }; - - // Don't use variables or blocks because const function does not allow them. - quote_item!( - ctx.ext_cx(), - impl XxxUnused { - #[inline] - $fn_prefix $ctor_name($params $param_name : $bitfield_ty) - -> $unit_field_int_ty { - ($body | - (($param_name as $bitfield_int_ty as $unit_field_int_ty) << $offset) & - ($mask as $unit_field_int_ty)) - } - } - ).unwrap() + // Don't use variables or blocks because const functions do not allow + // them. + quote! { + (#ctor_impl | + ((#param_name as #bitfield_int_ty as #unit_field_int_ty) << #offset) & + (#mask as #unit_field_int_ty)) + } } } @@ -1202,15 +1170,16 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { methods: &mut M, _: (), ) where - F: Extend<ast::StructField>, - M: Extend<ast::ImplItem>, + F: Extend<quote::Tokens>, + M: Extend<quote::Tokens>, { let field_ty = helpers::blob(self.layout()); let unit_field_name = format!("_bitfield_{}", self.nth()); + let unit_field_ident = ctx.rust_ident(&unit_field_name); - let field = StructFieldBuilder::named(&unit_field_name) - .pub_() - .build_ty(field_ty.clone()); + let field = quote! { + pub #unit_field_ident : #field_ty , + }; fields.extend(Some(field)); let mut field_int_size = self.layout().size; @@ -1219,10 +1188,10 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { } let unit_field_int_ty = match field_int_size { - 8 => quote_ty!(ctx.ext_cx(), u64), - 4 => quote_ty!(ctx.ext_cx(), u32), - 2 => quote_ty!(ctx.ext_cx(), u16), - 1 => quote_ty!(ctx.ext_cx(), u8), + 8 => quote! { u64 }, + 4 => quote! { u32 }, + 2 => quote! { u16 }, + 1 => quote! { u8 }, size => { debug_assert!(size > 8); // Can't generate bitfield accessors for unit sizes larget than @@ -1232,8 +1201,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { } }; - let ctor_name = self.ctor_name(ctx); - let mut ctor_impl = self.initial_ctor_impl(ctx, &unit_field_int_ty); + let ctor_name = self.ctor_name(); + let mut ctor_params = vec![]; + let mut ctor_impl = quote! { 0 }; for bf in self.bitfields() { bf.codegen( @@ -1250,23 +1220,36 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { (&unit_field_name, unit_field_int_ty.clone()), ); + let param_name = bitfield_getter_name(ctx, parent, bf.name()); + let bitfield_ty_item = ctx.resolve_item(bf.ty()); + let bitfield_ty = bitfield_ty_item.expect_type(); + let bitfield_ty = + bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); + + ctor_params.push(quote! { + #param_name : #bitfield_ty + }); ctor_impl = bf.extend_ctor_impl( ctx, - parent, + param_name, ctor_impl, - &ctor_name, &unit_field_int_ty, ); } - match ctor_impl.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, items) => { - assert_eq!(items.len(), 1); - methods.extend(items.into_iter()); - } - _ => unreachable!(), + let const_ = if ctx.options().rust_features().const_fn() { + quote! { const } + } else { + quote! { } }; + methods.extend(Some(quote! { + #[inline] + pub #const_ fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_int_ty { + #ctor_impl + } + })); + struct_layout.saw_bitfield_unit(self.layout()); } } @@ -1297,23 +1280,25 @@ fn bitfield_getter_name( ctx: &BindgenContext, parent: &CompInfo, bitfield_name: &str, -) -> ast::Ident { +) -> quote::Tokens { let name = ctx.rust_mangle(bitfield_name); if parent_has_method(ctx, parent, &name) { let mut name = name.to_string(); name.push_str("_bindgen_bitfield"); - return ctx.ext_cx().ident_of(&name); + let name = ctx.rust_ident(name); + return quote! { #name }; } - ctx.ext_cx().ident_of(&name) + let name = ctx.rust_ident(name); + quote! { #name } } fn bitfield_setter_name( ctx: &BindgenContext, parent: &CompInfo, bitfield_name: &str, -) -> ast::Ident { +) -> quote::Tokens { let setter = format!("set_{}", bitfield_name); let mut setter = ctx.rust_mangle(&setter).to_string(); @@ -1321,11 +1306,12 @@ fn bitfield_setter_name( setter.push_str("_bindgen_bitfield"); } - ctx.ext_cx().ident_of(&setter) + let setter = ctx.rust_ident(setter); + quote! { #setter } } impl<'a> FieldCodegen<'a> for Bitfield { - type Extra = (&'a str, P<ast::Ty>); + type Extra = (&'a str, quote::Tokens); fn codegen<F, M>( &self, @@ -1339,15 +1325,15 @@ impl<'a> FieldCodegen<'a> for Bitfield { _struct_layout: &mut StructLayoutTracker, _fields: &mut F, methods: &mut M, - (unit_field_name, unit_field_int_ty): (&'a str, P<ast::Ty>), + (unit_field_name, unit_field_int_ty): (&'a str, quote::Tokens), ) where - F: Extend<ast::StructField>, - M: Extend<ast::ImplItem>, + F: Extend<quote::Tokens>, + M: Extend<quote::Tokens>, { let prefix = ctx.trait_prefix(); let getter_name = bitfield_getter_name(ctx, parent, self.name()); let setter_name = bitfield_setter_name(ctx, parent, self.name()); - let unit_field_ident = ctx.ext_cx().ident_of(unit_field_name); + let unit_field_ident = quote::Ident::new(unit_field_name); let bitfield_ty_item = ctx.resolve_item(self.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); @@ -1363,67 +1349,57 @@ impl<'a> FieldCodegen<'a> for Bitfield { let offset = self.offset_into_unit(); let mask = self.mask(); - let impl_item = quote_item!( - ctx.ext_cx(), - impl XxxIgnored { - #[inline] - pub fn $getter_name(&self) -> $bitfield_ty { - let mut unit_field_val: $unit_field_int_ty = unsafe { - ::$prefix::mem::uninitialized() - }; + methods.extend(Some(quote! { + #[inline] + pub fn #getter_name(&self) -> #bitfield_ty { + let mut unit_field_val: #unit_field_int_ty = unsafe { + ::#prefix::mem::uninitialized() + }; - unsafe { - ::$prefix::ptr::copy_nonoverlapping( - &self.$unit_field_ident as *const _ as *const u8, - &mut unit_field_val as *mut $unit_field_int_ty as *mut u8, - ::$prefix::mem::size_of::<$unit_field_int_ty>(), - ) - }; + unsafe { + ::#prefix::ptr::copy_nonoverlapping( + &self.#unit_field_ident as *const _ as *const u8, + &mut unit_field_val as *mut #unit_field_int_ty as *mut u8, + ::#prefix::mem::size_of::<#unit_field_int_ty>(), + ) + }; - let mask = $mask as $unit_field_int_ty; - let val = (unit_field_val & mask) >> $offset; - unsafe { - ::$prefix::mem::transmute(val as $bitfield_int_ty) - } + let mask = #mask as #unit_field_int_ty; + let val = (unit_field_val & mask) >> #offset; + unsafe { + ::#prefix::mem::transmute(val as #bitfield_int_ty) } + } - #[inline] - pub fn $setter_name(&mut self, val: $bitfield_ty) { - let mask = $mask as $unit_field_int_ty; - let val = val as $bitfield_int_ty as $unit_field_int_ty; + #[inline] + pub fn #setter_name(&mut self, val: #bitfield_ty) { + let mask = #mask as #unit_field_int_ty; + let val = val as #bitfield_int_ty as #unit_field_int_ty; - let mut unit_field_val: $unit_field_int_ty = unsafe { - ::$prefix::mem::uninitialized() - }; + let mut unit_field_val: #unit_field_int_ty = unsafe { + ::#prefix::mem::uninitialized() + }; - unsafe { - ::$prefix::ptr::copy_nonoverlapping( - &self.$unit_field_ident as *const _ as *const u8, - &mut unit_field_val as *mut $unit_field_int_ty as *mut u8, - ::$prefix::mem::size_of::<$unit_field_int_ty>(), - ) - }; + unsafe { + ::#prefix::ptr::copy_nonoverlapping( + &self.#unit_field_ident as *const _ as *const u8, + &mut unit_field_val as *mut #unit_field_int_ty as *mut u8, + ::#prefix::mem::size_of::< #unit_field_int_ty >(), + ) + }; - unit_field_val &= !mask; - unit_field_val |= (val << $offset) & mask; + unit_field_val &= !mask; + unit_field_val |= (val << #offset) & mask; - unsafe { - ::$prefix::ptr::copy_nonoverlapping( - &unit_field_val as *const _ as *const u8, - &mut self.$unit_field_ident as *mut _ as *mut u8, - ::$prefix::mem::size_of::<$unit_field_int_ty>(), - ); - } + unsafe { + ::#prefix::ptr::copy_nonoverlapping( + &unit_field_val as *const _ as *const u8, + &mut self.#unit_field_ident as *mut _ as *mut u8, + ::#prefix::mem::size_of::< #unit_field_int_ty >(), + ); } } - ).unwrap(); - - match impl_item.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, items) => { - methods.extend(items.into_iter()); - } - _ => unreachable!(), - }; + })); } } @@ -1454,13 +1430,12 @@ impl CodeGenerator for CompInfo { // collisions. if self.is_forward_declaration() && used_template_params.is_none() { let struct_name = item.canonical_name(ctx); - let struct_name = ctx.rust_ident_raw(&struct_name); - let tuple_struct = quote_item!(ctx.ext_cx(), - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct $struct_name { _unused: [u8; 0] }; - ) - .unwrap(); + let struct_name = ctx.rust_ident_raw(struct_name); + let tuple_struct = quote! { + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct #struct_name { _unused: [u8; 0] } + }; result.push(tuple_struct); return; } @@ -1527,18 +1502,17 @@ impl CodeGenerator for CompInfo { } let canonical_name = item.canonical_name(ctx); - let builder = if is_union && self.can_be_rust_union(ctx) { - aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .union_(&canonical_name) + let canonical_ident = ctx.rust_ident(&canonical_name); + let mut tokens = if is_union && self.can_be_rust_union(ctx) { + quote! { + #( #attributes )* + pub union #canonical_ident + } } else { - aster::AstBuilder::new() - .item() - .pub_() - .with_attrs(attributes) - .struct_(&canonical_name) + quote! { + #( #attributes )* + pub struct #canonical_ident + } }; // Generate the vtable from the method list if appropriate. @@ -1567,15 +1541,13 @@ impl CodeGenerator for CompInfo { let vtable_type = vtable .try_to_rust_ty(ctx, &()) .expect("vtable to Rust type conversion is infallible") - .to_ptr(true, ctx.span()); + .to_ptr(true); - let vtable_field = StructFieldBuilder::named("vtable_") - .pub_() - .build_ty(vtable_type); + fields.push(quote! { + pub vtable_: #vtable_type , + }); struct_layout.saw_vtable(); - - fields.push(vtable_field); } for (i, base) in self.base_members().iter().enumerate() { @@ -1596,17 +1568,17 @@ impl CodeGenerator for CompInfo { } let inner = base.ty.to_rust_ty_or_opaque(ctx, &()); - let field_name = if i == 0 { + let field_name = ctx.rust_ident(if i == 0 { "_base".into() } else { format!("_base_{}", i) - }; + }); struct_layout.saw_base(base_ty); - let field = - StructFieldBuilder::named(field_name).pub_().build_ty(inner); - fields.extend(Some(field)); + fields.push(quote! { + pub #field_name : #inner , + }); } } if is_union { @@ -1647,17 +1619,17 @@ impl CodeGenerator for CompInfo { let layout = layout.expect("Unable to get layout information?"); let ty = helpers::blob(layout); - let field = if self.can_be_rust_union(ctx) { - StructFieldBuilder::named("_bindgen_union_align").build_ty(ty) + fields.push(if self.can_be_rust_union(ctx) { + quote! { + _bindgen_union_align: #ty , + } } else { struct_layout.saw_union(layout); - StructFieldBuilder::named("bindgen_union_field") - .pub_() - .build_ty(ty) - }; - - fields.push(field); + quote! { + pub bindgen_union_field: #ty , + } + }); } if is_opaque { @@ -1668,11 +1640,9 @@ impl CodeGenerator for CompInfo { match layout { Some(l) => { let ty = helpers::blob(l); - let field = StructFieldBuilder::named( - "_bindgen_opaque_blob", - ).pub_() - .build_ty(ty); - fields.push(field); + fields.push(quote! { + pub _bindgen_opaque_blob: #ty , + }); } None => { warn!("Opaque type without layout! Expect dragons!"); @@ -1713,41 +1683,45 @@ impl CodeGenerator for CompInfo { if has_address { let ty = helpers::blob(Layout::new(1, 1)); - let field = - StructFieldBuilder::named("_address").pub_().build_ty(ty); - fields.push(field); + fields.push(quote! { + pub _address: #ty, + }); } } - let mut generics = aster::AstBuilder::new().generics(); + let mut generics = quote! {}; if let Some(ref params) = used_template_params { - for (idx, ty) in params.iter().enumerate() { - let param = ctx.resolve_type(*ty); - let name = param.name().unwrap(); - let ident = ctx.rust_ident(name); + if !params.is_empty() { + let mut param_names = vec![]; - generics = generics.ty_param_id(ident); + for (idx, ty) in params.iter().enumerate() { + let param = ctx.resolve_type(*ty); + let name = param.name().unwrap(); + let ident = ctx.rust_ident(name); + param_names.push(ident.clone()); - let prefix = ctx.trait_prefix(); - let phantom_ty = quote_ty!( - ctx.ext_cx(), - ::$prefix::marker::PhantomData<::$prefix::cell::UnsafeCell<$ident>>); - let phantom_field = StructFieldBuilder::named( - format!("_phantom_{}", idx), - ).pub_() - .build_ty(phantom_ty); - fields.push(phantom_field); + let prefix = ctx.trait_prefix(); + let field_name = ctx.rust_ident(format!("_phantom_{}", idx)); + fields.push(quote! { + pub #field_name : ::#prefix::marker::PhantomData< + ::#prefix::cell::UnsafeCell<#ident> + > , + }); + } + + generics = quote! { + < #( #param_names ),* > + }; } } - let generics = generics.build(); - - let rust_struct = builder - .with_generics(generics.clone()) - .with_fields(fields) - .build(); - result.push(rust_struct); + tokens.append(quote! { + #generics { + #( #fields )* + } + }); + result.push(tokens); // Generate the inner types and all that stuff. // @@ -1765,7 +1739,7 @@ impl CodeGenerator for CompInfo { if self.found_unknown_attr() { warn!( "Type {} has an unkown attribute that may affect layout", - canonical_name + canonical_ident ); } @@ -1779,14 +1753,15 @@ impl CodeGenerator for CompInfo { if ctx.options().layout_tests { if let Some(layout) = layout { let fn_name = - format!("bindgen_test_layout_{}", canonical_name); - let fn_name = ctx.rust_ident_raw(&fn_name); - let type_name = ctx.rust_ident_raw(&canonical_name); + format!("bindgen_test_layout_{}", canonical_ident); + let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$type_name>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$type_name>()); + let size_of_expr = quote! { + ::#prefix::mem::size_of::<#canonical_ident>() + }; + let align_of_expr = quote! { + ::#prefix::mem::align_of::<#canonical_ident>() + }; let size = layout.size; let align = layout.align; @@ -1795,11 +1770,12 @@ impl CodeGenerator for CompInfo { // FIXME when [RFC 1358](https://github.com/rust-lang/rust/issues/33626) ready None } else { - quote_item!(ctx.ext_cx(), - assert_eq!($align_of_expr, - $align, - concat!("Alignment of ", stringify!($type_name))); - ) + Some(quote! { + assert_eq!(#align_of_expr, + #align, + concat!("Alignment of ", stringify!(#canonical_ident))); + + }) }; // FIXME when [issue #465](https://github.com/rust-lang-nursery/rust-bindgen/issues/465) ready @@ -1814,43 +1790,43 @@ impl CodeGenerator for CompInfo { let check_field_offset = if should_skip_field_offset_checks { - None + vec![] } else { let asserts = self.fields() - .iter() - .filter_map(|field| match *field { - Field::DataMember(ref f) if f.name().is_some() => Some(f), - _ => None, - }) - .flat_map(|field| { - let name = field.name().unwrap(); - field.offset().and_then(|offset| { - let field_offset = offset / 8; - let field_name = ctx.rust_ident(name); - - quote_item!(ctx.ext_cx(), - assert_eq!(unsafe { &(*(0 as *const $type_name)).$field_name as *const _ as usize }, - $field_offset, - concat!("Alignment of field: ", stringify!($type_name), "::", stringify!($field_name))); - ) - }) - }) - .collect::<Vec<P<ast::Item>>>(); - - Some(asserts) + .iter() + .filter_map(|field| match *field { + Field::DataMember(ref f) if f.name().is_some() => Some(f), + _ => None, + }) + .flat_map(|field| { + let name = field.name().unwrap(); + field.offset().and_then(|offset| { + let field_offset = offset / 8; + let field_name = ctx.rust_ident(name); + + Some(quote! { + assert_eq!(unsafe { &(*(0 as *const #canonical_ident)).#field_name as *const _ as usize }, + #field_offset, + concat!("Alignment of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))); + }) + }) + }) + .collect::<Vec<quote::Tokens>>(); + + asserts }; - let item = quote_item!(ctx.ext_cx(), + let item = quote! { #[test] - fn $fn_name() { - assert_eq!($size_of_expr, - $size, - concat!("Size of: ", stringify!($type_name))); + fn #fn_name() { + assert_eq!(#size_of_expr, + #size, + concat!("Size of: ", stringify!(#canonical_ident))); - $check_struct_align - $check_field_offset - }) - .unwrap(); + #check_struct_align + #( #check_field_offset )* + } + }; result.push(item); } } @@ -1907,63 +1883,25 @@ impl CodeGenerator for CompInfo { // NB: We can't use to_rust_ty here since for opaque types this tries to // use the specialization knowledge to generate a blob field. - let ty_for_impl = aster::AstBuilder::new() - .ty() - .path() - .segment(&canonical_name) - .with_generics(generics.clone()) - .build() - .build(); + let ty_for_impl = quote! { + #canonical_ident #generics + }; if needs_clone_impl { - let impl_ = quote_item!(ctx.ext_cx(), - impl X { + result.push(quote! { + impl #generics Clone for #ty_for_impl { fn clone(&self) -> Self { *self } } - ); - - let impl_ = match impl_.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), - _ => unreachable!(), - }; - - let clone_impl = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id("Clone") - .build() - .with_generics(generics.clone()) - .with_items(impl_) - .build_ty(ty_for_impl.clone()); - - result.push(clone_impl); + }); } if needs_default_impl { let prefix = ctx.trait_prefix(); - let impl_ = quote_item!(ctx.ext_cx(), - impl X { - fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } } + result.push(quote! { + impl #generics Default for #ty_for_impl { + fn default() -> Self { unsafe { ::#prefix::mem::zeroed() } } } - ); - - let impl_ = match impl_.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), - _ => unreachable!(), - }; - - let default_impl = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id("Default") - .build() - .with_generics(generics.clone()) - .with_items(impl_) - .build_ty(ty_for_impl.clone()); - - result.push(default_impl); + }); } if needs_debug_impl { @@ -1974,27 +1912,19 @@ impl CodeGenerator for CompInfo { self.kind(), ); - let debug_impl = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id("::std::fmt::Debug") - .build() - .with_generics(generics.clone()) - .with_items(impl_) - .build_ty(ty_for_impl.clone()); - - result.push(debug_impl); + result.push(quote! { + impl #generics ::std::fmt::Debug for #ty_for_impl { + #impl_ + } + }); } if !methods.is_empty() { - let methods = aster::AstBuilder::new() - .item() - .impl_() - .with_generics(generics) - .with_items(methods) - .build_ty(ty_for_impl); - result.push(methods); + result.push(quote! { + impl #generics #ty_for_impl { + #( #methods )* + } + }); } } } @@ -2003,7 +1933,7 @@ trait MethodCodegen { fn codegen_method<'a>( &self, ctx: &BindgenContext, - methods: &mut Vec<ast::ImplItem>, + methods: &mut Vec<quote::Tokens>, method_names: &mut HashMap<String, usize>, result: &mut CodegenResult<'a>, parent: &CompInfo, @@ -2014,7 +1944,7 @@ impl MethodCodegen for Method { fn codegen_method<'a>( &self, ctx: &BindgenContext, - methods: &mut Vec<ast::ImplItem>, + methods: &mut Vec<quote::Tokens>, method_names: &mut HashMap<String, usize>, result: &mut CodegenResult<'a>, _parent: &CompInfo, @@ -2067,45 +1997,15 @@ impl MethodCodegen for Method { name.push_str(&count.to_string()); } - let function_name = function_item.canonical_name(ctx); - let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item) - .unwrap(); + let function_name = ctx.rust_ident(function_item.canonical_name(ctx)); + let mut args = utils::fnsig_arguments(ctx, signature); + let mut ret = utils::fnsig_return_ty(ctx, signature); + if !self.is_static() && !self.is_constructor() { - let mutability = if self.is_const() { - ast::Mutability::Immutable + args[0] = if self.is_const() { + quote! { &self } } else { - ast::Mutability::Mutable - }; - - assert!(!fndecl.inputs.is_empty()); - - // FIXME: use aster here. - fndecl.inputs[0] = ast::Arg { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Rptr( - None, - ast::MutTy { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::ImplicitSelf, - span: ctx.span(), - }), - mutbl: mutability, - }, - ), - span: ctx.span(), - }), - pat: P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: ast::PatKind::Ident( - ast::BindingMode::ByValue(ast::Mutability::Immutable), - respan(ctx.span(), ctx.ext_cx().ident_of("self")), - None, - ), - span: ctx.span(), - }), - id: ast::DUMMY_NODE_ID, + quote! { &mut self } }; } @@ -2115,19 +2015,10 @@ impl MethodCodegen for Method { // Note that constructors in Clang are represented as functions with // return-type = void. if self.is_constructor() { - fndecl.inputs.remove(0); - fndecl.output = - ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), Self)); + args.remove(0); + ret = quote! { -> Self }; } - let sig = ast::MethodSig { - unsafety: ast::Unsafety::Unsafe, - abi: abi::Abi::Rust, - decl: P(fndecl), - generics: ast::Generics::default(), - constness: respan(ctx.span(), ast::Constness::NotConst), - }; - let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, ctx); @@ -2138,67 +2029,60 @@ impl MethodCodegen for Method { if self.is_constructor() { let prefix = ctx.trait_prefix(); let tmp_variable_decl = - quote_stmt!(ctx.ext_cx(), - let mut __bindgen_tmp = ::$prefix::mem::uninitialized()) - .unwrap(); + quote! { + let mut __bindgen_tmp = ::#prefix::mem::uninitialized() + }; stmts.push(tmp_variable_decl); - exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp); + exprs[0] = quote! { + &mut __bindgen_tmp + }; } else if !self.is_static() { assert!(!exprs.is_empty()); - exprs[0] = quote_expr!(ctx.ext_cx(), self); + exprs[0] = quote! { + self + }; }; - let call = aster::expr::ExprBuilder::new() - .call() - .id(function_name) - .with_args(exprs) - .build(); + let call = quote! { + #function_name (#( #exprs ),* ) + }; - stmts.push(ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Expr(call), - span: ctx.span(), - }); + stmts.push(call); if self.is_constructor() { - stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap()); + stmts.push(quote! { + __bindgen_tmp + }); } - let block = ast::Block { - stmts: stmts, - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span(), + let block = quote! { + #( #stmts );* }; let mut attrs = vec![]; attrs.push(attributes::inline()); - let item = ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(&name), - vis: ast::Visibility::Public, - attrs: attrs, - node: ast::ImplItemKind::Method(sig, P(block)), - defaultness: ast::Defaultness::Final, - span: ctx.span(), - }; - - methods.push(item); + let name = ctx.rust_ident(&name); + methods.push(quote! { + #[inline] + pub unsafe fn #name ( #( #args ),* ) #ret { + #block + } + }); } } /// A helper type to construct enums, either bitfield ones or rust-style ones. enum EnumBuilder<'a> { - Rust(aster::item::ItemEnumBuilder<aster::invoke::Identity>), + Rust(quote::Tokens), Bitfield { canonical_name: &'a str, - aster: P<ast::Item>, + tokens: quote::Tokens, }, - Consts { aster: P<ast::Item> }, + Consts(Vec<quote::Tokens>), ModuleConsts { module_name: &'a str, - module_items: Vec<P<ast::Item>>, + module_items: Vec<quote::Tokens>, }, } @@ -2206,41 +2090,47 @@ impl<'a> EnumBuilder<'a> { /// Create a new enum given an item builder, a canonical name, a name for /// the representation, and whether it should be represented as a rust enum. fn new( - aster: aster::item::ItemBuilder<aster::invoke::Identity>, name: &'a str, - repr: P<ast::Ty>, + attrs: Vec<quote::Tokens>, + repr: quote::Tokens, bitfield_like: bool, constify: bool, constify_module: bool, ) -> Self { + let ident = quote::Ident::new(name); if bitfield_like { EnumBuilder::Bitfield { canonical_name: name, - aster: aster - .tuple_struct(name) - .field() - .pub_() - .build_ty(repr) - .build(), + tokens: quote! { + #( #attrs )* + pub struct #ident (pub #repr); + }, } } else if constify { if constify_module { - let type_definition = aster::item::ItemBuilder::new() - .pub_() - .type_(CONSTIFIED_ENUM_MODULE_REPR_NAME) - .build_ty(repr); + let ident = quote::Ident::new(CONSTIFIED_ENUM_MODULE_REPR_NAME); + let type_definition = quote! { + pub type #ident = #repr; + }; EnumBuilder::ModuleConsts { module_name: name, module_items: vec![type_definition], } } else { - EnumBuilder::Consts { - aster: aster.type_(name).build_ty(repr), - } + EnumBuilder::Consts(vec![ + quote! { + pub type #ident = #repr; + } + ]) } } else { - EnumBuilder::Rust(aster.enum_(name)) + let mut tokens = quote! { + #( #attrs )* + pub enum #ident + }; + tokens.append("{"); + EnumBuilder::Rust(tokens) } } @@ -2250,28 +2140,25 @@ impl<'a> EnumBuilder<'a> { ctx: &BindgenContext, variant: &EnumVariant, mangling_prefix: Option<&String>, - rust_ty: P<ast::Ty>, + rust_ty: quote::Tokens, result: &mut CodegenResult<'b>, ) -> Self { let variant_name = ctx.rust_mangle(variant.name()); - let expr = aster::AstBuilder::new().expr(); let expr = match variant.val() { EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), - EnumVariantValue::Unsigned(v) => expr.uint(v), + EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v), }; match self { - EnumBuilder::Rust(b) => { - EnumBuilder::Rust(b.with_variant_(ast::Variant_ { - name: ctx.rust_ident(&*variant_name), - attrs: vec![], - data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), - disr_expr: Some(expr), - })) + EnumBuilder::Rust(tokens) => { + let name = ctx.rust_ident(variant_name); + EnumBuilder::Rust(quote! { + #tokens + #name = #expr, + }) } - EnumBuilder::Bitfield { - canonical_name, .. - } => { + + EnumBuilder::Bitfield { .. } => { let constant_name = match mangling_prefix { Some(prefix) => { Cow::Owned(format!("{}_{}", prefix, variant_name)) @@ -2279,20 +2166,14 @@ impl<'a> EnumBuilder<'a> { None => variant_name, }; - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(&*constant_name) - .expr() - .call() - .id(canonical_name) - .arg() - .build(expr) - .build() - .build(rust_ty); - result.push(constant); + let ident = ctx.rust_ident(constant_name); + result.push(quote! { + pub const #ident : #rust_ty = #rust_ty ( #expr ); + }); + self } + EnumBuilder::Consts { .. } => { @@ -2303,37 +2184,22 @@ impl<'a> EnumBuilder<'a> { None => variant_name, }; - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(&*constant_name) - .expr() - .build(expr) - .build(rust_ty); + let ident = ctx.rust_ident(constant_name); + result.push(quote! { + pub const #ident : #rust_ty = #expr ; + }); - result.push(constant); self } EnumBuilder::ModuleConsts { module_name, - module_items, - .. + mut module_items, } => { - // Variant type - let inside_module_type = aster::AstBuilder::new().ty().id( - CONSTIFIED_ENUM_MODULE_REPR_NAME, - ); - - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(&*variant_name) - .expr() - .build(expr) - .build(inside_module_type.clone()); - - let mut module_items = module_items.clone(); - module_items.push(constant); + let name = ctx.rust_ident(variant_name); + let ty = ctx.rust_ident(CONSTIFIED_ENUM_MODULE_REPR_NAME); + module_items.push(quote! { + pub const #name : #ty = #expr ; + }); EnumBuilder::ModuleConsts { module_name, @@ -2346,86 +2212,74 @@ impl<'a> EnumBuilder<'a> { fn build<'b>( self, ctx: &BindgenContext, - rust_ty: P<ast::Ty>, + rust_ty: quote::Tokens, result: &mut CodegenResult<'b>, - ) -> P<ast::Item> { + ) -> quote::Tokens { match self { - EnumBuilder::Rust(b) => b.build(), + EnumBuilder::Rust(mut t) => { + t.append("}"); + t + } EnumBuilder::Bitfield { canonical_name, - aster, + tokens, } => { let rust_ty_name = ctx.rust_ident_raw(canonical_name); let prefix = ctx.trait_prefix(); - let impl_ = quote_item!(ctx.ext_cx(), - impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty { + result.push(quote! { + impl ::#prefix::ops::BitOr<#rust_ty> for #rust_ty { type Output = Self; #[inline] fn bitor(self, other: Self) -> Self { - $rust_ty_name(self.0 | other.0) + #rust_ty_name(self.0 | other.0) } } - ).unwrap(); - result.push(impl_); + }); - let impl_ = quote_item!(ctx.ext_cx(), - impl ::$prefix::ops::BitOrAssign for $rust_ty { + result.push(quote! { + impl ::#prefix::ops::BitOrAssign for #rust_ty { #[inline] - fn bitor_assign(&mut self, rhs: $rust_ty) { + fn bitor_assign(&mut self, rhs: #rust_ty) { self.0 |= rhs.0; } } - ).unwrap(); - result.push(impl_); + }); - let impl_ = quote_item!(ctx.ext_cx(), - impl ::$prefix::ops::BitAnd<$rust_ty> for $rust_ty { + result.push(quote! { + impl ::#prefix::ops::BitAnd<#rust_ty> for #rust_ty { type Output = Self; #[inline] fn bitand(self, other: Self) -> Self { - $rust_ty_name(self.0 & other.0) + #rust_ty_name(self.0 & other.0) } } - ).unwrap(); - result.push(impl_); + }); - let impl_ = quote_item!(ctx.ext_cx(), - impl ::$prefix::ops::BitAndAssign for $rust_ty { + result.push(quote! { + impl ::#prefix::ops::BitAndAssign for #rust_ty { #[inline] - fn bitand_assign(&mut self, rhs: $rust_ty) { + fn bitand_assign(&mut self, rhs: #rust_ty) { self.0 &= rhs.0; } } - ).unwrap(); - result.push(impl_); + }); - aster + tokens } - EnumBuilder::Consts { - aster, .. - } => aster, + EnumBuilder::Consts(tokens) => quote! { #( #tokens )* }, EnumBuilder::ModuleConsts { module_items, module_name, - .. } => { - // Create module item with type and variant definitions - let module_item = P(ast::Item { - ident: ast::Ident::from_str(module_name), - attrs: vec![], - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Mod(ast::Mod { - inner: DUMMY_SP, - items: module_items, - }), - vis: ast::Visibility::Public, - span: DUMMY_SP, - }); - - module_item + let ident = ctx.rust_ident(module_name); + quote! { + pub mod #ident { + #( #module_items )* + } + } } } } @@ -2444,6 +2298,7 @@ impl CodeGenerator for Enum { debug_assert!(item.is_enabled_for_codegen(ctx)); let name = item.canonical_name(ctx); + let ident = ctx.rust_ident(&name); let enum_ty = item.expect_type(); let layout = enum_ty.layout(ctx); @@ -2485,8 +2340,6 @@ impl CodeGenerator for Enum { } }; - let mut builder = aster::AstBuilder::new().item().pub_(); - // FIXME(emilio): These should probably use the path so it can // disambiguate between namespaces, just like is_opaque etc. let is_bitfield = { @@ -2511,42 +2364,41 @@ impl CodeGenerator for Enum { let is_rust_enum = !is_bitfield && !is_constified_enum; + let mut attrs = vec![]; + // FIXME: Rust forbids repr with empty enums. Remove this condition when // this is allowed. // // TODO(emilio): Delegate this to the builders? if is_rust_enum { if !self.variants().is_empty() { - builder = builder.with_attr(attributes::repr(repr_name)); + attrs.push(attributes::repr(repr_name)); } } else if is_bitfield { - builder = builder.with_attr(attributes::repr("C")); + attrs.push(attributes::repr("C")); } if let Some(comment) = item.comment(ctx) { - builder = builder.with_attr(attributes::doc(comment)); + attrs.push(attributes::doc(comment)); } if !is_constified_enum { - let derives = - attributes::derives( - &["Debug", "Copy", "Clone", "PartialEq", "Eq", "Hash"], - ); - - builder = builder.with_attr(derives); + attrs.push(attributes::derives( + &["Debug", "Copy", "Clone", "PartialEq", "Eq", "Hash"], + )); } fn add_constant<'a>( ctx: &BindgenContext, enum_: &Type, // Only to avoid recomputing every time. - enum_canonical_name: &str, + enum_canonical_name: "e::Ident, // May be the same as "variant" if it's because the // enum is unnamed and we still haven't seen the // value. variant_name: &str, - referenced_name: &str, - enum_rust_ty: P<ast::Ty>, + referenced_name: "e::Ident, + enum_rust_ty: quote::Tokens, result: &mut CodegenResult<'a>, ) { let constant_name = if enum_.name().is_some() { @@ -2558,17 +2410,12 @@ impl CodeGenerator for Enum { } else { variant_name.into() }; + let constant_name = ctx.rust_ident(constant_name); - let constant = aster::AstBuilder::new() - .item() - .pub_() - .const_(constant_name) - .expr() - .path() - .ids(&[&*enum_canonical_name, referenced_name]) - .build() - .build(enum_rust_ty); - result.push(constant); + result.push(quote! { + pub const #constant_name : #enum_rust_ty = + #enum_canonical_name :: #referenced_name ; + }); } let repr = @@ -2577,8 +2424,8 @@ impl CodeGenerator for Enum { .unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name)); let mut builder = EnumBuilder::new( - builder, &name, + attrs, repr, is_bitfield, is_constified_enum, @@ -2586,7 +2433,7 @@ impl CodeGenerator for Enum { ); // A map where we keep a value -> variant relation. - let mut seen_values = HashMap::<_, String>::new(); + let mut seen_values = HashMap::<_, quote::Ident>::new(); let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); let is_toplevel = item.is_toplevel(ctx); @@ -2646,7 +2493,7 @@ impl CodeGenerator for Enum { add_constant( ctx, enum_ty, - &name, + &ident, &*mangled_name, existing_variant_name, enum_rust_ty.clone(), @@ -2671,7 +2518,7 @@ impl CodeGenerator for Enum { result, ); - let variant_name = ctx.rust_mangle(variant.name()); + let variant_name = ctx.rust_ident(variant.name()); // If it's an unnamed enum, or constification is enforced, // we also generate a constant so it can be properly @@ -2685,29 +2532,33 @@ impl CodeGenerator for Enum { let parent_name = parent_canonical_name.as_ref().unwrap(); - Cow::Owned( - format!("{}_{}", parent_name, variant_name), + quote::Ident::new( + format!( + "{}_{}", + parent_name, + variant_name + ) ) }; add_constant( ctx, enum_ty, - &name, - &mangled_name, + &ident, + mangled_name.as_ref(), &variant_name, enum_rust_ty.clone(), result, ); } - entry.insert(variant_name.into_owned()); + entry.insert(quote::Ident::new(variant_name)); } } } - let enum_ = builder.build(ctx, enum_rust_ty, result); - result.push(enum_); + let item = builder.build(ctx, enum_rust_ty, result); + result.push(item); } } @@ -2731,7 +2582,7 @@ trait TryToOpaque { &self, ctx: &BindgenContext, extra: &Self::Extra, - ) -> error::Result<P<ast::Ty>> { + ) -> error::Result<quote::Tokens> { self.try_get_layout(ctx, extra).map(|layout| { helpers::blob(layout) }) @@ -2759,7 +2610,7 @@ trait ToOpaque: TryToOpaque { &self, ctx: &BindgenContext, extra: &Self::Extra, - ) -> P<ast::Ty> { + ) -> quote::Tokens { let layout = self.get_layout(ctx, extra); helpers::blob(layout) } @@ -2785,7 +2636,7 @@ trait TryToRustTy { &self, ctx: &BindgenContext, extra: &Self::Extra, - ) -> error::Result<P<ast::Ty>>; + ) -> error::Result<quote::Tokens>; } /// Fallible conversion to a Rust type or an opaque blob with the correct size @@ -2800,7 +2651,7 @@ trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { &self, ctx: &BindgenContext, extra: &<Self as TryToRustTyOrOpaque>::Extra, - ) -> error::Result<P<ast::Ty>>; + ) -> error::Result<quote::Tokens>; } impl<E, T> TryToRustTyOrOpaque for T @@ -2814,7 +2665,7 @@ where &self, ctx: &BindgenContext, extra: &E, - ) -> error::Result<P<ast::Ty>> { + ) -> error::Result<quote::Tokens> { self.try_to_rust_ty(ctx, extra).or_else( |_| if let Ok(layout) = self.try_get_layout(ctx, extra) @@ -2851,7 +2702,7 @@ trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { &self, ctx: &BindgenContext, extra: &<Self as ToRustTyOrOpaque>::Extra, - ) -> P<ast::Ty>; + ) -> quote::Tokens; } impl<E, T> ToRustTyOrOpaque for T @@ -2864,7 +2715,7 @@ where &self, ctx: &BindgenContext, extra: &E, - ) -> P<ast::Ty> { + ) -> quote::Tokens { self.try_to_rust_ty(ctx, extra).unwrap_or_else(|_| { self.to_opaque(ctx, extra) }) @@ -2890,7 +2741,7 @@ impl TryToRustTy for ItemId { &self, ctx: &BindgenContext, _: &(), - ) -> error::Result<P<ast::Ty>> { + ) -> error::Result<quote::Tokens> { ctx.resolve_item(*self).try_to_rust_ty(ctx, &()) } } @@ -2914,7 +2765,7 @@ impl TryToRustTy for Item { &self, ctx: &BindgenContext, _: &(), - ) -> error::Result<P<ast::Ty>> { + ) -> error::Result<quote::Tokens> { self.kind().expect_type().try_to_rust_ty(ctx, self) } } @@ -2938,7 +2789,7 @@ impl TryToRustTy for Type { &self, ctx: &BindgenContext, item: &Item, - ) -> error::Result<P<ast::Ty>> { + ) -> error::Result<quote::Tokens> { use self::helpers::ast_ty::*; match *self.kind() { @@ -2946,11 +2797,11 @@ impl TryToRustTy for Type { // TODO: we should do something smart with nullptr, or maybe *const // c_void is enough? TypeKind::NullPtr => { - Ok(raw_type(ctx, "c_void").to_ptr(true, ctx.span())) + Ok(raw_type(ctx, "c_void").to_ptr(true)) } TypeKind::Int(ik) => { match ik { - IntKind::Bool => Ok(aster::ty::TyBuilder::new().bool()), + IntKind::Bool => Ok(quote! { bool }), IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")), @@ -2965,25 +2816,27 @@ impl TryToRustTy for Type { IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), - IntKind::I8 => Ok(aster::ty::TyBuilder::new().i8()), - IntKind::U8 => Ok(aster::ty::TyBuilder::new().u8()), - IntKind::I16 => Ok(aster::ty::TyBuilder::new().i16()), - IntKind::U16 => Ok(aster::ty::TyBuilder::new().u16()), - IntKind::I32 => Ok(aster::ty::TyBuilder::new().i32()), - IntKind::U32 => Ok(aster::ty::TyBuilder::new().u32()), - IntKind::I64 => Ok(aster::ty::TyBuilder::new().i64()), - IntKind::U64 => Ok(aster::ty::TyBuilder::new().u64()), + IntKind::I8 => Ok(quote! { i8 }), + IntKind::U8 => Ok(quote! { u8 }), + IntKind::I16 => Ok(quote! { i16 }), + IntKind::U16 => Ok(quote! { u16 }), + IntKind::I32 => Ok(quote! { i32 }), + IntKind::U32 => Ok(quote! { u32 }), + IntKind::I64 => Ok(quote! { i64 }), + IntKind::U64 => Ok(quote! { u64 }), IntKind::Custom { name, .. } => { let ident = ctx.rust_ident_raw(name); - Ok(quote_ty!(ctx.ext_cx(), $ident)) + Ok(quote! { + #ident + }) } // FIXME: This doesn't generate the proper alignment, but we // can't do better right now. We should be able to use // i128/u128 when they're available. IntKind::U128 | IntKind::I128 => { - Ok(aster::ty::TyBuilder::new().array(2).u64()) + Ok(quote! { [u64; 2] }) } } } @@ -2993,9 +2846,13 @@ impl TryToRustTy for Type { ctx.generated_bindegen_complex(); Ok(if ctx.options().enable_cxx_namespaces { - quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) + quote! { + root::__BindgenComplex<#float_path> + } } else { - quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) + quote! { + __BindgenComplex<#float_path> + } }) } TypeKind::Function(ref fs) => { @@ -3003,18 +2860,24 @@ impl TryToRustTy for Type { // sizeof(NonZero<_>) optimization with opaque blobs (because // they aren't NonZero), so don't *ever* use an or_opaque // variant here. - let ty = fs.try_to_rust_ty(ctx, item)?; + let ty = fs.try_to_rust_ty(ctx, &())?; let prefix = ctx.trait_prefix(); - Ok(quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)) + Ok(quote! { + ::#prefix::option::Option<#ty> + }) } TypeKind::Array(item, len) => { let ty = item.try_to_rust_ty(ctx, &())?; - Ok(aster::ty::TyBuilder::new().array(len).build(ty)) + Ok(quote! { + [ #ty ; #len ] + }) } TypeKind::Enum(..) => { + let mut tokens = quote! {}; let path = item.namespace_aware_canonical_path(ctx); - Ok(aster::AstBuilder::new().ty().path().ids(path).build()) + tokens.append_separated(path.into_iter().map(quote::Ident::new), "::"); + Ok(tokens) } TypeKind::TemplateInstantiation(ref inst) => { inst.try_to_rust_ty(ctx, item) @@ -3039,7 +2902,7 @@ impl TryToRustTy for Type { { Ok(ty) } else { - utils::build_templated_path(item, ctx, template_params) + utils::build_templated_path(item, ctx, vec![]) //template_params) } } TypeKind::Comp(ref info) => { @@ -3050,48 +2913,54 @@ impl TryToRustTy for Type { return self.try_to_opaque(ctx, item); } - let template_params = template_params.unwrap_or(vec![]); - utils::build_templated_path(item, ctx, template_params) + // let template_params = template_params.unwrap_or(vec![]); + utils::build_templated_path(item, ctx, vec![]) } TypeKind::Opaque => self.try_to_opaque(ctx, item), TypeKind::BlockPointer => { let void = raw_type(ctx, "c_void"); Ok(void.to_ptr( /* is_const = */ - false, - ctx.span(), + false )) } TypeKind::Pointer(inner) | TypeKind::Reference(inner) => { - let inner = ctx.resolve_item(inner); + let is_const = self.is_const() || ctx.resolve_type(inner).is_const(); + + let inner = inner.into_resolver().through_type_refs().resolve(ctx); let inner_ty = inner.expect_type(); // Regardless if we can properly represent the inner type, we // should always generate a proper pointer here, so use // infallible conversion of the inner type. - let ty = inner.to_rust_ty_or_opaque(ctx, &()); + let mut ty = inner.to_rust_ty_or_opaque(ctx, &()); + ty.append_implicit_template_params(ctx, inner); // Avoid the first function pointer level, since it's already // represented in Rust. if inner_ty.canonical_type(ctx).is_function() { Ok(ty) } else { - let is_const = self.is_const() || - inner.expect_type().is_const(); - Ok(ty.to_ptr(is_const, ctx.span())) + Ok(ty.to_ptr(is_const)) } } TypeKind::TypeParam => { let name = item.canonical_name(ctx); let ident = ctx.rust_ident(&name); - Ok(quote_ty!(ctx.ext_cx(), $ident)) + Ok(quote! { + #ident + }) } TypeKind::ObjCSel => { - Ok(quote_ty!(ctx.ext_cx(), objc::runtime::Sel)) + Ok(quote! { + objc::runtime::Sel + }) } TypeKind::ObjCId | - TypeKind::ObjCInterface(..) => Ok(quote_ty!(ctx.ext_cx(), id)), + TypeKind::ObjCInterface(..) => Ok(quote! { + id + }), ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } @@ -3120,108 +2989,81 @@ impl TryToRustTy for TemplateInstantiation { &self, ctx: &BindgenContext, item: &Item, - ) -> error::Result<P<ast::Ty>> { + ) -> error::Result<quote::Tokens> { if self.is_opaque(ctx, item) { return Err(error::Error::InstantiationOfOpaqueType); } - let decl = self.template_definition(); - let mut ty = decl.try_to_rust_ty(ctx, &())?.unwrap(); + let def = self.template_definition() + .into_resolver() + .through_type_refs() + .resolve(ctx); - let decl_params = match decl.self_template_params(ctx) { + let mut ty = quote! {}; + let def_path = def.namespace_aware_canonical_path(ctx); + ty.append_separated(def_path.into_iter().map(|p| ctx.rust_ident(p)), "::"); + + let def_params = match def.self_template_params(ctx) { Some(params) => params, None => { // This can happen if we generated an opaque type for a partial // template specialization, and we've hit an instantiation of // that partial specialization. extra_assert!( - decl.into_resolver() - .through_type_refs() - .resolve(ctx) - .is_opaque(ctx, &()) + def.is_opaque(ctx, &()) ); return Err(error::Error::InstantiationOfOpaqueType); } }; - // TODO: If the decl type is a template class/struct - // declaration's member template declaration, it could rely on + // TODO: If the definition type is a template class/struct + // definition's member template definition, it could rely on // generic template parameters from its outer template // class/struct. When we emit bindings for it, it could require // *more* type arguments than we have here, and we will need to // reconstruct them somehow. We don't have any means of doing // that reconstruction at this time. - if let ast::TyKind::Path(_, ref mut path) = ty.node { - let template_args = self.template_arguments() - .iter() - .zip(decl_params.iter()) - // Only pass type arguments for the type parameters that - // the decl uses. - .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) - .map(|(arg, _)| arg.try_to_rust_ty(ctx, &())) - .collect::<error::Result<Vec<_>>>()?; - - path.segments.last_mut().unwrap().parameters = - if template_args.is_empty() { - None - } else { - Some(P(ast::PathParameters::AngleBracketed( - ast::AngleBracketedParameterData { - lifetimes: vec![], - types: template_args, - bindings: vec![], - }, - ))) - } + let template_args = self.template_arguments() + .iter() + .zip(def_params.iter()) + // Only pass type arguments for the type parameters that + // the def uses. + .filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param)) + .map(|(arg, _)| { + let arg = arg.into_resolver().through_type_refs().resolve(ctx); + let mut ty = arg.try_to_rust_ty(ctx, &())?; + ty.append_implicit_template_params(ctx, arg); + Ok(ty) + }) + .collect::<error::Result<Vec<_>>>()?; + + if template_args.is_empty() { + return Ok(ty); } - Ok(P(ty)) + Ok(quote! { + #ty < #( #template_args ),* > + }) } } impl TryToRustTy for FunctionSig { - type Extra = Item; + type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, - item: &Item, - ) -> error::Result<P<ast::Ty>> { + _: &(), + ) -> error::Result<quote::Tokens> { // TODO: we might want to consider ignoring the reference return value. let ret = utils::fnsig_return_ty(ctx, &self); let arguments = utils::fnsig_arguments(ctx, &self); + let abi = self.abi(); - let decl = P(ast::FnDecl { - inputs: arguments, - output: ret, - variadic: self.is_variadic(), - }); - - let abi = match self.abi() { - Abi::Known(abi) => abi, - Abi::Unknown(unknown_abi) => { - panic!( - "Invalid or unknown abi {:?} for function {:?} {:?}", - unknown_abi, - item.canonical_name(ctx), - self - ); - } - }; - - let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: abi, - lifetimes: vec![], - decl: decl, - })); - - Ok(P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: fnty, - span: ctx.span(), - })) + Ok(quote! { + unsafe extern #abi fn ( #( #arguments ),* ) #ret + }) } } @@ -3270,7 +3112,8 @@ impl CodeGenerator for Function { _ => panic!("Signature kind is not a Function: {:?}", signature), }; - let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); + let args = utils::fnsig_arguments(ctx, signature); + let ret = utils::fnsig_return_ty(ctx, signature); let mut attributes = vec![]; @@ -3284,9 +3127,6 @@ impl CodeGenerator for Function { attributes.push(attributes::link_name(name)); } - let foreign_item_kind = - ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); - // Handle overloaded functions by giving each overload its own unique // suffix. let times_seen = result.overload_number(&canonical_name); @@ -3294,17 +3134,7 @@ impl CodeGenerator for Function { write!(&mut canonical_name, "{}", times_seen).unwrap(); } - let foreign_item = ast::ForeignItem { - ident: ctx.rust_ident_raw(&canonical_name), - attrs: attributes, - node: foreign_item_kind, - id: ast::DUMMY_NODE_ID, - span: ctx.span(), - vis: ast::Visibility::Public, - }; - let abi = match signature.abi() { - Abi::Known(abi) => abi, Abi::Unknown(unknown_abi) => { panic!( "Invalid or unknown abi {:?} for function {:?} ({:?})", @@ -3313,13 +3143,29 @@ impl CodeGenerator for Function { self ); } + abi => abi, }; - let item = ForeignModBuilder::new(abi) - .with_foreign_item(foreign_item) - .build(ctx); + let variadic = if signature.is_variadic() { + quote! { ... } + } else { + quote! {} + }; - result.push(item); + let ident = ctx.rust_ident(canonical_name); + let mut tokens = quote! { extern #abi }; + tokens.append("{\n"); + if !attributes.is_empty() { + tokens.append_separated(attributes, "\n"); + tokens.append("\n"); + } + let mut args = args; + args.push(variadic); + tokens.append(quote! { + pub fn #ident ( #( #args ),* ) #ret; + }); + tokens.append("\n}"); + result.push(tokens); } } @@ -3329,86 +3175,53 @@ fn objc_method_codegen( method: &ObjCMethod, class_name: Option<&str>, prefix: &str, -) -> (ast::ImplItem, ast::TraitItem) { +) -> (quote::Tokens, quote::Tokens) { let signature = method.signature(); let fn_args = utils::fnsig_arguments(ctx, signature); let fn_ret = utils::fnsig_return_ty(ctx, signature); let sig = if method.is_class_method() { - aster::AstBuilder::new() - .method_sig() - .unsafe_() - .fn_decl() - .with_args(fn_args.clone()) - .build(fn_ret) + let fn_args = fn_args.clone(); + quote! { + ( #( #fn_args ),* ) #fn_ret + } } else { - aster::AstBuilder::new() - .method_sig() - .unsafe_() - .fn_decl() - .self_() - .build(ast::SelfKind::Value(ast::Mutability::Immutable)) - .with_args(fn_args.clone()) - .build(fn_ret) + let fn_args = fn_args.clone(); + let args = iter::once(quote! { self }) + .chain(fn_args.into_iter()); + quote! { + ( #( #args ),* ) #fn_ret + } }; - // Collect the actual used argument names - let arg_names: Vec<_> = fn_args - .iter() - .map(|ref arg| match arg.pat.node { - ast::PatKind::Ident(_, ref spanning, _) => { - spanning.node.name.as_str().to_string() - } - _ => { - panic!("odd argument!"); - } - }) - .collect(); - - let methods_and_args = - ctx.rust_ident(&method.format_method_call(&arg_names)); + let methods_and_args = method.format_method_call(&fn_args); let body = if method.is_class_method() { let class_name = class_name .expect("Generating a class method without class name?") .to_owned(); let expect_msg = format!("Couldn't find {}", class_name); - quote_stmt!(ctx.ext_cx(), - msg_send![objc::runtime::Class::get($class_name).expect($expect_msg), $methods_and_args]) - .unwrap() + quote! { + msg_send!(objc::runtime::Class::get(#class_name).expect(#expect_msg), #methods_and_args) + } } else { - quote_stmt!(ctx.ext_cx(), msg_send![self, $methods_and_args]).unwrap() - }; - let block = ast::Block { - stmts: vec![body], - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span(), - }; - - let attrs = vec![]; - - let method_name = format!("{}{}", prefix, method.rust_name()); - - let impl_item = ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(&method_name), - vis: ast::Visibility::Inherited, // Public, - attrs: attrs.clone(), - node: ast::ImplItemKind::Method(sig.clone(), P(block)), - defaultness: ast::Defaultness::Final, - span: ctx.span(), + quote! { + msg_send!(self, #methods_and_args) + } }; - let trait_item = ast::TraitItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.rust_ident(&method_name), - attrs: attrs, - node: ast::TraitItemKind::Method(sig, None), - span: ctx.span(), - }; + let method_name = ctx.rust_ident(format!("{}{}", prefix, method.rust_name())); - (impl_item, trait_item) + ( + quote! { + unsafe fn #method_name #sig { + #body + } + }, + quote! { + unsafe fn #method_name #sig ; + } + ) } impl CodeGenerator for ObjCInterface { @@ -3440,7 +3253,6 @@ impl CodeGenerator for ObjCInterface { .collect(); for class_method in self.class_methods() { - let ambiquity = instance_method_names.contains(&class_method.rust_name()); let prefix = if ambiquity { "class_" } else { "" }; @@ -3454,24 +3266,22 @@ impl CodeGenerator for ObjCInterface { trait_items.push(trait_item) } - let trait_name = self.rust_name(); + let trait_name = ctx.rust_ident(self.rust_name()); - let trait_block = aster::AstBuilder::new() - .item() - .pub_() - .trait_(&trait_name) - .with_items(trait_items) - .build(); + let trait_block = quote! { + pub trait #trait_name { + #( #trait_items )* + } + }; - let ty_for_impl = quote_ty!(ctx.ext_cx(), id); - let impl_block = aster::AstBuilder::new() - .item() - .impl_() - .trait_() - .id(&trait_name) - .build() - .with_items(impl_items) - .build_ty(ty_for_impl); + let ty_for_impl = quote! { + id + }; + let impl_block = quote! { + impl #trait_name for #ty_for_impl { + #( #impl_items )* + } + }; result.push(trait_block); result.push(impl_block); @@ -3479,7 +3289,7 @@ impl CodeGenerator for ObjCInterface { } } -pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { +pub fn codegen(context: &mut BindgenContext) -> Vec<quote::Tokens> { context.gen(|context| { let _t = context.timer("codegen"); let counter = Cell::new(0); @@ -3511,35 +3321,32 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { mod utils { use super::{ToRustTyOrOpaque, TryToRustTy, error}; - use aster; use ir::context::{BindgenContext, ItemId}; use ir::function::FunctionSig; use ir::item::{Item, ItemCanonicalPath}; use ir::ty::TypeKind; + use quote; use std::mem; - use syntax::ast; - use syntax::ptr::P; pub fn prepend_objc_header( ctx: &BindgenContext, - result: &mut Vec<P<ast::Item>>, + result: &mut Vec<quote::Tokens>, ) { let use_objc = if ctx.options().objc_extern_crate { - quote_item!(ctx.ext_cx(), + quote! { #[macro_use] extern crate objc; - ).unwrap() + } } else { - quote_item!(ctx.ext_cx(), + quote! { use objc; - ).unwrap() + } }; - - let id_type = quote_item!(ctx.ext_cx(), + let id_type = quote! { #[allow(non_camel_case_types)] pub type id = *mut objc::runtime::Object; - ).unwrap(); + }; let items = vec![use_objc, id_type]; let old_items = mem::replace(result, items); @@ -3548,90 +3355,88 @@ mod utils { pub fn prepend_union_types( ctx: &BindgenContext, - result: &mut Vec<P<ast::Item>>, + result: &mut Vec<quote::Tokens>, ) { let prefix = ctx.trait_prefix(); // TODO(emilio): The fmt::Debug impl could be way nicer with // std::intrinsics::type_name, but... - let union_field_decl = quote_item!(ctx.ext_cx(), + let union_field_decl = quote! { #[repr(C)] - pub struct __BindgenUnionField<T>( - ::$prefix::marker::PhantomData<T>); - ).unwrap(); + pub struct __BindgenUnionField<T>(::#prefix::marker::PhantomData<T>); + }; - let union_field_impl = quote_item!(&ctx.ext_cx(), + let union_field_impl = quote! { impl<T> __BindgenUnionField<T> { #[inline] pub fn new() -> Self { - __BindgenUnionField(::$prefix::marker::PhantomData) + __BindgenUnionField(::#prefix::marker::PhantomData) } #[inline] pub unsafe fn as_ref(&self) -> &T { - ::$prefix::mem::transmute(self) + ::#prefix::mem::transmute(self) } #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { - ::$prefix::mem::transmute(self) + ::#prefix::mem::transmute(self) } } - ).unwrap(); + }; - let union_field_default_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::default::Default for __BindgenUnionField<T> { + let union_field_default_impl = quote! { + impl<T> ::#prefix::default::Default for __BindgenUnionField<T> { #[inline] fn default() -> Self { Self::new() } } - ).unwrap(); + }; - let union_field_clone_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::clone::Clone for __BindgenUnionField<T> { + let union_field_clone_impl = quote! { + impl<T> ::#prefix::clone::Clone for __BindgenUnionField<T> { #[inline] fn clone(&self) -> Self { Self::new() } } - ).unwrap(); + }; - let union_field_copy_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::marker::Copy for __BindgenUnionField<T> {} - ).unwrap(); + let union_field_copy_impl = quote! { + impl<T> ::#prefix::marker::Copy for __BindgenUnionField<T> {} + }; - let union_field_debug_impl = quote_item!(ctx.ext_cx(), - impl<T> ::$prefix::fmt::Debug for __BindgenUnionField<T> { - fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) - -> ::$prefix::fmt::Result { + let union_field_debug_impl = quote! { + impl<T> ::#prefix::fmt::Debug for __BindgenUnionField<T> { + fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter) + -> ::#prefix::fmt::Result { fmt.write_str("__BindgenUnionField") } } - ).unwrap(); + }; // The actual memory of the filed will be hashed, so that's why these // field doesn't do anything with the hash. - let union_field_hash_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::hash::Hash for __BindgenUnionField<T> { - fn hash<H: ::$prefix::hash::Hasher>(&self, _state: &mut H) { + let union_field_hash_impl = quote! { + impl<T> ::#prefix::hash::Hash for __BindgenUnionField<T> { + fn hash<H: ::#prefix::hash::Hasher>(&self, _state: &mut H) { } } - ).unwrap(); + }; - let union_field_partialeq_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::cmp::PartialEq for __BindgenUnionField<T> { + let union_field_partialeq_impl = quote! { + impl<T> ::#prefix::cmp::PartialEq for __BindgenUnionField<T> { fn eq(&self, _other: &__BindgenUnionField<T>) -> bool { true } } - ).unwrap(); + }; - let union_field_eq_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::cmp::Eq for __BindgenUnionField<T> { + let union_field_eq_impl = quote! { + impl<T> ::#prefix::cmp::Eq for __BindgenUnionField<T> { } - ) - .unwrap(); + }; let items = vec![union_field_decl, union_field_impl, @@ -3649,67 +3454,67 @@ mod utils { pub fn prepend_incomplete_array_types( ctx: &BindgenContext, - result: &mut Vec<P<ast::Item>>, + result: &mut Vec<quote::Tokens>, ) { let prefix = ctx.trait_prefix(); - let incomplete_array_decl = quote_item!(ctx.ext_cx(), + let incomplete_array_decl = quote! { #[repr(C)] #[derive(Default)] pub struct __IncompleteArrayField<T>( - ::$prefix::marker::PhantomData<T>); - ).unwrap(); + ::#prefix::marker::PhantomData<T>); + }; - let incomplete_array_impl = quote_item!(&ctx.ext_cx(), + let incomplete_array_impl = quote! { impl<T> __IncompleteArrayField<T> { #[inline] pub fn new() -> Self { - __IncompleteArrayField(::$prefix::marker::PhantomData) + __IncompleteArrayField(::#prefix::marker::PhantomData) } #[inline] pub unsafe fn as_ptr(&self) -> *const T { - ::$prefix::mem::transmute(self) + ::#prefix::mem::transmute(self) } #[inline] pub unsafe fn as_mut_ptr(&mut self) -> *mut T { - ::$prefix::mem::transmute(self) + ::#prefix::mem::transmute(self) } #[inline] pub unsafe fn as_slice(&self, len: usize) -> &[T] { - ::$prefix::slice::from_raw_parts(self.as_ptr(), len) + ::#prefix::slice::from_raw_parts(self.as_ptr(), len) } #[inline] pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { - ::$prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + ::#prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) } } - ).unwrap(); + }; - let incomplete_array_debug_impl = quote_item!(ctx.ext_cx(), - impl<T> ::$prefix::fmt::Debug for __IncompleteArrayField<T> { - fn fmt(&self, fmt: &mut ::$prefix::fmt::Formatter) - -> ::$prefix::fmt::Result { + let incomplete_array_debug_impl = quote! { + impl<T> ::#prefix::fmt::Debug for __IncompleteArrayField<T> { + fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter) + -> ::#prefix::fmt::Result { fmt.write_str("__IncompleteArrayField") } } - ).unwrap(); + }; - let incomplete_array_clone_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::clone::Clone for __IncompleteArrayField<T> { + let incomplete_array_clone_impl = quote! { + impl<T> ::#prefix::clone::Clone for __IncompleteArrayField<T> { #[inline] fn clone(&self) -> Self { Self::new() } } - ).unwrap(); + }; - let incomplete_array_copy_impl = quote_item!(&ctx.ext_cx(), - impl<T> ::$prefix::marker::Copy for __IncompleteArrayField<T> {} - ).unwrap(); + let incomplete_array_copy_impl = quote! { + impl<T> ::#prefix::marker::Copy for __IncompleteArrayField<T> {} + }; let items = vec![incomplete_array_decl, incomplete_array_impl, @@ -3722,17 +3527,16 @@ mod utils { } pub fn prepend_complex_type( - ctx: &BindgenContext, - result: &mut Vec<P<ast::Item>>, + result: &mut Vec<quote::Tokens>, ) { - let complex_type = quote_item!(ctx.ext_cx(), + let complex_type = quote! { #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(C)] pub struct __BindgenComplex<T> { pub re: T, pub im: T } - ).unwrap(); + }; let items = vec![complex_type]; let old_items = mem::replace(result, items); @@ -3743,53 +3547,38 @@ mod utils { item: &Item, ctx: &BindgenContext, template_params: Vec<ItemId>, - ) -> error::Result<P<ast::Ty>> { + ) -> error::Result<quote::Tokens> { let path = item.namespace_aware_canonical_path(ctx); - let builder = aster::AstBuilder::new().ty().path(); let template_params = template_params .iter() .map(|param| param.try_to_rust_ty(ctx, &())) .collect::<error::Result<Vec<_>>>()?; - // XXX: I suck at aster. - if path.len() == 1 { - return Ok( - builder - .segment(&path[0]) - .with_tys(template_params) - .build() - .build(), - ); - } + let mut tokens = quote! {}; + tokens.append_separated(path.into_iter().map(quote::Ident::new), "::"); - let mut builder = builder.id(&path[0]); - for (i, segment) in path.iter().skip(1).enumerate() { - // Take into account the skip(1) - builder = if i == path.len() - 2 { - // XXX Extra clone courtesy of the borrow checker. - builder - .segment(&segment) - .with_tys(template_params.clone()) - .build() - } else { - builder.segment(&segment).build() - } + if template_params.is_empty() { + Ok(tokens) + } else { + Ok(quote! { + #tokens < #( #template_params ),* > + }) } - - Ok(builder.build()) } - fn primitive_ty(ctx: &BindgenContext, name: &str) -> P<ast::Ty> { - let ident = ctx.rust_ident_raw(&name); - quote_ty!(ctx.ext_cx(), $ident) + fn primitive_ty(ctx: &BindgenContext, name: &str) -> quote::Tokens { + let ident = ctx.rust_ident_raw(name); + quote! { + #ident + } } pub fn type_from_named( ctx: &BindgenContext, name: &str, _inner: ItemId, - ) -> Option<P<ast::Ty>> { + ) -> Option<quote::Tokens> { // FIXME: We could use the inner item to check this is really a // primitive type but, who the heck overrides these anyway? Some(match name { @@ -3809,42 +3598,27 @@ mod utils { }) } - pub fn rust_fndecl_from_signature( - ctx: &BindgenContext, - sig: &Item, - ) -> P<ast::FnDecl> { - let signature = sig.kind().expect_type().canonical_type(ctx); - let signature = match *signature.kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("How?"), - }; - - let decl_ty = signature.try_to_rust_ty(ctx, sig).expect( - "function signature to Rust type conversion is infallible", - ); - match decl_ty.unwrap().node { - ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, - _ => panic!("How did this happen exactly?"), - } - } - pub fn fnsig_return_ty( ctx: &BindgenContext, sig: &FunctionSig, - ) -> ast::FunctionRetTy { + ) -> quote::Tokens { let return_item = ctx.resolve_item(sig.return_type()); if let TypeKind::Void = *return_item.kind().expect_type().kind() { - ast::FunctionRetTy::Default(ctx.span()) + quote! { } } else { - ast::FunctionRetTy::Ty(return_item.to_rust_ty_or_opaque(ctx, &())) + let ret_ty = return_item.to_rust_ty_or_opaque(ctx, &()); + quote! { + -> #ret_ty + } } } pub fn fnsig_arguments( ctx: &BindgenContext, sig: &FunctionSig, - ) -> Vec<ast::Arg> { + ) -> Vec<quote::Tokens> { use super::ToPtr; + let mut unnamed_arguments = 0; sig.argument_types().iter().map(|&(ref name, ty)| { let arg_item = ctx.resolve_item(ty); @@ -3861,13 +3635,15 @@ mod utils { let arg_ty = match *arg_ty.canonical_type(ctx).kind() { TypeKind::Array(t, _) => { t.to_rust_ty_or_opaque(ctx, &()) - .to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) + .to_ptr(ctx.resolve_type(t).is_const()) }, TypeKind::Pointer(inner) => { let inner = ctx.resolve_item(inner); let inner_ty = inner.expect_type(); if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { - quote_ty!(ctx.ext_cx(), id) + quote! { + id + } } else { arg_item.to_rust_ty_or_opaque(ctx, &()) } @@ -3886,12 +3662,11 @@ mod utils { }; assert!(!arg_name.is_empty()); + let arg_name = ctx.rust_ident(arg_name); - ast::Arg { - ty: arg_ty, - pat: aster::AstBuilder::new().pat().id(arg_name), - id: ast::DUMMY_NODE_ID, + quote! { + #arg_name : #arg_ty } - }).collect::<Vec<_>>() + }).collect() } } |