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
Show file tree
Hide file tree
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
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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,
),
}
Expand Down Expand Up @@ -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);
Expand All @@ -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() {
Expand Down Expand Up @@ -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);
Expand Down
20 changes: 10 additions & 10 deletions macro/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
};
Expand Down
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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()?;
Expand All @@ -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))
Expand All @@ -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
Expand Up @@ -319,6 +319,7 @@ impl PartialEq for Signature {
throws,
paren_token: _,
throws_tokens: _,
class,
} = self;
let Signature {
asyncness: asyncness2,
Expand All @@ -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()
Expand Down Expand Up @@ -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);
Expand All @@ -393,6 +397,7 @@ impl Hash for Signature {
}
ret.hash(state);
throws.hash(state);
class.hash(state);
}
}

Expand Down
8 changes: 4 additions & 4 deletions syntax/mangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
}
Expand Down
3 changes: 2 additions & 1 deletion syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading