зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1429816 - Part 1: Bump syn and quote in xpcom. r=froydnj,mystor
--HG-- extra : rebase_source : 46d9431193b07658534bd5489477aadce7398e1a
This commit is contained in:
Родитель
4f61ba5899
Коммит
06d6bb6d34
|
@ -7,6 +7,6 @@ authors = ["Michael Layzell <michael@thelayzells.com>"]
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "0.11"
|
||||
quote = "0.3"
|
||||
syn = "0.13"
|
||||
quote = "0.5"
|
||||
lazy_static = "1.0"
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
extern crate proc_macro;
|
||||
|
@ -144,8 +145,9 @@ use quote::{ToTokens, Tokens};
|
|||
|
||||
use syn::*;
|
||||
|
||||
use syn::punctuated::Punctuated;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::default::Default;
|
||||
use std::error::Error;
|
||||
|
||||
/* These are the structs generated by the rust_macros.py script */
|
||||
|
@ -174,6 +176,18 @@ struct Interface {
|
|||
methods: Result<&'static [Method], &'static str>,
|
||||
}
|
||||
|
||||
impl Interface {
|
||||
fn base(&self) -> Result<Option<&'static Interface>, Box<Error>> {
|
||||
Ok(if let Some(base) = self.base {
|
||||
Some(*IFACES.get(base).ok_or_else(
|
||||
|| format!("Base interface {} does not exist", base)
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// This item contains the information generated by the procedural macro in
|
||||
/// the form of a `HashMap` from interface names to their descriptions.
|
||||
|
@ -211,11 +225,17 @@ impl ToTokens for RefcntKind {
|
|||
/// Scans through the attributes on a struct, and extracts the type of the refcount to use.
|
||||
fn get_refcnt_kind(attrs: &[Attribute]) -> Result<RefcntKind, Box<Error>> {
|
||||
for attr in attrs {
|
||||
if let MetaItem::NameValue(ref name, Lit::Str(ref value, _)) = attr.value {
|
||||
if name != "refcnt" {
|
||||
if let Some(Meta::NameValue(ref attr)) = attr.interpret_meta() {
|
||||
if attr.ident.as_ref() != "refcnt" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = if let Lit::Str(ref s) = attr.lit {
|
||||
s.value()
|
||||
} else {
|
||||
Err("Unexpected non-string value in #[refcnt]")?
|
||||
};
|
||||
|
||||
return if value == "nonatomic" {
|
||||
Ok(RefcntKind::NonAtomic)
|
||||
} else if value == "atomic" {
|
||||
|
@ -227,26 +247,30 @@ fn get_refcnt_kind(attrs: &[Attribute]) -> Result<RefcntKind, Box<Error>> {
|
|||
}
|
||||
}
|
||||
|
||||
Err("Expected #[refcnt] attribute".into())
|
||||
Err("Expected #[refcnt] attribute")?
|
||||
}
|
||||
|
||||
/// Scan the attributes looking for an #[xpimplements] attribute. The identifier
|
||||
/// arguments passed to this attribute are the interfaces which the type wants to
|
||||
/// directly implement.
|
||||
fn get_bases(attrs: &[Attribute]) -> Result<Vec<&str>, Box<Error>> {
|
||||
fn get_bases(attrs: &[Attribute]) -> Result<Vec<&'static Interface>, Box<Error>> {
|
||||
let mut inherits = Vec::new();
|
||||
for attr in attrs {
|
||||
if let MetaItem::List(ref name, ref items) = attr.value {
|
||||
if name != "xpimplements" {
|
||||
if let Some(Meta::List(ref attr)) = attr.interpret_meta() {
|
||||
if attr.ident.as_ref() != "xpimplements" {
|
||||
continue;
|
||||
}
|
||||
|
||||
for item in items {
|
||||
if let NestedMetaItem::MetaItem(MetaItem::Word(ref iface)) = *item {
|
||||
inherits.push(iface.as_ref());
|
||||
for item in &attr.nested {
|
||||
if let NestedMeta::Meta(Meta::Word(ref iface)) = *item {
|
||||
if let Some(&iface) = IFACES.get(iface.as_ref()) {
|
||||
inherits.push(iface);
|
||||
} else {
|
||||
Err(format!("Unexpected invalid base interface `{}` in \
|
||||
#[xpimplements(..)]", iface))?
|
||||
}
|
||||
} else {
|
||||
return Err("Unexpected non-identifier in xpimplements \
|
||||
attribute list".into());
|
||||
Err("Unexpected non-identifier in #[xpimplements(..)]")?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,82 +279,41 @@ fn get_bases(attrs: &[Attribute]) -> Result<Vec<&str>, Box<Error>> {
|
|||
}
|
||||
|
||||
/// Extract the fields list from the input struct.
|
||||
fn get_fields(di: &DeriveInput) -> Result<&[Field], Box<Error>> {
|
||||
match di.body {
|
||||
Body::Struct(VariantData::Struct(ref fields)) => Ok(fields),
|
||||
fn get_fields(di: &DeriveInput) -> Result<&Punctuated<Field, Token![,]>, Box<Error>> {
|
||||
match di.data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(ref named), ..
|
||||
}) => Ok(&named.named),
|
||||
_ => Err("The initializer struct must be a standard \
|
||||
named value struct definition".into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function for building a `syn::Ty` from a list of path segment.s
|
||||
fn mk_path_ty(segments: &[&str]) -> Ty {
|
||||
Ty::Path(None, Path {
|
||||
global: true,
|
||||
segments: segments.iter().map(|&seg| {
|
||||
PathSegment {
|
||||
ident: seg.into(),
|
||||
parameters: PathParameters::none(),
|
||||
}
|
||||
}).collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// Takes the `Init*` struct in, and generates a `DeriveInput` for the "real" struct.
|
||||
fn gen_real_struct(init: &DeriveInput, bases: &[&str], refcnt_ty: RefcntKind) -> Result<DeriveInput, Box<Error>> {
|
||||
fn gen_real_struct(init: &DeriveInput, bases: &[&Interface], refcnt_ty: RefcntKind) -> Result<DeriveInput, Box<Error>> {
|
||||
// Determine the name for the real struct based on the name of the
|
||||
// initializer struct's name.
|
||||
if !init.ident.as_ref().starts_with("Init") {
|
||||
return Err("The target struct's name must begin with Init".into());
|
||||
Err("The target struct's name must begin with Init")?
|
||||
}
|
||||
let name: Ident = init.ident.as_ref()[4..].into();
|
||||
let vis = &init.vis;
|
||||
|
||||
// Add the vtable and refcnt fields to the struct declaration.
|
||||
let mut fields = vec![];
|
||||
for base in bases {
|
||||
fields.push(Field {
|
||||
ident: Some(format!("__base_{}", base).into()),
|
||||
vis: Visibility::Inherited,
|
||||
attrs: vec![],
|
||||
ty: Ty::Ptr(
|
||||
Box::new(MutTy {
|
||||
ty: mk_path_ty(&["xpcom", "interfaces", &format!("{}VTable", base)]),
|
||||
mutability: Mutability::Immutable,
|
||||
})
|
||||
),
|
||||
});
|
||||
}
|
||||
let bases = bases.iter().map(|base| {
|
||||
let ident = Ident::from(format!("__base_{}", base.name));
|
||||
let vtable = Ident::from(format!("{}VTable", base.name));
|
||||
quote!(#ident : *const xpcom::interfaces::#vtable)
|
||||
});
|
||||
|
||||
fields.push(Field {
|
||||
ident: Some("__refcnt".into()),
|
||||
vis: Visibility::Inherited,
|
||||
attrs: vec![],
|
||||
ty: syn::parse_type(quote!(#refcnt_ty).as_ref())?,
|
||||
});
|
||||
|
||||
// Add the data fields from the initializer to the struct declaration.
|
||||
fields.extend(get_fields(init)?.iter().cloned());
|
||||
|
||||
// Create the real struct definition
|
||||
Ok(DeriveInput {
|
||||
ident: name,
|
||||
vis: init.vis.clone(),
|
||||
attrs: vec![
|
||||
// #[repr(C)]
|
||||
Attribute {
|
||||
style: AttrStyle::Outer,
|
||||
value: MetaItem::List(
|
||||
"repr".into(),
|
||||
vec![NestedMetaItem::MetaItem(
|
||||
MetaItem::Word("C".into())
|
||||
)],
|
||||
),
|
||||
is_sugared_doc: false,
|
||||
}
|
||||
],
|
||||
generics: Generics::default(),
|
||||
body: Body::Struct(VariantData::Struct(fields)),
|
||||
})
|
||||
let fields = get_fields(init)?;
|
||||
Ok(parse_quote! {
|
||||
#[repr(C)]
|
||||
#vis struct #name {
|
||||
#(#bases,)*
|
||||
__refcnt: #refcnt_ty,
|
||||
#fields
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Generates the `extern "system"` methods which are actually included in the
|
||||
|
@ -339,13 +322,10 @@ fn gen_real_struct(init: &DeriveInput, bases: &[&str], refcnt_ty: RefcntKind) ->
|
|||
/// These methods attempt to invoke the `recover_self` method to translate from
|
||||
/// the passed-in raw pointer to the actual `&self` value, and it is expected to
|
||||
/// be in scope.
|
||||
fn gen_vtable_methods(base: &str) -> Result<Tokens, Box<Error>> {
|
||||
let base_ty = Ident::from(base);
|
||||
fn gen_vtable_methods(iface: &Interface) -> Result<Tokens, Box<Error>> {
|
||||
let base_ty = Ident::from(iface.name);
|
||||
|
||||
let iface = IFACES.get(base)
|
||||
.ok_or(format!("Interface {} does not exist", base))?;
|
||||
|
||||
let base_methods = if let Some(base) = iface.base {
|
||||
let base_methods = if let Some(base) = iface.base()? {
|
||||
gen_vtable_methods(base)?
|
||||
} else {
|
||||
quote!{}
|
||||
|
@ -353,18 +333,18 @@ fn gen_vtable_methods(base: &str) -> Result<Tokens, Box<Error>> {
|
|||
|
||||
let methods = iface.methods
|
||||
.map_err(|reason| format!("Interface {} cannot be implemented in rust \
|
||||
because {} is not supported yet", base, reason))?;
|
||||
because {} is not supported yet", iface.name, reason))?;
|
||||
|
||||
let mut method_defs = Vec::new();
|
||||
for method in methods {
|
||||
let name = Ident::from(method.name);
|
||||
let ret = Ident::from(method.ret);
|
||||
let ret = syn::parse_str::<Type>(method.ret)?;
|
||||
|
||||
let mut params = Vec::new();
|
||||
let mut args = Vec::new();
|
||||
for param in method.params {
|
||||
let name = Ident::from(param.name);
|
||||
let ty = Ident::from(param.ty);
|
||||
let ty = syn::parse_str::<Type>(param.ty)?;
|
||||
|
||||
params.push(quote!{#name : #ty,});
|
||||
args.push(quote!{#name,});
|
||||
|
@ -386,18 +366,15 @@ fn gen_vtable_methods(base: &str) -> Result<Tokens, Box<Error>> {
|
|||
|
||||
/// Generates the VTable for a given base interface. This assumes that the
|
||||
/// implementations of each of the `extern "system"` methods are in scope.
|
||||
fn gen_inner_vtable(base: &str) -> Result<Tokens, Box<Error>> {
|
||||
let vtable_ty = Ident::from(format!("{}VTable", base));
|
||||
|
||||
let iface = IFACES.get(base)
|
||||
.ok_or(format!("Interface {} does not exist", base))?;
|
||||
fn gen_inner_vtable(iface: &Interface) -> Result<Tokens, Box<Error>> {
|
||||
let vtable_ty = Ident::from(format!("{}VTable", iface.name));
|
||||
|
||||
let methods = iface.methods
|
||||
.map_err(|reason| format!("Interface {} cannot be implemented in rust \
|
||||
because {} is not supported yet", base, reason))?;
|
||||
because {} is not supported yet", iface.name, reason))?;
|
||||
|
||||
// Generate the vtable for the base interface.
|
||||
let base_vtable = if let Some(base) = iface.base {
|
||||
let base_vtable = if let Some(base) = iface.base()? {
|
||||
let vt = gen_inner_vtable(base)?;
|
||||
quote!{__base: #vt,}
|
||||
} else {
|
||||
|
@ -416,9 +393,9 @@ fn gen_inner_vtable(base: &str) -> Result<Tokens, Box<Error>> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn gen_root_vtable(name: &Ident, base: &str) -> Result<Tokens, Box<Error>> {
|
||||
let field = Ident::from(format!("__base_{}", base));
|
||||
let vtable_ty = Ident::from(format!("{}VTable", base));
|
||||
fn gen_root_vtable(name: &Ident, base: &Interface) -> Result<Tokens, Box<Error>> {
|
||||
let field = Ident::from(format!("__base_{}", base.name));
|
||||
let vtable_ty = Ident::from(format!("{}VTable", base.name));
|
||||
let methods = gen_vtable_methods(base)?;
|
||||
let value = gen_inner_vtable(base)?;
|
||||
|
||||
|
@ -458,18 +435,18 @@ fn gen_root_vtable(name: &Ident, base: &str) -> Result<Tokens, Box<Error>> {
|
|||
/// value is the `QueryInterface` implementation, and the second is the `Coerce`
|
||||
/// implementation.
|
||||
fn gen_casts(
|
||||
seen: &mut HashSet<String>,
|
||||
base: &str,
|
||||
seen: &mut HashSet<&'static str>,
|
||||
iface: &Interface,
|
||||
name: &Ident,
|
||||
coerce_name: &Ident,
|
||||
vtable_field: &Ident,
|
||||
) -> Result<(Tokens, Tokens), Box<Error>> {
|
||||
if !seen.insert(base.to_owned()) {
|
||||
if !seen.insert(iface.name) {
|
||||
return Ok((quote!{}, quote!{}));
|
||||
}
|
||||
|
||||
// Generate the cast implementations for the base interfaces.
|
||||
let (base_qi, base_coerce) = if let Some(base) = IFACES[base].base {
|
||||
let (base_qi, base_coerce) = if let Some(base) = iface.base()? {
|
||||
gen_casts(
|
||||
seen,
|
||||
base,
|
||||
|
@ -482,7 +459,7 @@ fn gen_casts(
|
|||
};
|
||||
|
||||
// Add the if statment to QueryInterface for the base class.
|
||||
let base_name = Ident::from(base);
|
||||
let base_name = Ident::from(iface.name);
|
||||
|
||||
let qi = quote! {
|
||||
#base_qi
|
||||
|
@ -519,9 +496,8 @@ fn gen_casts(
|
|||
}
|
||||
|
||||
/// The root xpcom procedural macro definition.
|
||||
fn xpcom(input: &str) -> Result<Tokens, Box<Error>> {
|
||||
let init = syn::parse_derive_input(input)?;
|
||||
if init.generics != Generics::default() {
|
||||
fn xpcom(init: DeriveInput) -> Result<Tokens, Box<Error>> {
|
||||
if !init.generics.params.is_empty() || !init.generics.where_clause.is_none() {
|
||||
return Err("Cannot #[derive(xpcom)] on a generic type, due to \
|
||||
rust limitations. It is not possible to instantiate \
|
||||
a static with a generic type parameter, meaning that \
|
||||
|
@ -570,7 +546,7 @@ fn xpcom(input: &str) -> Result<Tokens, Box<Error>> {
|
|||
base,
|
||||
name,
|
||||
&coerce_name,
|
||||
&Ident::from(format!("__base_{}", base)),
|
||||
&Ident::from(format!("__base_{}", base.name)),
|
||||
)?;
|
||||
qi_impl.push(qi);
|
||||
coerce_impl.push(coerce);
|
||||
|
@ -689,7 +665,6 @@ fn xpcom(input: &str) -> Result<Tokens, Box<Error>> {
|
|||
|
||||
#[proc_macro_derive(xpcom, attributes(xpimplements, refcnt))]
|
||||
pub fn xpcom_internal(input: TokenStream) -> TokenStream {
|
||||
let source = input.to_string();
|
||||
let out_src = xpcom(&source).unwrap().to_string();
|
||||
out_src.parse().unwrap()
|
||||
xpcom(parse(input).expect("Invalid derive input"))
|
||||
.expect("#[derive(xpcom)] failed").into()
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче