Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

impl Blocks and Static Methods #1102

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions gen/src/write.rs
Original file line number Diff line number Diff line change
@@ -70,9 +70,9 @@ fn write_data_structures<'a>(out: &mut OutFile<'a>, apis: &'a [Api]) {
let mut methods_for_type = Map::new();
for api in apis {
if let Api::CxxFunction(efn) | Api::RustFunction(efn) = api {
if let Some(receiver) = &efn.sig.receiver {
if let Some(class) = &efn.sig.class {
methods_for_type
.entry(&receiver.ty.rust)
.entry(&class.rust)
.or_insert_with(Vec::new)
.push(efn);
}
@@ -762,12 +762,12 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
}
}
write!(out, " = ");
match &efn.receiver {
match &efn.class {
None => write!(out, "{}", efn.name.to_fully_qualified()),
Some(receiver) => write!(
Some(class) => write!(
out,
"&{}::{}",
out.types.resolve(&receiver.ty).name.to_fully_qualified(),
out.types.resolve(class).name.to_fully_qualified(),
efn.name.cxx,
),
}
@@ -948,13 +948,9 @@ fn write_rust_function_decl_impl(

fn write_rust_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
out.set_namespace(&efn.name.namespace);
let local_name = match &efn.sig.receiver {
let local_name = match &efn.sig.class {
None => efn.name.cxx.to_string(),
Some(receiver) => format!(
"{}::{}",
out.types.resolve(&receiver.ty).name.cxx,
efn.name.cxx,
),
Some(class) => format!("{}::{}", out.types.resolve(class).name.cxx, efn.name.cxx,),
};
let doc = &efn.doc;
let invoke = mangle::extern_fn(efn, out.types);
@@ -969,6 +965,9 @@ fn write_rust_function_shim_decl(
indirect_call: bool,
) {
begin_function_definition(out);
if sig.receiver.is_none() && sig.class.is_some() && out.header {
write!(out, "static ");
}
write_return_type(out, &sig.ret);
write!(out, "{}(", local_name);
for (i, arg) in sig.args.iter().enumerate() {
@@ -1003,11 +1002,11 @@ fn write_rust_function_shim_impl(
invoke: &Symbol,
indirect_call: bool,
) {
if out.header && sig.receiver.is_some() {
if out.header && sig.class.is_some() {
// We've already defined this inside the struct.
return;
}
if sig.receiver.is_none() {
if sig.class.is_none() {
// Member functions already documented at their declaration.
for line in doc.to_string().lines() {
writeln!(out, "//{}", line);
20 changes: 10 additions & 10 deletions macro/src/expand.rs
Original file line number Diff line number Diff line change
@@ -726,20 +726,20 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
#trampolines
#dispatch
});
match &efn.receiver {
match &efn.class {
None => {
quote! {
#doc
#attrs
#visibility #unsafety #fn_token #ident #generics #arg_list #ret #fn_body
}
}
Some(receiver) => {
Some(class) => {
let elided_generics;
let receiver_ident = &receiver.ty.rust;
let resolve = types.resolve(&receiver.ty);
let receiver_generics = if receiver.ty.generics.lt_token.is_some() {
&receiver.ty.generics
let class_ident = &class.rust;
let resolve = types.resolve(class);
let class_generics = if class.generics.lt_token.is_some() {
&class.generics
} else {
elided_generics = Lifetimes {
lt_token: resolve.generics.lt_token,
@@ -758,7 +758,7 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
&elided_generics
};
quote_spanned! {ident.span()=>
impl #generics #receiver_ident #receiver_generics {
impl #generics #class_ident #class_generics {
#doc
#attrs
#visibility #unsafety #fn_token #ident #arg_list #ret #fn_body
@@ -1176,10 +1176,10 @@ fn expand_rust_function_shim_super(
let vars = receiver_var.iter().chain(arg_vars);

let span = invoke.span();
let call = match &sig.receiver {
let call = match &sig.class {
None => quote_spanned!(span=> super::#invoke),
Some(receiver) => {
let receiver_type = &receiver.ty.rust;
Some(class) => {
let receiver_type = &class.rust;
quote_spanned!(span=> #receiver_type::#invoke)
}
};
122 changes: 105 additions & 17 deletions syntax/file.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::syntax::cfg::CfgExpr;
use crate::syntax::namespace::Namespace;
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Error, Parse, ParseStream, Result};
use syn::spanned::Spanned;
use syn::{
braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemImpl,
ItemStruct, ItemUse, LitStr, Token, Visibility,
braced, token, Abi, Attribute, ForeignItem as RustForeignItem, ForeignItemFn, ForeignItemMacro,
ForeignItemType, Ident, Item as RustItem, ItemEnum, ItemImpl, ItemStruct, ItemUse, LitStr,
Token, TypePath, Visibility,
};

pub struct Module {
@@ -36,6 +39,28 @@ pub struct ItemForeignMod {
pub items: Vec<ForeignItem>,
}

pub enum ForeignItem {
Type(ForeignItemType),
Fn(ForeignItemFn),
Macro(ForeignItemMacro),
Verbatim(TokenStream),
Impl(ForeignItemImpl),
Other(RustForeignItem),
}

pub struct ForeignItemImpl {
pub attrs: Vec<Attribute>,
pub unsafety: Option<Token![unsafe]>,
pub impl_token: Token![impl],
pub self_ty: TypePath,
pub brace_token: token::Brace,
pub items: Vec<ForeignImplItem>,
}

pub enum ForeignImplItem {
Fn(ForeignItemFn),
}

impl Parse for Module {
fn parse(input: ParseStream) -> Result<Self> {
let cfg = CfgExpr::Unconditional;
@@ -83,14 +108,16 @@ impl Parse for Item {
let attrs = input.call(Attribute::parse_outer)?;

let ahead = input.fork();
let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some()
&& ahead.parse::<Option<Token![extern]>>()?.is_some()
ahead.parse::<Option<Token![unsafe]>>()?;
if ahead.parse::<Option<Token![extern]>>()?.is_some()
&& ahead.parse::<Option<LitStr>>().is_ok()
&& ahead.peek(token::Brace)
{
Some(input.parse()?)
} else {
None
let unsafety = input.parse()?;
let mut foreign_mod = ItemForeignMod::parse(input)?;
foreign_mod.attrs.splice(..0, attrs);
foreign_mod.unsafety = unsafety;
return Ok(Item::ForeignMod(foreign_mod));
};

let item = input.parse()?;
@@ -103,16 +130,10 @@ impl Parse for Item {
item.attrs.splice(..0, attrs);
Ok(Item::Enum(item))
}
RustItem::ForeignMod(mut item) => {
item.attrs.splice(..0, attrs);
Ok(Item::ForeignMod(ItemForeignMod {
attrs: item.attrs,
unsafety,
abi: item.abi,
brace_token: item.brace_token,
items: item.items,
}))
}
RustItem::ForeignMod(item) => Err(syn::parse::Error::new(
item.span(),
"Reached generic ForeignMod code instead of custom ItemForeignMod, this is a bug",
)),
RustItem::Impl(mut item) => {
item.attrs.splice(..0, attrs);
Ok(Item::Impl(item))
@@ -125,3 +146,70 @@ impl Parse for Item {
}
}
}

impl Parse for ItemForeignMod {
fn parse(input: ParseStream) -> Result<Self> {
let mut attrs = input.call(Attribute::parse_outer)?;
let abi: Abi = input.parse()?;

let content;
let brace_token = braced!(content in input);
attrs.extend(content.call(Attribute::parse_inner)?);
let mut items = Vec::new();
while !content.is_empty() {
items.push(content.parse()?);
}
Ok(ItemForeignMod {
attrs,
unsafety: None,
abi,
brace_token,
items,
})
}
}

impl Parse for ForeignItem {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Token![impl]) {
return Ok(ForeignItem::Impl(ForeignItemImpl::parse(input)?));
}
Ok(match RustForeignItem::parse(input)? {
RustForeignItem::Type(ty) => ForeignItem::Type(ty),
RustForeignItem::Fn(f) => ForeignItem::Fn(f),
RustForeignItem::Macro(m) => ForeignItem::Macro(m),
RustForeignItem::Verbatim(t) => ForeignItem::Verbatim(t),
i => ForeignItem::Other(i),
})
}
}

impl Parse for ForeignItemImpl {
fn parse(input: ParseStream) -> Result<Self> {
let mut attrs = input.call(Attribute::parse_outer)?;
let unsafety: Option<Token![unsafe]> = input.parse()?;
let impl_token: Token![impl] = input.parse()?;
let self_ty: TypePath = input.parse()?;
let content;
let brace_token = braced!(content in input);
attrs.extend(content.call(Attribute::parse_inner)?);
let mut items = Vec::new();
while !content.is_empty() {
items.push(content.parse()?);
}
Ok(ForeignItemImpl {
attrs,
unsafety,
impl_token,
self_ty,
brace_token,
items,
})
}
}

impl Parse for ForeignImplItem {
fn parse(input: ParseStream) -> Result<Self> {
Ok(ForeignImplItem::Fn(input.parse()?))
}
}
5 changes: 5 additions & 0 deletions syntax/impls.rs
Original file line number Diff line number Diff line change
@@ -319,6 +319,7 @@ impl PartialEq for Signature {
throws,
paren_token: _,
throws_tokens: _,
class,
} = self;
let Signature {
asyncness: asyncness2,
@@ -331,10 +332,12 @@ impl PartialEq for Signature {
throws: throws2,
paren_token: _,
throws_tokens: _,
class: class2,
} = other;
asyncness.is_some() == asyncness2.is_some()
&& unsafety.is_some() == unsafety2.is_some()
&& receiver == receiver2
&& class == class2
&& ret == ret2
&& throws == throws2
&& args.len() == args2.len()
@@ -375,6 +378,7 @@ impl Hash for Signature {
throws,
paren_token: _,
throws_tokens: _,
class,
} = self;
asyncness.is_some().hash(state);
unsafety.is_some().hash(state);
@@ -393,6 +397,7 @@ impl Hash for Signature {
}
ret.hash(state);
throws.hash(state);
class.hash(state);
}
}

8 changes: 4 additions & 4 deletions syntax/mangle.rs
Original file line number Diff line number Diff line change
@@ -85,13 +85,13 @@ macro_rules! join {
}

pub fn extern_fn(efn: &ExternFn, types: &Types) -> Symbol {
match &efn.receiver {
Some(receiver) => {
let receiver_ident = types.resolve(&receiver.ty);
match &efn.class {
Some(class) => {
let class_ident = types.resolve(class);
join!(
efn.name.namespace,
CXXBRIDGE,
receiver_ident.name.cxx,
class_ident.name.cxx,
efn.name.rust,
)
}
3 changes: 2 additions & 1 deletion syntax/mod.rs
Original file line number Diff line number Diff line change
@@ -184,6 +184,7 @@ pub struct Signature {
pub fn_token: Token![fn],
pub generics: Generics,
pub receiver: Option<Receiver>,
pub class: Option<NamedType>,
pub args: Punctuated<Var, Token![,]>,
pub ret: Option<Type>,
pub throws: bool,
@@ -299,7 +300,7 @@ pub struct Pair {

// Wrapper for a type which needs to be resolved before it can be printed in
// C++.
#[derive(PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct NamedType {
pub rust: Ident,
pub generics: Lifetimes,
Loading