Merge pull request #266 from ohanar/webidl_attributes

WebIDL: add support for typedefs and interface attributes
This commit is contained in:
Nick Fitzgerald 2018-06-11 21:42:15 -07:00 committed by GitHub
commit 0cd767c9d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 704 additions and 5 deletions

View File

@ -10,6 +10,7 @@ pub struct Program {
pub imports: Vec<Import>,
pub enums: Vec<Enum>,
pub structs: Vec<Struct>,
pub type_aliases: Vec<TypeAlias>,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
@ -120,6 +121,13 @@ pub enum TypeLocation {
ExportRet,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
pub struct TypeAlias {
pub vis: syn::Visibility,
pub dest: Ident,
pub src: syn::Type,
}
impl Program {
pub fn push_item(
&mut self,

View File

@ -59,6 +59,9 @@ impl ToTokens for ast::Program {
for e in self.enums.iter() {
e.to_tokens(tokens);
}
for a in self.type_aliases.iter() {
a.to_tokens(tokens);
}
// Generate a static which will eventually be what lives in a custom section
// of the wasm executable. For now it's just a plain old static, but we'll
@ -823,3 +826,15 @@ impl ToTokens for ast::ImportStatic {
}).to_tokens(into);
}
}
impl ToTokens for ast::TypeAlias {
fn to_tokens(&self, into: &mut TokenStream) {
let vis = &self.vis;
let dest = &self.dest;
let src = &self.src;
(quote! {
#[allow(non_camel_case_types)]
#vis type #dest = #src;
}).to_tokens(into);
}
}

View File

@ -123,6 +123,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::Definition {
webidl::ast::Definition::Interface(ref interface) => {
interface.webidl_parse(program, ())
}
webidl::ast::Definition::Typedef(ref typedef) => typedef.webidl_parse(program, ()),
// TODO
webidl::ast::Definition::Callback(..)
| webidl::ast::Definition::Dictionary(..)
@ -130,8 +131,7 @@ impl<'a> WebidlParse<'a> for webidl::ast::Definition {
| webidl::ast::Definition::Implements(..)
| webidl::ast::Definition::Includes(..)
| webidl::ast::Definition::Mixin(..)
| webidl::ast::Definition::Namespace(..)
| webidl::ast::Definition::Typedef(..) => {
| webidl::ast::Definition::Namespace(..) => {
warn!("Unsupported WebIDL definition: {:?}", self);
Ok(())
}
@ -156,6 +156,34 @@ impl<'a> WebidlParse<'a> for webidl::ast::Interface {
}
}
impl<'a> WebidlParse<'a> for webidl::ast::Typedef {
type Extra = ();
fn webidl_parse(&self, program: &mut backend::ast::Program, _: ()) -> Result<()> {
let dest = rust_ident(&self.name);
let src = match webidl_ty_to_syn_ty(&self.type_, TypePosition::Return) {
Some(src) => src,
None => {
warn!(
"typedef's source type is not yet supported: {:?}. Skipping typedef {:?}",
*self.type_, self
);
return Ok(());
}
};
program.type_aliases.push(backend::ast::TypeAlias {
vis: syn::Visibility::Public(syn::VisPublic {
pub_token: Default::default(),
}),
dest,
src,
});
Ok(())
}
}
impl<'a> WebidlParse<'a> for webidl::ast::NonPartialInterface {
type Extra = ();
@ -185,10 +213,12 @@ impl<'a> WebidlParse<'a> for webidl::ast::InterfaceMember {
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
match *self {
webidl::ast::InterfaceMember::Attribute(ref attr) => {
attr.webidl_parse(program, self_name)
}
webidl::ast::InterfaceMember::Operation(ref op) => op.webidl_parse(program, self_name),
// TODO
webidl::ast::InterfaceMember::Attribute(_)
| webidl::ast::InterfaceMember::Const(_)
webidl::ast::InterfaceMember::Const(_)
| webidl::ast::InterfaceMember::Iterable(_)
| webidl::ast::InterfaceMember::Maplike(_)
| webidl::ast::InterfaceMember::Setlike(_) => {
@ -199,6 +229,21 @@ impl<'a> WebidlParse<'a> for webidl::ast::InterfaceMember {
}
}
impl<'a> WebidlParse<'a> for webidl::ast::Attribute {
type Extra = &'a str;
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
match *self {
webidl::ast::Attribute::Regular(ref attr) => attr.webidl_parse(program, self_name),
// TODO
webidl::ast::Attribute::Static(_) | webidl::ast::Attribute::Stringifier(_) => {
warn!("Unsupported WebIDL attribute: {:?}", self);
Ok(())
}
}
}
}
impl<'a> WebidlParse<'a> for webidl::ast::Operation {
type Extra = &'a str;
@ -257,6 +302,10 @@ enum TypePosition {
}
fn webidl_ty_to_syn_ty(ty: &webidl::ast::Type, pos: TypePosition) -> Option<syn::Type> {
// nullable types are not yet supported (see issue #14)
if ty.nullable {
return None;
}
Some(match ty.kind {
// `any` becomes `::wasm_bindgen::JsValue`.
webidl::ast::TypeKind::Any => {
@ -332,6 +381,151 @@ fn simple_fn_arg(ident: Ident, ty: syn::Type) -> syn::FnArg {
})
}
impl<'a> WebidlParse<'a> for webidl::ast::RegularAttribute {
type Extra = &'a str;
fn webidl_parse(&self, program: &mut backend::ast::Program, self_name: &'a str) -> Result<()> {
fn create_getter(
this: &webidl::ast::RegularAttribute,
self_name: &str,
) -> Option<backend::ast::Import> {
let name = raw_ident(&this.name);
let rust_name = rust_ident(&this.name.to_snake_case());
let (output, ret) = match webidl_ty_to_syn_ty(&this.type_, TypePosition::Return) {
None => {
warn!("Attribute's type does not yet support reading: {:?}. Skipping getter binding for {:?}",
this.type_, this);
return None;
}
Some(ty) => (
syn::ReturnType::Type(Default::default(), Box::new(ty.clone())),
Some(ty),
),
};
let self_ty = ident_ty(rust_ident(self_name));
let self_ref_ty = shared_ref(self_ty.clone());
let shim = rust_ident(&format!("__wbg_f_{}_{}_{}", name, rust_name, self_name));
Some(backend::ast::Import {
module: None,
version: None,
js_namespace: None,
kind: backend::ast::ImportKind::Function(backend::ast::ImportFunction {
function: backend::ast::Function {
name: name.clone(),
arguments: vec![self_ref_ty.clone()],
ret,
opts: backend::ast::BindgenAttrs {
attrs: vec![
backend::ast::BindgenAttr::Method,
backend::ast::BindgenAttr::Getter(Some(name.clone())),
],
},
rust_attrs: vec![],
rust_decl: Box::new(syn::FnDecl {
fn_token: Default::default(),
generics: Default::default(),
paren_token: Default::default(),
inputs: syn::punctuated::Punctuated::from_iter(vec![simple_fn_arg(
raw_ident("self_"),
self_ref_ty,
)]),
variadic: None,
output,
}),
rust_vis: syn::Visibility::Public(syn::VisPublic {
pub_token: Default::default(),
}),
},
rust_name,
kind: backend::ast::ImportFunctionKind::Method {
class: self_name.to_string(),
ty: self_ty,
},
shim,
}),
})
}
fn create_setter(
this: &webidl::ast::RegularAttribute,
self_name: &str,
) -> Option<backend::ast::Import> {
let name = raw_ident(&this.name);
let rust_attr_name = rust_ident(&this.name.to_snake_case());
let rust_name = rust_ident(&format!("set_{}", rust_attr_name));
let self_ty = ident_ty(rust_ident(self_name));
let (inputs, arguments) = match webidl_ty_to_syn_ty(&this.type_, TypePosition::Argument)
{
None => {
warn!("Attribute's type does not yet support writing: {:?}. Skipping setter binding for {:?}",
this.type_, this);
return None;
}
Some(ty) => {
let self_ref_ty = shared_ref(self_ty.clone());
let mut inputs = syn::punctuated::Punctuated::new();
inputs.push(simple_fn_arg(raw_ident("self_"), self_ref_ty.clone()));
inputs.push(simple_fn_arg(rust_attr_name, ty.clone()));
(inputs, vec![self_ref_ty, ty])
}
};
let shim = rust_ident(&format!("__wbg_f_{}_{}_{}", name, rust_name, self_name));
Some(backend::ast::Import {
module: None,
version: None,
js_namespace: None,
kind: backend::ast::ImportKind::Function(backend::ast::ImportFunction {
function: backend::ast::Function {
name: name.clone(),
arguments,
ret: None,
opts: backend::ast::BindgenAttrs {
attrs: vec![
backend::ast::BindgenAttr::Method,
backend::ast::BindgenAttr::Setter(Some(name)),
],
},
rust_attrs: vec![],
rust_decl: Box::new(syn::FnDecl {
fn_token: Default::default(),
generics: Default::default(),
paren_token: Default::default(),
inputs,
variadic: None,
output: syn::ReturnType::Default,
}),
rust_vis: syn::Visibility::Public(syn::VisPublic {
pub_token: Default::default(),
}),
},
rust_name,
kind: backend::ast::ImportFunctionKind::Method {
class: self_name.to_string(),
ty: self_ty,
},
shim,
}),
})
}
create_getter(self, self_name).map(|import| program.imports.push(import));
if !self.read_only {
create_setter(self, self_name).map(|import| program.imports.push(import));
}
Ok(())
}
}
impl<'a> WebidlParse<'a> for webidl::ast::RegularOperation {
type Extra = &'a str;

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,9 @@
* liability, trademark and document use rules apply.
*/
// TODO: don't include this here, use Performance.webidl instead
typedef double DOMHighResTimeStamp;
[Constructor(DOMString type, optional EventInit eventInitDict),
Exposed=(Window,Worker,System), ProbablyShortLivingWrapper]
interface Event {