Store finer grained tokens of Signature
This is required in order for function pointers like `fn(&CxxString)` to
work, which requires the cxx bridge to emit `fn(&::cxx::CxxString)`
rather than a straight copy of the input tokens.
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 6afb548..1bb3628 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -273,7 +273,7 @@
.unwrap_or(call);
quote! {
#doc
- pub fn #ident(#(#args),*) #ret {
+ pub fn #ident(#args) #ret {
extern "C" {
#decl
}
diff --git a/syntax/impls.rs b/syntax/impls.rs
index 27aa43a..34fb851 100644
--- a/syntax/impls.rs
+++ b/syntax/impls.rs
@@ -116,7 +116,8 @@
args,
ret,
throws,
- tokens: _,
+ paren_token: _,
+ throws_tokens: _,
} = self;
let Signature {
fn_token: _,
@@ -124,9 +125,14 @@
args: args2,
ret: ret2,
throws: throws2,
- tokens: _,
+ paren_token: _,
+ throws_tokens: _,
} = other;
- receiver == receiver2 && args == args2 && ret == ret2 && throws == throws2
+ receiver == receiver2
+ && ret == ret2
+ && throws == throws2
+ && args.len() == args2.len()
+ && args.iter().zip(args2).all(|(arg, arg2)| arg == arg2)
}
}
@@ -138,10 +144,13 @@
args,
ret,
throws,
- tokens: _,
+ paren_token: _,
+ throws_tokens: _,
} = self;
receiver.hash(state);
- args.hash(state);
+ for arg in args {
+ arg.hash(state);
+ }
ret.hash(state);
throws.hash(state);
}
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 38e21b0..0d0328b 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -12,8 +12,11 @@
mod tokens;
pub mod types;
-use proc_macro2::{Ident, Span, TokenStream};
-use syn::{token::Brace, LitStr, Token};
+use self::parse::kw;
+use proc_macro2::{Ident, Span};
+use syn::punctuated::Punctuated;
+use syn::token::{Brace, Paren};
+use syn::{LitStr, Token};
pub use self::atom::Atom;
pub use self::doc::Doc;
@@ -55,10 +58,11 @@
pub struct Signature {
pub fn_token: Token![fn],
pub receiver: Option<Receiver>,
- pub args: Vec<Var>,
+ pub args: Punctuated<Var, Token![,]>,
pub ret: Option<Type>,
pub throws: bool,
- pub tokens: TokenStream,
+ pub paren_token: Paren,
+ pub throws_tokens: Option<(kw::Result, Token![<], Token![>])>,
}
#[derive(Eq, PartialEq, Hash)]
diff --git a/syntax/parse.rs b/syntax/parse.rs
index a00f8dd..8e674bd 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -4,12 +4,17 @@
};
use proc_macro2::Ident;
use quote::{format_ident, quote};
+use syn::punctuated::Punctuated;
use syn::{
Abi, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType, GenericArgument, Item,
- ItemForeignMod, ItemStruct, Pat, PathArguments, Result, ReturnType, Type as RustType,
+ ItemForeignMod, ItemStruct, Pat, PathArguments, Result, ReturnType, Token, Type as RustType,
TypeBareFn, TypePath, TypeReference,
};
+pub mod kw {
+ syn::custom_keyword!(Result);
+}
+
pub fn parse_items(items: Vec<Item>) -> Result<Vec<Api>> {
let mut apis = Vec::new();
for item in items {
@@ -151,8 +156,9 @@
}
let mut receiver = None;
- let mut args = Vec::new();
- for arg in &foreign_fn.sig.inputs {
+ let mut args = Punctuated::new();
+ for arg in foreign_fn.sig.inputs.pairs() {
+ let (arg, comma) = arg.into_tuple();
match arg {
FnArg::Receiver(receiver) => {
return Err(Error::new_spanned(receiver, "unsupported signature"))
@@ -164,7 +170,10 @@
};
let ty = parse_type(&arg.ty)?;
if ident != "self" {
- args.push(Var { ident, ty });
+ args.push_value(Var { ident, ty });
+ if let Some(comma) = comma {
+ args.push_punct(*comma);
+ }
continue;
}
if let Type::Ref(reference) = ty {
@@ -181,14 +190,13 @@
}
}
- let mut throws = false;
- let ret = parse_return_type(&foreign_fn.sig.output, &mut throws)?;
+ let mut throws_tokens = None;
+ let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
+ let throws = throws_tokens.is_some();
let doc = attrs::parse_doc(&foreign_fn.attrs)?;
let fn_token = foreign_fn.sig.fn_token;
let ident = foreign_fn.sig.ident.clone();
- let mut foreign_fn2 = foreign_fn.clone();
- foreign_fn2.attrs.clear();
- let tokens = quote!(#foreign_fn2);
+ let paren_token = foreign_fn.sig.paren_token;
let semi_token = foreign_fn.semi_token;
Ok(ExternFn {
@@ -201,7 +209,8 @@
args,
ret,
throws,
- tokens,
+ paren_token,
+ throws_tokens,
},
semi_token,
})
@@ -298,20 +307,24 @@
Ok(Var { ident, ty })
})
.collect::<Result<_>>()?;
- let mut throws = false;
- let ret = parse_return_type(&ty.output, &mut throws)?;
- let tokens = quote!(#ty);
+ let mut throws_tokens = None;
+ let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
+ let throws = throws_tokens.is_some();
Ok(Type::Fn(Box::new(Signature {
fn_token: ty.fn_token,
receiver: None,
args,
ret,
throws,
- tokens,
+ paren_token: ty.paren_token,
+ throws_tokens,
})))
}
-fn parse_return_type(ty: &ReturnType, throws: &mut bool) -> Result<Option<Type>> {
+fn parse_return_type(
+ ty: &ReturnType,
+ throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
+) -> Result<Option<Type>> {
let mut ret = match ty {
ReturnType::Default => return Ok(None),
ReturnType::Type(_, ret) => ret.as_ref(),
@@ -325,7 +338,8 @@
if ident == "Result" && generic.args.len() == 1 {
if let GenericArgument::Type(arg) = &generic.args[0] {
ret = arg;
- *throws = true;
+ *throws_tokens =
+ Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
}
}
}
diff --git a/syntax/tokens.rs b/syntax/tokens.rs
index 59bb0de..51592dd 100644
--- a/syntax/tokens.rs
+++ b/syntax/tokens.rs
@@ -63,12 +63,28 @@
impl ToTokens for ExternFn {
fn to_tokens(&self, tokens: &mut TokenStream) {
- self.sig.tokens.to_tokens(tokens);
+ // Notional token range for error reporting purposes.
+ self.sig.fn_token.to_tokens(tokens);
+ self.semi_token.to_tokens(tokens);
}
}
impl ToTokens for Signature {
fn to_tokens(&self, tokens: &mut TokenStream) {
- self.tokens.to_tokens(tokens);
+ self.fn_token.to_tokens(tokens);
+ self.paren_token.surround(tokens, |tokens| {
+ self.args.to_tokens(tokens);
+ });
+ if let Some(ret) = &self.ret {
+ Token.to_tokens(tokens);
+ if let Some((result, langle, rangle)) = self.throws_tokens {
+ result.to_tokens(tokens);
+ langle.to_tokens(tokens);
+ ret.to_tokens(tokens);
+ rangle.to_tokens(tokens);
+ } else {
+ ret.to_tokens(tokens);
+ }
+ }
}
}