mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-04-25 22:22:12 +00:00
Backend refactor (#411)
* remove BindgenAttrs from other backend::ast structs This is primarily a tool for use with the macro crate. Most of these attributes were ignored in the actual codegen, but a few were still being used. This is confusing when trying to add other sources for codegen (such as webidl and typescript). * move parsing logic to macro crate This makes the backend crate solely concerned with having an ast for which we can generate code.
This commit is contained in:
parent
056b45aeed
commit
2d50d5209b
File diff suppressed because it is too large
Load Diff
@ -273,7 +273,7 @@ impl ToTokens for ast::StructField {
|
|||||||
}
|
}
|
||||||
}).to_tokens(tokens);
|
}).to_tokens(tokens);
|
||||||
|
|
||||||
if self.opts.readonly() {
|
if self.readonly {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,12 +356,10 @@ impl ToTokens for ast::Export {
|
|||||||
});
|
});
|
||||||
quote! { me.#name }
|
quote! { me.#name }
|
||||||
}
|
}
|
||||||
None => {
|
None => match &self.class {
|
||||||
match &self.class {
|
Some(class) => quote! { #class::#name },
|
||||||
Some(class) => quote! { #class::#name },
|
None => quote! { #name },
|
||||||
None => quote! { #name }
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i, syn::ArgCaptured { ty, .. }) in self.function.arguments.iter().enumerate() {
|
for (i, syn::ArgCaptured { ty, .. }) in self.function.arguments.iter().enumerate() {
|
||||||
@ -591,7 +589,10 @@ impl ToTokens for ast::ImportFunction {
|
|||||||
ast::ImportFunctionKind::Method {
|
ast::ImportFunctionKind::Method {
|
||||||
ref ty, ref kind, ..
|
ref ty, ref kind, ..
|
||||||
} => {
|
} => {
|
||||||
if let ast::MethodKind::Normal = kind {
|
if let ast::MethodKind::Operation(ast::Operation {
|
||||||
|
is_static: false, ..
|
||||||
|
}) = kind
|
||||||
|
{
|
||||||
is_method = true;
|
is_method = true;
|
||||||
}
|
}
|
||||||
class_ty = Some(ty);
|
class_ty = Some(ty);
|
||||||
@ -618,9 +619,7 @@ impl ToTokens for ast::ImportFunction {
|
|||||||
subpat: None,
|
subpat: None,
|
||||||
..
|
..
|
||||||
}) => ident.clone(),
|
}) => ident.clone(),
|
||||||
syn::Pat::Wild(_) => {
|
syn::Pat::Wild(_) => syn::Ident::new(&format!("__genarg_{}", i), Span::call_site()),
|
||||||
syn::Ident::new(&format!("__genarg_{}", i), Span::call_site())
|
|
||||||
}
|
|
||||||
_ => panic!("unsupported pattern in foreign function"),
|
_ => panic!("unsupported pattern in foreign function"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -664,7 +663,7 @@ impl ToTokens for ast::ImportFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut exceptional_ret = quote!();
|
let mut exceptional_ret = quote!();
|
||||||
let exn_data = if self.function.opts.catch() {
|
let exn_data = if self.catch {
|
||||||
let exn_data = Ident::new("exn_data", Span::call_site());
|
let exn_data = Ident::new("exn_data", Span::call_site());
|
||||||
let exn_data_ptr = Ident::new("exn_data_ptr", Span::call_site());
|
let exn_data_ptr = Ident::new("exn_data_ptr", Span::call_site());
|
||||||
abi_argument_names.push(exn_data_ptr.clone());
|
abi_argument_names.push(exn_data_ptr.clone());
|
||||||
|
@ -4,9 +4,8 @@
|
|||||||
extern crate proc_macro2;
|
extern crate proc_macro2;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
#[macro_use]
|
|
||||||
extern crate syn;
|
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
extern crate syn;
|
||||||
|
|
||||||
extern crate wasm_bindgen_shared as shared;
|
extern crate wasm_bindgen_shared as shared;
|
||||||
|
|
||||||
|
@ -978,7 +978,8 @@ impl<'a> Context<'a> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.config.nodejs_experimental_modules {
|
if self.config.nodejs_experimental_modules {
|
||||||
self.imports.push_str("import { TextEncoder } from 'util';\n");
|
self.imports
|
||||||
|
.push_str("import { TextEncoder } from 'util';\n");
|
||||||
} else if self.config.nodejs {
|
} else if self.config.nodejs {
|
||||||
self.global(
|
self.global(
|
||||||
"
|
"
|
||||||
@ -1006,7 +1007,8 @@ impl<'a> Context<'a> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.config.nodejs_experimental_modules {
|
if self.config.nodejs_experimental_modules {
|
||||||
self.imports.push_str("import { TextDecoder } from 'util';\n");
|
self.imports
|
||||||
|
.push_str("import { TextDecoder } from 'util';\n");
|
||||||
} else if self.config.nodejs {
|
} else if self.config.nodejs {
|
||||||
self.global(
|
self.global(
|
||||||
"
|
"
|
||||||
@ -1788,7 +1790,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
import: &shared::ImportFunction,
|
import: &shared::ImportFunction,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if !self.cx.wasm_import_needed(&import.shim) {
|
if !self.cx.wasm_import_needed(&import.shim) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let descriptor = match self.cx.describe(&import.shim) {
|
let descriptor = match self.cx.describe(&import.shim) {
|
||||||
@ -1797,101 +1799,85 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let target = match &import.method {
|
let target = match &import.method {
|
||||||
Some(shared::MethodData {
|
Some(shared::MethodData { class, kind }) => {
|
||||||
class,
|
|
||||||
kind,
|
|
||||||
getter,
|
|
||||||
setter,
|
|
||||||
}) => {
|
|
||||||
let class = self.import_name(info, class)?;
|
let class = self.import_name(info, class)?;
|
||||||
if let shared::MethodKind::Constructor = kind {
|
match kind {
|
||||||
format!("new {}", class)
|
shared::MethodKind::Constructor => format!("new {}", class),
|
||||||
} else {
|
shared::MethodKind::Operation(shared::Operation { is_static, kind }) => {
|
||||||
let is_static = if let shared::MethodKind::Static = kind {
|
let target = if import.structural {
|
||||||
true
|
let location = if *is_static { &class } else { "this" };
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
let target = if let Some(g) = getter {
|
match kind {
|
||||||
if import.structural {
|
shared::OperationKind::Getter(g) => format!(
|
||||||
format!(
|
"function() {{
|
||||||
"function() {{
|
return {}.{};
|
||||||
return {}.{};
|
}}",
|
||||||
}}",
|
location, g
|
||||||
if is_static { &class } else { "this" },
|
),
|
||||||
g
|
shared::OperationKind::Setter(s) => format!(
|
||||||
)
|
"function(y) {{
|
||||||
} else {
|
{}.{} = y;
|
||||||
self.cx.expose_get_inherited_descriptor();
|
}}",
|
||||||
format!(
|
location, s
|
||||||
"GetOwnOrInheritedPropertyDescriptor\
|
),
|
||||||
({}{}, '{}').get",
|
shared::OperationKind::Regular => {
|
||||||
class,
|
let nargs = descriptor.unwrap_function().arguments.len();
|
||||||
if is_static { "" } else { ".prototype" },
|
let mut s = format!("function(");
|
||||||
g,
|
for i in 0..nargs - 1 {
|
||||||
)
|
if i > 0 {
|
||||||
}
|
drop(write!(s, ", "));
|
||||||
} else if let Some(s) = setter {
|
}
|
||||||
if import.structural {
|
drop(write!(s, "x{}", i));
|
||||||
format!(
|
}
|
||||||
"function(y) {{
|
s.push_str(") { \nreturn this.");
|
||||||
{}.{} = y;
|
s.push_str(&import.function.name);
|
||||||
}}",
|
s.push_str("(");
|
||||||
if is_static { &class } else { "this" },
|
for i in 0..nargs - 1 {
|
||||||
s
|
if i > 0 {
|
||||||
)
|
drop(write!(s, ", "));
|
||||||
} else {
|
}
|
||||||
self.cx.expose_get_inherited_descriptor();
|
drop(write!(s, "x{}", i));
|
||||||
format!(
|
}
|
||||||
"GetOwnOrInheritedPropertyDescriptor\
|
s.push_str(");\n}");
|
||||||
({}{}, '{}').set",
|
s
|
||||||
class,
|
|
||||||
if is_static { "" } else { ".prototype" },
|
|
||||||
s,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if import.structural {
|
|
||||||
let nargs = descriptor.unwrap_function().arguments.len();
|
|
||||||
let mut s = format!("function(");
|
|
||||||
for i in 0..nargs - 1 {
|
|
||||||
if i > 0 {
|
|
||||||
drop(write!(s, ", "));
|
|
||||||
}
|
}
|
||||||
drop(write!(s, "x{}", i));
|
|
||||||
}
|
}
|
||||||
s.push_str(") { \nreturn this.");
|
|
||||||
s.push_str(&import.function.name);
|
|
||||||
s.push_str("(");
|
|
||||||
for i in 0..nargs - 1 {
|
|
||||||
if i > 0 {
|
|
||||||
drop(write!(s, ", "));
|
|
||||||
}
|
|
||||||
drop(write!(s, "x{}", i));
|
|
||||||
}
|
|
||||||
s.push_str(");\n}");
|
|
||||||
s
|
|
||||||
} else {
|
} else {
|
||||||
format!(
|
let location = if *is_static { "" } else { ".prototype" };
|
||||||
"{}{}.{}",
|
|
||||||
class,
|
match kind {
|
||||||
if is_static { "" } else { ".prototype" },
|
shared::OperationKind::Getter(g) => {
|
||||||
import.function.name
|
self.cx.expose_get_inherited_descriptor();
|
||||||
)
|
format!(
|
||||||
}
|
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').get",
|
||||||
};
|
class, location, g,
|
||||||
self.cx.global(&format!(
|
)
|
||||||
"
|
}
|
||||||
const {}_target = {};
|
shared::OperationKind::Setter(s) => {
|
||||||
",
|
self.cx.expose_get_inherited_descriptor();
|
||||||
import.shim, target
|
format!(
|
||||||
));
|
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').set",
|
||||||
format!(
|
class, location, s,
|
||||||
"{}_target{}",
|
)
|
||||||
import.shim,
|
}
|
||||||
if is_static { "" } else { ".call" }
|
shared::OperationKind::Regular => {
|
||||||
)
|
format!("{}{}.{}", class, location, import.function.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.cx.global(&format!(
|
||||||
|
"
|
||||||
|
const {}_target = {};
|
||||||
|
",
|
||||||
|
import.shim, target
|
||||||
|
));
|
||||||
|
format!(
|
||||||
|
"{}_target{}",
|
||||||
|
import.shim,
|
||||||
|
if *is_static { "" } else { ".call" }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -22,3 +22,4 @@ syn = { version = '0.14', features = ['full'] }
|
|||||||
quote = '0.6'
|
quote = '0.6'
|
||||||
proc-macro2 = "0.4.4"
|
proc-macro2 = "0.4.4"
|
||||||
wasm-bindgen-backend = { path = "../backend", version = "=0.2.11" }
|
wasm-bindgen-backend = { path = "../backend", version = "=0.2.11" }
|
||||||
|
wasm-bindgen-shared = { path = "../shared", version = "=0.2.11" }
|
||||||
|
@ -3,21 +3,27 @@
|
|||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
extern crate proc_macro2;
|
extern crate proc_macro2;
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
|
extern crate wasm_bindgen_shared as shared;
|
||||||
|
#[macro_use]
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
extern crate wasm_bindgen_backend as backend;
|
extern crate wasm_bindgen_backend as backend;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
|
||||||
|
mod parser;
|
||||||
|
|
||||||
|
use parser::MacroParse;
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn wasm_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let item = syn::parse::<syn::Item>(input.clone()).expect("expected a valid Rust item");
|
let item = syn::parse::<syn::Item>(input.clone()).expect("expected a valid Rust item");
|
||||||
let opts = syn::parse::<backend::ast::BindgenAttrs>(attr)
|
let opts =
|
||||||
.expect("invalid arguments to #[wasm_bindgen]");
|
syn::parse::<parser::BindgenAttrs>(attr).expect("invalid arguments to #[wasm_bindgen]");
|
||||||
|
|
||||||
let mut ret = proc_macro2::TokenStream::new();
|
let mut ret = proc_macro2::TokenStream::new();
|
||||||
let mut program = backend::ast::Program::default();
|
let mut program = backend::ast::Program::default();
|
||||||
program.push_item(item, Some(opts), &mut ret);
|
item.macro_parse(&mut program, (Some(opts), &mut ret));
|
||||||
program.to_tokens(&mut ret);
|
program.to_tokens(&mut ret);
|
||||||
|
|
||||||
if cfg!(feature = "xxx_debug_only_print_generated_code") {
|
if cfg!(feature = "xxx_debug_only_print_generated_code") {
|
||||||
|
879
crates/macro/src/parser.rs
Normal file
879
crates/macro/src/parser.rs
Normal file
@ -0,0 +1,879 @@
|
|||||||
|
use backend::{ast, util::ident_ty};
|
||||||
|
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||||
|
use quote::ToTokens;
|
||||||
|
use shared;
|
||||||
|
use syn;
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct BindgenAttrs {
|
||||||
|
pub attrs: Vec<BindgenAttr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BindgenAttrs {
|
||||||
|
fn find(attrs: &mut Vec<syn::Attribute>) -> BindgenAttrs {
|
||||||
|
let pos = attrs
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|&(_, ref m)| m.path.segments[0].ident == "wasm_bindgen")
|
||||||
|
.map(|a| a.0);
|
||||||
|
let pos = match pos {
|
||||||
|
Some(i) => i,
|
||||||
|
None => return BindgenAttrs::default(),
|
||||||
|
};
|
||||||
|
let mut tts = attrs.remove(pos).tts.into_iter();
|
||||||
|
let tt = match tts.next() {
|
||||||
|
Some(TokenTree::Group(d)) => d.stream(),
|
||||||
|
Some(_) => panic!("malformed #[wasm_bindgen] attribute"),
|
||||||
|
None => return BindgenAttrs::default(),
|
||||||
|
};
|
||||||
|
if tts.next().is_some() {
|
||||||
|
panic!("malformed #[wasm_bindgen] attribute");
|
||||||
|
}
|
||||||
|
syn::parse(tt.into()).expect("malformed #[wasm_bindgen] attribute")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn module(&self) -> Option<&str> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::Module(s) => Some(&s[..]),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> Option<&str> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::Version(s) => Some(&s[..]),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn catch(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match a {
|
||||||
|
BindgenAttr::Catch => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constructor(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match a {
|
||||||
|
BindgenAttr::Constructor => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn static_method_of(&self) -> Option<&Ident> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::StaticMethodOf(c) => Some(c),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn method(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match a {
|
||||||
|
BindgenAttr::Method => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn js_namespace(&self) -> Option<&Ident> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::JsNamespace(s) => Some(s),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getter(&self) -> Option<Option<Ident>> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::Getter(g) => Some(g.clone()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setter(&self) -> Option<Option<Ident>> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::Setter(s) => Some(s.clone()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn structural(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match *a {
|
||||||
|
BindgenAttr::Structural => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readonly(&self) -> bool {
|
||||||
|
self.attrs.iter().any(|a| match *a {
|
||||||
|
BindgenAttr::Readonly => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn js_name(&self) -> Option<&Ident> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::JsName(s) => Some(s),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn js_class(&self) -> Option<&str> {
|
||||||
|
self.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| match a {
|
||||||
|
BindgenAttr::JsClass(s) => Some(&s[..]),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl syn::synom::Synom for BindgenAttrs {
|
||||||
|
named!(parse -> Self, alt!(
|
||||||
|
do_parse!(
|
||||||
|
opts: call!(
|
||||||
|
syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated
|
||||||
|
) >>
|
||||||
|
(BindgenAttrs {
|
||||||
|
attrs: opts.into_iter().collect(),
|
||||||
|
})
|
||||||
|
) => { |s| s }
|
||||||
|
|
|
||||||
|
epsilon!() => { |_| BindgenAttrs { attrs: Vec::new() } }
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
|
||||||
|
pub enum BindgenAttr {
|
||||||
|
Catch,
|
||||||
|
Constructor,
|
||||||
|
Method,
|
||||||
|
StaticMethodOf(Ident),
|
||||||
|
JsNamespace(Ident),
|
||||||
|
Module(String),
|
||||||
|
Version(String),
|
||||||
|
Getter(Option<Ident>),
|
||||||
|
Setter(Option<Ident>),
|
||||||
|
Structural,
|
||||||
|
Readonly,
|
||||||
|
JsName(Ident),
|
||||||
|
JsClass(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl syn::synom::Synom for BindgenAttr {
|
||||||
|
named!(parse -> Self, alt!(
|
||||||
|
call!(term, "catch") => { |_| BindgenAttr::Catch }
|
||||||
|
|
|
||||||
|
call!(term, "constructor") => { |_| BindgenAttr::Constructor }
|
||||||
|
|
|
||||||
|
call!(term, "method") => { |_| BindgenAttr::Method }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "static_method_of") >>
|
||||||
|
punct!(=) >>
|
||||||
|
cls: call!(term2ident) >>
|
||||||
|
(cls)
|
||||||
|
)=> { BindgenAttr::StaticMethodOf }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "getter") >>
|
||||||
|
val: option!(do_parse!(
|
||||||
|
punct!(=) >>
|
||||||
|
s: call!(term2ident) >>
|
||||||
|
(s)
|
||||||
|
)) >>
|
||||||
|
(val)
|
||||||
|
)=> { BindgenAttr::Getter }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "setter") >>
|
||||||
|
val: option!(do_parse!(
|
||||||
|
punct!(=) >>
|
||||||
|
s: call!(term2ident) >>
|
||||||
|
(s)
|
||||||
|
)) >>
|
||||||
|
(val)
|
||||||
|
)=> { BindgenAttr::Setter }
|
||||||
|
|
|
||||||
|
call!(term, "structural") => { |_| BindgenAttr::Structural }
|
||||||
|
|
|
||||||
|
call!(term, "readonly") => { |_| BindgenAttr::Readonly }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "js_namespace") >>
|
||||||
|
punct!(=) >>
|
||||||
|
ns: call!(term2ident) >>
|
||||||
|
(ns)
|
||||||
|
)=> { BindgenAttr::JsNamespace }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "module") >>
|
||||||
|
punct!(=) >>
|
||||||
|
s: syn!(syn::LitStr) >>
|
||||||
|
(s.value())
|
||||||
|
)=> { BindgenAttr::Module }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "version") >>
|
||||||
|
punct!(=) >>
|
||||||
|
s: syn!(syn::LitStr) >>
|
||||||
|
(s.value())
|
||||||
|
)=> { BindgenAttr::Version }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "js_name") >>
|
||||||
|
punct!(=) >>
|
||||||
|
ns: call!(term2ident) >>
|
||||||
|
(ns)
|
||||||
|
)=> { BindgenAttr::JsName }
|
||||||
|
|
|
||||||
|
do_parse!(
|
||||||
|
call!(term, "js_class") >>
|
||||||
|
punct!(=) >>
|
||||||
|
s: syn!(syn::LitStr) >>
|
||||||
|
(s.value())
|
||||||
|
)=> { BindgenAttr::JsClass }
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str) -> syn::synom::PResult<'a, ()> {
|
||||||
|
if let Some((ident, next)) = cursor.ident() {
|
||||||
|
if ident == name {
|
||||||
|
return Ok(((), next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syn::parse_error()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn term2ident<'a>(cursor: syn::buffer::Cursor<'a>) -> syn::synom::PResult<'a, Ident> {
|
||||||
|
match cursor.ident() {
|
||||||
|
Some(pair) => Ok(pair),
|
||||||
|
None => syn::parse_error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ConvertToAst<Ctx> {
|
||||||
|
type Target;
|
||||||
|
fn convert(self, context: Ctx) -> Self::Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ConvertToAst<()> for &'a mut syn::ItemStruct {
|
||||||
|
type Target = ast::Struct;
|
||||||
|
|
||||||
|
fn convert(self, (): ()) -> Self::Target {
|
||||||
|
if self.generics.params.len() > 0 {
|
||||||
|
panic!(
|
||||||
|
"structs with #[wasm_bindgen] cannot have lifetime or \
|
||||||
|
type parameters currently"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut fields = Vec::new();
|
||||||
|
if let syn::Fields::Named(names) = &mut self.fields {
|
||||||
|
for field in names.named.iter_mut() {
|
||||||
|
match field.vis {
|
||||||
|
syn::Visibility::Public(..) => {}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
let name = match &field.ident {
|
||||||
|
Some(n) => n,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let ident = self.ident.to_string();
|
||||||
|
let name_str = name.to_string();
|
||||||
|
let getter = shared::struct_field_get(&ident, &name_str);
|
||||||
|
let setter = shared::struct_field_set(&ident, &name_str);
|
||||||
|
let opts = BindgenAttrs::find(&mut field.attrs);
|
||||||
|
let comments = extract_doc_comments(&field.attrs);
|
||||||
|
fields.push(ast::StructField {
|
||||||
|
name: name.clone(),
|
||||||
|
struct_name: self.ident.clone(),
|
||||||
|
readonly: opts.readonly(),
|
||||||
|
ty: field.ty.clone(),
|
||||||
|
getter: Ident::new(&getter, Span::call_site()),
|
||||||
|
setter: Ident::new(&setter, Span::call_site()),
|
||||||
|
comments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let comments: Vec<String> = extract_doc_comments(&self.attrs);
|
||||||
|
ast::Struct {
|
||||||
|
name: self.ident.clone(),
|
||||||
|
fields,
|
||||||
|
comments,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertToAst<BindgenAttrs> for syn::ForeignItemFn {
|
||||||
|
type Target = ast::ImportKind;
|
||||||
|
|
||||||
|
fn convert(self, opts: BindgenAttrs) -> Self::Target {
|
||||||
|
let js_name = opts.js_name().unwrap_or(&self.ident).clone();
|
||||||
|
let wasm = function_from_decl(&js_name, self.decl, self.attrs, self.vis, false).0;
|
||||||
|
let catch = opts.catch();
|
||||||
|
let js_ret = if catch {
|
||||||
|
// TODO: this assumes a whole bunch:
|
||||||
|
//
|
||||||
|
// * The outer type is actually a `Result`
|
||||||
|
// * The error type is a `JsValue`
|
||||||
|
// * The actual type is the first type parameter
|
||||||
|
//
|
||||||
|
// should probably fix this one day...
|
||||||
|
extract_first_ty_param(wasm.ret.as_ref())
|
||||||
|
.expect("can't `catch` without returning a Result")
|
||||||
|
} else {
|
||||||
|
wasm.ret.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut operation_kind = ast::OperationKind::Regular;
|
||||||
|
if let Some(g) = opts.getter() {
|
||||||
|
operation_kind = ast::OperationKind::Getter(g);
|
||||||
|
}
|
||||||
|
if let Some(s) = opts.setter() {
|
||||||
|
operation_kind = ast::OperationKind::Setter(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
let kind = if opts.method() {
|
||||||
|
let class = wasm
|
||||||
|
.arguments
|
||||||
|
.get(0)
|
||||||
|
.expect("methods must have at least one argument");
|
||||||
|
let class = match class.ty {
|
||||||
|
syn::Type::Reference(syn::TypeReference {
|
||||||
|
mutability: None,
|
||||||
|
ref elem,
|
||||||
|
..
|
||||||
|
}) => &**elem,
|
||||||
|
_ => panic!("first argument of method must be a shared reference"),
|
||||||
|
};
|
||||||
|
let class_name = match *class {
|
||||||
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => path,
|
||||||
|
_ => panic!("first argument of method must be a path"),
|
||||||
|
};
|
||||||
|
let class_name = extract_path_ident(class_name)
|
||||||
|
.expect("first argument of method must be a bare type");
|
||||||
|
let class_name = opts
|
||||||
|
.js_class()
|
||||||
|
.map(Into::into)
|
||||||
|
.unwrap_or_else(|| class_name.to_string());
|
||||||
|
|
||||||
|
let kind = ast::MethodKind::Operation(ast::Operation {
|
||||||
|
is_static: false,
|
||||||
|
kind: operation_kind,
|
||||||
|
});
|
||||||
|
|
||||||
|
ast::ImportFunctionKind::Method {
|
||||||
|
class: class_name,
|
||||||
|
ty: class.clone(),
|
||||||
|
kind,
|
||||||
|
}
|
||||||
|
} else if let Some(cls) = opts.static_method_of() {
|
||||||
|
let class = cls.to_string();
|
||||||
|
let ty = ident_ty(cls.clone());
|
||||||
|
|
||||||
|
let kind = ast::MethodKind::Operation(ast::Operation {
|
||||||
|
is_static: true,
|
||||||
|
kind: operation_kind,
|
||||||
|
});
|
||||||
|
|
||||||
|
ast::ImportFunctionKind::Method { class, ty, kind }
|
||||||
|
} else if opts.constructor() {
|
||||||
|
let class = match wasm.ret {
|
||||||
|
Some(ref ty) => ty,
|
||||||
|
_ => panic!("constructor returns must be bare types"),
|
||||||
|
};
|
||||||
|
let class_name = match *class {
|
||||||
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => path,
|
||||||
|
_ => panic!("first argument of method must be a path"),
|
||||||
|
};
|
||||||
|
let class_name = extract_path_ident(class_name)
|
||||||
|
.expect("first argument of method must be a bare type");
|
||||||
|
|
||||||
|
ast::ImportFunctionKind::Method {
|
||||||
|
class: class_name.to_string(),
|
||||||
|
ty: class.clone(),
|
||||||
|
kind: ast::MethodKind::Constructor,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ast::ImportFunctionKind::Normal
|
||||||
|
};
|
||||||
|
|
||||||
|
let shim = {
|
||||||
|
let ns = match kind {
|
||||||
|
ast::ImportFunctionKind::Normal => "n",
|
||||||
|
ast::ImportFunctionKind::Method { ref class, .. } => class,
|
||||||
|
};
|
||||||
|
format!("__wbg_f_{}_{}_{}", js_name, self.ident, ns)
|
||||||
|
};
|
||||||
|
ast::ImportKind::Function(ast::ImportFunction {
|
||||||
|
function: wasm,
|
||||||
|
kind,
|
||||||
|
js_ret,
|
||||||
|
catch,
|
||||||
|
structural: opts.structural(),
|
||||||
|
rust_name: self.ident.clone(),
|
||||||
|
shim: Ident::new(&shim, Span::call_site()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertToAst<()> for syn::ForeignItemType {
|
||||||
|
type Target = ast::ImportKind;
|
||||||
|
|
||||||
|
fn convert(self, (): ()) -> Self::Target {
|
||||||
|
ast::ImportKind::Type(ast::ImportType {
|
||||||
|
vis: self.vis,
|
||||||
|
name: self.ident,
|
||||||
|
attrs: self.attrs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
|
||||||
|
type Target = ast::ImportKind;
|
||||||
|
|
||||||
|
fn convert(self, opts: BindgenAttrs) -> Self::Target {
|
||||||
|
if self.mutability.is_some() {
|
||||||
|
panic!("cannot import mutable globals yet")
|
||||||
|
}
|
||||||
|
let js_name = opts.js_name().unwrap_or(&self.ident);
|
||||||
|
let shim = format!("__wbg_static_accessor_{}_{}", js_name, self.ident);
|
||||||
|
ast::ImportKind::Static(ast::ImportStatic {
|
||||||
|
ty: *self.ty,
|
||||||
|
vis: self.vis,
|
||||||
|
rust_name: self.ident.clone(),
|
||||||
|
js_name: js_name.clone(),
|
||||||
|
shim: Ident::new(&shim, Span::call_site()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConvertToAst<()> for syn::ItemFn {
|
||||||
|
type Target = ast::Function;
|
||||||
|
|
||||||
|
fn convert(self, (): ()) -> Self::Target {
|
||||||
|
match self.vis {
|
||||||
|
syn::Visibility::Public(_) => {}
|
||||||
|
_ => panic!("can only bindgen public functions"),
|
||||||
|
}
|
||||||
|
if self.constness.is_some() {
|
||||||
|
panic!("can only bindgen non-const functions");
|
||||||
|
}
|
||||||
|
if self.unsafety.is_some() {
|
||||||
|
panic!("can only bindgen safe functions");
|
||||||
|
}
|
||||||
|
|
||||||
|
function_from_decl(&self.ident, self.decl, self.attrs, self.vis, false).0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_from_decl(
|
||||||
|
name: &Ident,
|
||||||
|
mut decl: Box<syn::FnDecl>,
|
||||||
|
attrs: Vec<syn::Attribute>,
|
||||||
|
vis: syn::Visibility,
|
||||||
|
allow_self: bool,
|
||||||
|
) -> (ast::Function, Option<ast::MethodSelf>) {
|
||||||
|
if decl.variadic.is_some() {
|
||||||
|
panic!("can't bindgen variadic functions")
|
||||||
|
}
|
||||||
|
if decl.generics.params.len() > 0 {
|
||||||
|
panic!("can't bindgen functions with lifetime or type parameters")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_no_lifetimes(&mut decl);
|
||||||
|
|
||||||
|
let syn::FnDecl { inputs, output, .. } = { *decl };
|
||||||
|
|
||||||
|
let mut method_self = None;
|
||||||
|
let arguments = inputs
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|arg| match arg {
|
||||||
|
syn::FnArg::Captured(c) => Some(c),
|
||||||
|
syn::FnArg::SelfValue(_) => {
|
||||||
|
assert!(method_self.is_none());
|
||||||
|
method_self = Some(ast::MethodSelf::ByValue);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
syn::FnArg::SelfRef(ref a) if allow_self => {
|
||||||
|
assert!(method_self.is_none());
|
||||||
|
if a.mutability.is_some() {
|
||||||
|
method_self = Some(ast::MethodSelf::RefMutable);
|
||||||
|
} else {
|
||||||
|
method_self = Some(ast::MethodSelf::RefShared);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => panic!("arguments cannot be `self` or ignored"),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let ret = match output {
|
||||||
|
syn::ReturnType::Default => None,
|
||||||
|
syn::ReturnType::Type(_, ty) => Some(*ty),
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
ast::Function {
|
||||||
|
name: name.clone(),
|
||||||
|
arguments,
|
||||||
|
ret,
|
||||||
|
rust_vis: vis,
|
||||||
|
rust_attrs: attrs,
|
||||||
|
},
|
||||||
|
method_self,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait MacroParse<Ctx> {
|
||||||
|
fn macro_parse(self, program: &mut ast::Program, context: Ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
|
||||||
|
fn macro_parse(
|
||||||
|
self,
|
||||||
|
program: &mut ast::Program,
|
||||||
|
(opts, tokens): (Option<BindgenAttrs>, &'a mut TokenStream),
|
||||||
|
) {
|
||||||
|
match self {
|
||||||
|
syn::Item::Fn(mut f) => {
|
||||||
|
let no_mangle = f
|
||||||
|
.attrs
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, m)| m.interpret_meta().map(|m| (i, m)))
|
||||||
|
.find(|&(_, ref m)| m.name() == "no_mangle");
|
||||||
|
match no_mangle {
|
||||||
|
Some((i, _)) => {
|
||||||
|
f.attrs.remove(i);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let comments = extract_doc_comments(&f.attrs);
|
||||||
|
f.to_tokens(tokens);
|
||||||
|
program.exports.push(ast::Export {
|
||||||
|
class: None,
|
||||||
|
method_self: None,
|
||||||
|
constructor: None,
|
||||||
|
function: f.convert(()),
|
||||||
|
comments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
syn::Item::Struct(mut s) => {
|
||||||
|
program.structs.push((&mut s).convert(()));
|
||||||
|
s.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
syn::Item::Impl(mut i) => {
|
||||||
|
(&mut i).macro_parse(program, ());
|
||||||
|
i.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
syn::Item::ForeignMod(mut f) => {
|
||||||
|
let opts = opts.unwrap_or_else(|| BindgenAttrs::find(&mut f.attrs));
|
||||||
|
f.macro_parse(program, opts);
|
||||||
|
}
|
||||||
|
syn::Item::Enum(e) => {
|
||||||
|
e.to_tokens(tokens);
|
||||||
|
e.macro_parse(program, ());
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"#[wasm_bindgen] can only be applied to a function, \
|
||||||
|
struct, enum, impl, or extern block"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MacroParse<()> for &'a mut syn::ItemImpl {
|
||||||
|
fn macro_parse(self, program: &mut ast::Program, (): ()) {
|
||||||
|
if self.defaultness.is_some() {
|
||||||
|
panic!("default impls are not supported");
|
||||||
|
}
|
||||||
|
if self.unsafety.is_some() {
|
||||||
|
panic!("unsafe impls are not supported");
|
||||||
|
}
|
||||||
|
if self.trait_.is_some() {
|
||||||
|
panic!("trait impls are not supported");
|
||||||
|
}
|
||||||
|
if self.generics.params.len() > 0 {
|
||||||
|
panic!("generic impls aren't supported");
|
||||||
|
}
|
||||||
|
let name = match *self.self_ty {
|
||||||
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => match extract_path_ident(path) {
|
||||||
|
Some(ident) => ident,
|
||||||
|
None => panic!("unsupported self type in impl"),
|
||||||
|
},
|
||||||
|
_ => panic!("unsupported self type in impl"),
|
||||||
|
};
|
||||||
|
for item in self.items.iter_mut() {
|
||||||
|
(&name, item).macro_parse(program, ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
|
||||||
|
fn macro_parse(self, program: &mut ast::Program, (): ()) {
|
||||||
|
let (class, item) = self;
|
||||||
|
replace_self(class, item);
|
||||||
|
let method = match item {
|
||||||
|
syn::ImplItem::Const(_) => panic!("const definitions aren't supported"),
|
||||||
|
syn::ImplItem::Type(_) => panic!("type definitions in impls aren't supported"),
|
||||||
|
syn::ImplItem::Method(ref mut m) => m,
|
||||||
|
syn::ImplItem::Macro(_) => panic!("macros in impls aren't supported"),
|
||||||
|
syn::ImplItem::Verbatim(_) => panic!("unparsed impl item?"),
|
||||||
|
};
|
||||||
|
match method.vis {
|
||||||
|
syn::Visibility::Public(_) => {}
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
if method.defaultness.is_some() {
|
||||||
|
panic!("default methods are not supported");
|
||||||
|
}
|
||||||
|
if method.sig.constness.is_some() {
|
||||||
|
panic!("can only bindgen non-const functions");
|
||||||
|
}
|
||||||
|
if method.sig.unsafety.is_some() {
|
||||||
|
panic!("can only bindgen safe functions");
|
||||||
|
}
|
||||||
|
|
||||||
|
let opts = BindgenAttrs::find(&mut method.attrs);
|
||||||
|
let comments = extract_doc_comments(&method.attrs);
|
||||||
|
let is_constructor = opts.constructor();
|
||||||
|
let constructor = if is_constructor {
|
||||||
|
Some(method.sig.ident.to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let (function, method_self) = function_from_decl(
|
||||||
|
&method.sig.ident,
|
||||||
|
Box::new(method.sig.decl.clone()),
|
||||||
|
method.attrs.clone(),
|
||||||
|
method.vis.clone(),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
program.exports.push(ast::Export {
|
||||||
|
class: Some(class.clone()),
|
||||||
|
method_self,
|
||||||
|
constructor,
|
||||||
|
function,
|
||||||
|
comments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MacroParse<()> for syn::ItemEnum {
|
||||||
|
fn macro_parse(self, program: &mut ast::Program, (): ()) {
|
||||||
|
match self.vis {
|
||||||
|
syn::Visibility::Public(_) => {}
|
||||||
|
_ => panic!("only public enums are allowed"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let variants = self
|
||||||
|
.variants
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, v)| {
|
||||||
|
match v.fields {
|
||||||
|
syn::Fields::Unit => (),
|
||||||
|
_ => panic!("Only C-Style enums allowed"),
|
||||||
|
}
|
||||||
|
let value = match v.discriminant {
|
||||||
|
Some((
|
||||||
|
_,
|
||||||
|
syn::Expr::Lit(syn::ExprLit {
|
||||||
|
attrs: _,
|
||||||
|
lit: syn::Lit::Int(ref int_lit),
|
||||||
|
}),
|
||||||
|
)) => {
|
||||||
|
if int_lit.value() > <u32>::max_value() as u64 {
|
||||||
|
panic!("Enums can only support numbers that can be represented as u32");
|
||||||
|
}
|
||||||
|
int_lit.value() as u32
|
||||||
|
}
|
||||||
|
None => i as u32,
|
||||||
|
_ => panic!("Enums may only have number literal values"),
|
||||||
|
};
|
||||||
|
|
||||||
|
ast::Variant {
|
||||||
|
name: v.ident.clone(),
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let comments = extract_doc_comments(&self.attrs);
|
||||||
|
program.enums.push(ast::Enum {
|
||||||
|
name: self.ident,
|
||||||
|
variants,
|
||||||
|
comments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MacroParse<BindgenAttrs> for syn::ItemForeignMod {
|
||||||
|
fn macro_parse(self, program: &mut ast::Program, opts: BindgenAttrs) {
|
||||||
|
match self.abi.name {
|
||||||
|
Some(ref l) if l.value() == "C" => {}
|
||||||
|
None => {}
|
||||||
|
_ => panic!("only foreign mods with the `C` ABI are allowed"),
|
||||||
|
}
|
||||||
|
for mut item in self.items.into_iter() {
|
||||||
|
let item_opts = {
|
||||||
|
let attrs = match item {
|
||||||
|
syn::ForeignItem::Fn(ref mut f) => &mut f.attrs,
|
||||||
|
syn::ForeignItem::Type(ref mut t) => &mut t.attrs,
|
||||||
|
syn::ForeignItem::Static(ref mut s) => &mut s.attrs,
|
||||||
|
_ => panic!("only foreign functions/types allowed for now"),
|
||||||
|
};
|
||||||
|
BindgenAttrs::find(attrs)
|
||||||
|
};
|
||||||
|
let module = item_opts.module().or(opts.module()).map(|s| s.to_string());
|
||||||
|
let version = item_opts
|
||||||
|
.version()
|
||||||
|
.or(opts.version())
|
||||||
|
.map(|s| s.to_string());
|
||||||
|
let js_namespace = item_opts.js_namespace().or(opts.js_namespace()).cloned();
|
||||||
|
let mut kind = match item {
|
||||||
|
syn::ForeignItem::Fn(f) => f.convert(item_opts),
|
||||||
|
syn::ForeignItem::Type(t) => t.convert(()),
|
||||||
|
syn::ForeignItem::Static(s) => s.convert(item_opts),
|
||||||
|
_ => panic!("only foreign functions/types allowed for now"),
|
||||||
|
};
|
||||||
|
|
||||||
|
program.imports.push(ast::Import {
|
||||||
|
module,
|
||||||
|
version,
|
||||||
|
js_namespace,
|
||||||
|
kind,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_first_ty_param(ty: Option<&syn::Type>) -> Option<Option<syn::Type>> {
|
||||||
|
let t = match ty {
|
||||||
|
Some(t) => t,
|
||||||
|
None => return Some(None),
|
||||||
|
};
|
||||||
|
let path = match *t {
|
||||||
|
syn::Type::Path(syn::TypePath {
|
||||||
|
qself: None,
|
||||||
|
ref path,
|
||||||
|
}) => path,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let seg = path.segments.last()?.into_value();
|
||||||
|
let generics = match seg.arguments {
|
||||||
|
syn::PathArguments::AngleBracketed(ref t) => t,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let ty = match *generics.args.first()?.into_value() {
|
||||||
|
syn::GenericArgument::Type(ref t) => t,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
match *ty {
|
||||||
|
syn::Type::Tuple(ref t) if t.elems.len() == 0 => return Some(None),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Some(Some(ty.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_self(name: &Ident, item: &mut syn::ImplItem) {
|
||||||
|
struct Walk<'a>(&'a Ident);
|
||||||
|
|
||||||
|
impl<'a> syn::visit_mut::VisitMut for Walk<'a> {
|
||||||
|
fn visit_ident_mut(&mut self, i: &mut Ident) {
|
||||||
|
if i == "Self" {
|
||||||
|
*i = self.0.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syn::visit_mut::VisitMut::visit_impl_item_mut(&mut Walk(name), item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract the documentation comments from a Vec of attributes
|
||||||
|
fn extract_doc_comments(attrs: &[syn::Attribute]) -> Vec<String> {
|
||||||
|
attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| {
|
||||||
|
// if the path segments include an ident of "doc" we know this
|
||||||
|
// this is a doc comment
|
||||||
|
if a.path.segments.iter().any(|s| s.ident.to_string() == "doc") {
|
||||||
|
Some(
|
||||||
|
// We want to filter out any Puncts so just grab the Literals
|
||||||
|
a.tts.clone().into_iter().filter_map(|t| match t {
|
||||||
|
TokenTree::Literal(lit) => {
|
||||||
|
// this will always return the quoted string, we deal with
|
||||||
|
// that in the cli when we read in the comments
|
||||||
|
Some(lit.to_string())
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//Fold up the [[String]] iter we created into Vec<String>
|
||||||
|
.fold(vec![], |mut acc, a| {acc.extend(a); acc})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_no_lifetimes(decl: &mut syn::FnDecl) {
|
||||||
|
struct Walk;
|
||||||
|
|
||||||
|
impl<'ast> syn::visit_mut::VisitMut for Walk {
|
||||||
|
fn visit_lifetime_mut(&mut self, _i: &mut syn::Lifetime) {
|
||||||
|
panic!(
|
||||||
|
"it is currently not sound to use lifetimes in function \
|
||||||
|
signatures"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syn::visit_mut::VisitMut::visit_fn_decl_mut(&mut Walk, decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_path_ident(path: &syn::Path) -> Option<Ident> {
|
||||||
|
if path.leading_colon.is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if path.segments.len() != 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
match path.segments.first().unwrap().value().arguments {
|
||||||
|
syn::PathArguments::None => {}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
path.segments.first().map(|v| v.value().ident.clone())
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
pub const SCHEMA_VERSION: &str = "5";
|
pub const SCHEMA_VERSION: &str = "6";
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct ProgramOnlySchema {
|
pub struct ProgramOnlySchema {
|
||||||
@ -48,15 +48,25 @@ pub struct ImportFunction {
|
|||||||
pub struct MethodData {
|
pub struct MethodData {
|
||||||
pub class: String,
|
pub class: String,
|
||||||
pub kind: MethodKind,
|
pub kind: MethodKind,
|
||||||
pub getter: Option<String>,
|
|
||||||
pub setter: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum MethodKind {
|
pub enum MethodKind {
|
||||||
Normal,
|
|
||||||
Constructor,
|
Constructor,
|
||||||
Static,
|
Operation(Operation),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct Operation {
|
||||||
|
pub is_static: bool,
|
||||||
|
pub kind: OperationKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub enum OperationKind {
|
||||||
|
Regular,
|
||||||
|
Getter(String),
|
||||||
|
Setter(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
|
@ -129,7 +129,7 @@ impl WebidlParse<()> for webidl::ast::Interface {
|
|||||||
impl WebidlParse<()> for webidl::ast::Typedef {
|
impl WebidlParse<()> for webidl::ast::Typedef {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let dest = rust_ident(&self.name);
|
let dest = rust_ident(&self.name);
|
||||||
@ -159,7 +159,7 @@ impl WebidlParse<()> for webidl::ast::Typedef {
|
|||||||
impl WebidlParse<()> for webidl::ast::NonPartialInterface {
|
impl WebidlParse<()> for webidl::ast::NonPartialInterface {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
program.imports.push(backend::ast::Import {
|
program.imports.push(backend::ast::Import {
|
||||||
@ -205,9 +205,8 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte
|
|||||||
arguments
|
arguments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| (&*arg.name, &*arg.type_, arg.variadic)),
|
.map(|arg| (&*arg.name, &*arg.type_, arg.variadic)),
|
||||||
kind,
|
|
||||||
Some(self_ty),
|
Some(self_ty),
|
||||||
vec![backend::ast::BindgenAttr::Constructor],
|
kind,
|
||||||
).map(|function| {
|
).map(|function| {
|
||||||
program.imports.push(backend::ast::Import {
|
program.imports.push(backend::ast::Import {
|
||||||
module: None,
|
module: None,
|
||||||
@ -303,24 +302,16 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Operation {
|
|||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
create_getter(
|
create_getter(&self.name, &self.type_, self_name, false)
|
||||||
&self.name,
|
.map(wrap_import_function)
|
||||||
&self.type_,
|
|
||||||
self_name,
|
|
||||||
backend::ast::MethodKind::Normal,
|
|
||||||
).map(wrap_import_function)
|
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
if !self.read_only {
|
if !self.read_only {
|
||||||
create_setter(
|
create_setter(&self.name, &self.type_, self_name, false)
|
||||||
&self.name,
|
.map(wrap_import_function)
|
||||||
&self.type_,
|
|
||||||
self_name,
|
|
||||||
backend::ast::MethodKind::Normal,
|
|
||||||
).map(wrap_import_function)
|
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,24 +322,16 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute {
|
|||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
create_getter(
|
create_getter(&self.name, &self.type_, self_name, true)
|
||||||
&self.name,
|
.map(wrap_import_function)
|
||||||
&self.type_,
|
|
||||||
self_name,
|
|
||||||
backend::ast::MethodKind::Static,
|
|
||||||
).map(wrap_import_function)
|
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
if !self.read_only {
|
if !self.read_only {
|
||||||
create_setter(
|
create_setter(&self.name, &self.type_, self_name, true)
|
||||||
&self.name,
|
.map(wrap_import_function)
|
||||||
&self.type_,
|
|
||||||
self_name,
|
|
||||||
backend::ast::MethodKind::Static,
|
|
||||||
).map(wrap_import_function)
|
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +342,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute {
|
|||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
create_basic_method(
|
create_basic_method(
|
||||||
@ -367,7 +350,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
|
|||||||
self.name.as_ref(),
|
self.name.as_ref(),
|
||||||
&self.return_type,
|
&self.return_type,
|
||||||
self_name,
|
self_name,
|
||||||
backend::ast::MethodKind::Normal,
|
false,
|
||||||
).map(wrap_import_function)
|
).map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
@ -378,7 +361,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation {
|
|||||||
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation {
|
impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation {
|
||||||
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
|
||||||
if util::is_chrome_only(&self.extended_attributes) {
|
if util::is_chrome_only(&self.extended_attributes) {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
create_basic_method(
|
create_basic_method(
|
||||||
@ -386,7 +369,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation {
|
|||||||
self.name.as_ref(),
|
self.name.as_ref(),
|
||||||
&self.return_type,
|
&self.return_type,
|
||||||
self_name,
|
self_name,
|
||||||
backend::ast::MethodKind::Static,
|
true,
|
||||||
).map(wrap_import_function)
|
).map(wrap_import_function)
|
||||||
.map(|import| program.imports.push(import));
|
.map(|import| program.imports.push(import));
|
||||||
|
|
||||||
|
@ -114,7 +114,10 @@ where
|
|||||||
let len = estimate.1.unwrap_or(estimate.0);
|
let len = estimate.1.unwrap_or(estimate.0);
|
||||||
let mut res = if let backend::ast::ImportFunctionKind::Method {
|
let mut res = if let backend::ast::ImportFunctionKind::Method {
|
||||||
ty,
|
ty,
|
||||||
kind: backend::ast::MethodKind::Normal,
|
kind:
|
||||||
|
backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
|
is_static: false, ..
|
||||||
|
}),
|
||||||
..
|
..
|
||||||
} = kind
|
} = kind
|
||||||
{
|
{
|
||||||
@ -146,9 +149,8 @@ where
|
|||||||
pub fn create_function<'a, I>(
|
pub fn create_function<'a, I>(
|
||||||
name: &str,
|
name: &str,
|
||||||
arguments: I,
|
arguments: I,
|
||||||
kind: backend::ast::ImportFunctionKind,
|
|
||||||
ret: Option<syn::Type>,
|
ret: Option<syn::Type>,
|
||||||
mut attrs: Vec<backend::ast::BindgenAttr>,
|
kind: backend::ast::ImportFunctionKind,
|
||||||
) -> Option<backend::ast::ImportFunction>
|
) -> Option<backend::ast::ImportFunction>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (&'a str, &'a webidl::ast::Type, bool)>,
|
I: Iterator<Item = (&'a str, &'a webidl::ast::Type, bool)>,
|
||||||
@ -160,12 +162,6 @@ where
|
|||||||
|
|
||||||
let js_ret = ret.clone();
|
let js_ret = ret.clone();
|
||||||
|
|
||||||
if let backend::ast::ImportFunctionKind::Method { .. } = kind {
|
|
||||||
attrs.push(backend::ast::BindgenAttr::Method);
|
|
||||||
}
|
|
||||||
|
|
||||||
let opts = backend::ast::BindgenAttrs { attrs };
|
|
||||||
|
|
||||||
let shim = {
|
let shim = {
|
||||||
let ns = match kind {
|
let ns = match kind {
|
||||||
backend::ast::ImportFunctionKind::Normal => "",
|
backend::ast::ImportFunctionKind::Normal => "",
|
||||||
@ -180,7 +176,6 @@ where
|
|||||||
name,
|
name,
|
||||||
arguments,
|
arguments,
|
||||||
ret,
|
ret,
|
||||||
opts,
|
|
||||||
rust_attrs: vec![],
|
rust_attrs: vec![],
|
||||||
rust_vis: syn::Visibility::Public(syn::VisPublic {
|
rust_vis: syn::Visibility::Public(syn::VisPublic {
|
||||||
pub_token: Default::default(),
|
pub_token: Default::default(),
|
||||||
@ -188,6 +183,8 @@ where
|
|||||||
},
|
},
|
||||||
rust_name,
|
rust_name,
|
||||||
js_ret,
|
js_ret,
|
||||||
|
catch: false,
|
||||||
|
structural: false,
|
||||||
kind,
|
kind,
|
||||||
shim,
|
shim,
|
||||||
})
|
})
|
||||||
@ -198,7 +195,7 @@ pub fn create_basic_method(
|
|||||||
name: Option<&String>,
|
name: Option<&String>,
|
||||||
return_type: &webidl::ast::ReturnType,
|
return_type: &webidl::ast::ReturnType,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
kind: backend::ast::MethodKind,
|
is_static: bool,
|
||||||
) -> Option<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
let name = match name {
|
let name = match name {
|
||||||
None => {
|
None => {
|
||||||
@ -211,7 +208,10 @@ pub fn create_basic_method(
|
|||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: self_name.to_string(),
|
class: self_name.to_string(),
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
ty: ident_ty(rust_ident(self_name)),
|
||||||
kind,
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
|
is_static,
|
||||||
|
kind: backend::ast::OperationKind::Regular,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret = match return_type {
|
let ret = match return_type {
|
||||||
@ -231,9 +231,8 @@ pub fn create_basic_method(
|
|||||||
arguments
|
arguments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| (&*arg.name, &*arg.type_, arg.variadic)),
|
.map(|arg| (&*arg.name, &*arg.type_, arg.variadic)),
|
||||||
kind,
|
|
||||||
ret,
|
ret,
|
||||||
Vec::new(),
|
kind,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +240,7 @@ pub fn create_getter(
|
|||||||
name: &str,
|
name: &str,
|
||||||
ty: &webidl::ast::Type,
|
ty: &webidl::ast::Type,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
kind: backend::ast::MethodKind,
|
is_static: bool,
|
||||||
) -> Option<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
let ret = match webidl_ty_to_syn_ty(ty, TypePosition::Return) {
|
let ret = match webidl_ty_to_syn_ty(ty, TypePosition::Return) {
|
||||||
None => {
|
None => {
|
||||||
@ -254,36 +253,35 @@ pub fn create_getter(
|
|||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: self_name.to_string(),
|
class: self_name.to_string(),
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
ty: ident_ty(rust_ident(self_name)),
|
||||||
kind,
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
|
is_static,
|
||||||
|
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
create_function(
|
create_function(name, iter::empty(), ret, kind)
|
||||||
name,
|
|
||||||
iter::empty(),
|
|
||||||
kind,
|
|
||||||
ret,
|
|
||||||
vec![backend::ast::BindgenAttr::Getter(Some(raw_ident(name)))],
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_setter(
|
pub fn create_setter(
|
||||||
name: &str,
|
name: &str,
|
||||||
ty: &webidl::ast::Type,
|
ty: &webidl::ast::Type,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
kind: backend::ast::MethodKind,
|
is_static: bool,
|
||||||
) -> Option<backend::ast::ImportFunction> {
|
) -> Option<backend::ast::ImportFunction> {
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = backend::ast::ImportFunctionKind::Method {
|
||||||
class: self_name.to_string(),
|
class: self_name.to_string(),
|
||||||
ty: ident_ty(rust_ident(self_name)),
|
ty: ident_ty(rust_ident(self_name)),
|
||||||
kind,
|
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||||
|
is_static,
|
||||||
|
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
create_function(
|
create_function(
|
||||||
&format!("set_{}", name),
|
&format!("set_{}", name),
|
||||||
iter::once((name, ty, false)),
|
iter::once((name, ty, false)),
|
||||||
kind,
|
|
||||||
None,
|
None,
|
||||||
vec![backend::ast::BindgenAttr::Setter(Some(raw_ident(name)))],
|
kind,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,24 +292,26 @@ pub fn is_chrome_only(ext_attrs: &[Box<ExtendedAttribute>]) -> bool {
|
|||||||
ExtendedAttribute::ArgumentList(al) => {
|
ExtendedAttribute::ArgumentList(al) => {
|
||||||
println!("ArgumentList");
|
println!("ArgumentList");
|
||||||
al.name == "ChromeOnly"
|
al.name == "ChromeOnly"
|
||||||
},
|
}
|
||||||
ExtendedAttribute::Identifier(i) => {
|
ExtendedAttribute::Identifier(i) => {
|
||||||
println!("Identifier");
|
println!("Identifier");
|
||||||
i.lhs == "ChromeOnly"
|
i.lhs == "ChromeOnly"
|
||||||
},
|
}
|
||||||
ExtendedAttribute::IdentifierList(il) => {
|
ExtendedAttribute::IdentifierList(il) => {
|
||||||
println!("IdentifierList");
|
println!("IdentifierList");
|
||||||
il.lhs == "ChromeOnly"
|
il.lhs == "ChromeOnly"
|
||||||
},
|
}
|
||||||
ExtendedAttribute::NamedArgumentList(nal) => {
|
ExtendedAttribute::NamedArgumentList(nal) => {
|
||||||
println!("NamedArgumentList");
|
println!("NamedArgumentList");
|
||||||
nal.lhs_name == "ChromeOnly"
|
nal.lhs_name == "ChromeOnly"
|
||||||
},
|
}
|
||||||
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => name == "ChromeOnly",
|
ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) => {
|
||||||
|
name == "ChromeOnly"
|
||||||
|
}
|
||||||
ExtendedAttribute::NoArguments(_na) => {
|
ExtendedAttribute::NoArguments(_na) => {
|
||||||
println!("NoArguments");
|
println!("NoArguments");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user