diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 823437ab..265f4ac6 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -17,8 +17,6 @@ pub struct Program { pub enums: Vec, /// rust structs pub structs: Vec, - /// rust type aliases - pub type_aliases: Vec, /// rust consts pub consts: Vec, } @@ -198,13 +196,6 @@ 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, -} - #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq))] pub struct Const { pub vis: syn::Visibility, diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index f91e2f20..7db3913d 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -64,9 +64,6 @@ impl TryToTokens for ast::Program { for e in self.enums.iter() { e.to_tokens(tokens); } - for a in self.type_aliases.iter() { - a.to_tokens(tokens); - } for c in self.consts.iter() { c.to_tokens(tokens); } @@ -983,18 +980,6 @@ impl ToTokens for ast::ImportStatic { } } -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); - } -} - impl ToTokens for ast::Const { fn to_tokens(&self, tokens: &mut TokenStream) { use ast::ConstValue::*; diff --git a/crates/backend/src/defined.rs b/crates/backend/src/defined.rs index 7d943871..59a2aa61 100644 --- a/crates/backend/src/defined.rs +++ b/crates/backend/src/defined.rs @@ -83,7 +83,6 @@ impl ImportedTypes for ast::Program { F: FnMut(&Ident, ImportedTypeKind), { self.imports.imported_types(f); - self.type_aliases.imported_types(f); self.consts.imported_types(f); } } @@ -290,15 +289,6 @@ impl ImportedTypes for ast::ImportEnum { } } -impl ImportedTypes for ast::TypeAlias { - fn imported_types(&self, f: &mut F) - where - F: FnMut(&Ident, ImportedTypeKind), - { - f(&self.dest, ImportedTypeKind::Reference); - } -} - impl ImportedTypes for ast::Const { fn imported_types(&self, f: &mut F) where @@ -322,7 +312,6 @@ impl RemoveUndefinedImports for ast::Program { F: Fn(&Ident) -> bool, { self.imports.remove_undefined_imports(is_defined); - self.type_aliases.remove_undefined_imports(is_defined); self.consts.remove_undefined_imports(is_defined); } } diff --git a/crates/webidl/src/first_pass.rs b/crates/webidl/src/first_pass.rs index 9ffe859a..e072737f 100644 --- a/crates/webidl/src/first_pass.rs +++ b/crates/webidl/src/first_pass.rs @@ -23,6 +23,7 @@ pub(crate) struct FirstPassRecord<'a> { pub(crate) enums: BTreeSet, /// The mixins, mapping their name to the webidl ast node for the mixin. pub(crate) mixins: BTreeMap>, + pub(crate) typedefs: BTreeMap, } /// We need to collect interface data during the first pass, to be used later. @@ -82,6 +83,7 @@ impl FirstPass<()> for webidl::ast::Definition { Enum(enum_) => enum_.first_pass(record, ()), Interface(interface) => interface.first_pass(record, ()), Mixin(mixin) => mixin.first_pass(record, ()), + Typedef(typedef) => typedef.first_pass(record, ()), _ => { // Other definitions aren't currently used in the first pass Ok(()) @@ -356,3 +358,17 @@ impl FirstPass<()> for webidl::ast::PartialMixin { Ok(()) } } + +impl FirstPass<()> for webidl::ast::Typedef { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { + if ::util::is_chrome_only(&self.extended_attributes) { + return Ok(()); + } + + if record.typedefs.insert(self.name.clone(), *self.type_.clone()).is_some() { + warn!("Encountered multiple declarations of {}", self.name); + } + + Ok(()) + } +} diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 5a91c9fc..6462ea02 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -40,7 +40,7 @@ use failure::{ResultExt, Fail}; use heck::{ShoutySnakeCase}; use first_pass::{FirstPass, FirstPassRecord}; -use util::{public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, mdn_doc}; +use util::{ApplyTypedefs, public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, camel_case_ident, mdn_doc}; pub use error::{Error, ErrorKind, Result}; @@ -159,9 +159,6 @@ impl WebidlParse<()> for webidl::ast::Definition { webidl::ast::Definition::Interface(interface) => { interface.webidl_parse(program, first_pass, ())? } - webidl::ast::Definition::Typedef(typedef) => { - typedef.webidl_parse(program, first_pass, ())? - } // TODO webidl::ast::Definition::Callback(..) | webidl::ast::Definition::Dictionary(..) @@ -169,7 +166,8 @@ impl WebidlParse<()> for webidl::ast::Definition { | webidl::ast::Definition::Namespace(..) => { warn!("Unsupported WebIDL definition: {:?}", self) } - webidl::ast::Definition::Mixin(_) => { + webidl::ast::Definition::Mixin(_) + | webidl::ast::Definition::Typedef(_) => { // handled in the first pass } } @@ -226,39 +224,6 @@ impl WebidlParse<()> for webidl::ast::Interface { } } -impl WebidlParse<()> for webidl::ast::Typedef { - fn webidl_parse( - &self, - program: &mut backend::ast::Program, - first_pass: &FirstPassRecord<'_>, - (): (), - ) -> Result<()> { - if util::is_chrome_only(&self.extended_attributes) { - return Ok(()); - } - - let dest = rust_ident(camel_case_ident(&self.name).as_str()); - let src = match first_pass.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: public(), - dest, - src, - }); - - Ok(()) - } -} - impl WebidlParse<()> for webidl::ast::NonPartialInterface { fn webidl_parse( &self, @@ -334,6 +299,11 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte interface: &'a webidl::ast::NonPartialInterface, ) -> Result<()> { let mut add_constructor = |arguments: &[webidl::ast::Argument], class: &str| { + let arguments = &arguments + .iter() + .map(|argument| argument.apply_typedefs(first_pass)) + .collect::>(); + let (overloaded, same_argument_names) = first_pass.get_operation_overloading( arguments, ::first_pass::OperationId::Constructor, @@ -530,7 +500,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute { first_pass .create_getter( &self.name, - &self.type_, + &self.type_.apply_typedefs(first_pass), self_name, false, is_structural, @@ -543,7 +513,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularAttribute { first_pass .create_setter( &self.name, - &self.type_, + &self.type_.apply_typedefs(first_pass), self_name, false, is_structural, @@ -618,7 +588,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute { first_pass .create_getter( &self.name, - &self.type_, + &self.type_.apply_typedefs(first_pass), self_name, true, is_structural, @@ -631,7 +601,7 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticAttribute { first_pass .create_setter( &self.name, - &self.type_, + &self.type_.apply_typedefs(first_pass), self_name, true, is_structural, @@ -660,9 +630,13 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::RegularOperation { first_pass .create_basic_method( - &self.arguments, + &self + .arguments + .iter() + .map(|argument| argument.apply_typedefs(first_pass)) + .collect::>(), self.name.as_ref(), - &self.return_type, + &self.return_type.apply_typedefs(first_pass), self_name, false, throws, @@ -689,9 +663,13 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::StaticOperation { first_pass .create_basic_method( - &self.arguments, + &self + .arguments + .iter() + .map(|argument| argument.apply_typedefs(first_pass)) + .collect::>(), self.name.as_ref(), - &self.return_type, + &self.return_type.apply_typedefs(first_pass), self_name, true, throws, @@ -741,10 +719,10 @@ impl<'a> WebidlParse<&'a str> for webidl::ast::Const { fn webidl_parse( &self, program: &mut backend::ast::Program, - _: &FirstPassRecord<'_>, + first_pass: &FirstPassRecord<'_>, self_name: &'a str, ) -> Result<()> { - let ty = webidl_const_ty_to_syn_ty(&self.type_); + let ty = webidl_const_ty_to_syn_ty(&self.type_.apply_typedefs(first_pass)); program.consts.push(backend::ast::Const { vis: public(), diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index e5d1cc50..21910184 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -142,6 +142,111 @@ pub enum TypePosition { Return, } +fn type_kind_to_const_type(type_kind: &webidl::ast::TypeKind) -> webidl::ast::ConstType { + match type_kind { + webidl::ast::TypeKind::Boolean => webidl::ast::ConstType::Boolean, + webidl::ast::TypeKind::Byte => webidl::ast::ConstType::Byte, + webidl::ast::TypeKind::Identifier(identifier) => webidl::ast::ConstType::Identifier(identifier.clone()), + webidl::ast::TypeKind::Octet => webidl::ast::ConstType::Octet, + webidl::ast::TypeKind::RestrictedDouble => webidl::ast::ConstType::RestrictedDouble, + webidl::ast::TypeKind::RestrictedFloat => webidl::ast::ConstType::RestrictedFloat, + webidl::ast::TypeKind::SignedLong => webidl::ast::ConstType::SignedLong, + webidl::ast::TypeKind::SignedLongLong => webidl::ast::ConstType::SignedLongLong, + webidl::ast::TypeKind::SignedShort => webidl::ast::ConstType::SignedShort, + webidl::ast::TypeKind::UnrestrictedDouble => webidl::ast::ConstType::UnrestrictedDouble, + webidl::ast::TypeKind::UnrestrictedFloat => webidl::ast::ConstType::UnrestrictedFloat, + webidl::ast::TypeKind::UnsignedLong => webidl::ast::ConstType::UnsignedLong, + webidl::ast::TypeKind::UnsignedLongLong => webidl::ast::ConstType::UnsignedLongLong, + webidl::ast::TypeKind::UnsignedShort => webidl::ast::ConstType::UnsignedShort, + _ => panic!("can not convert TypeKind to ConstType: {:#?}", type_kind), + } +} + +/// Implemented on an AST type node to apply typedefs. +pub(crate) trait ApplyTypedefs { + fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self; +} + +impl ApplyTypedefs for webidl::ast::Type { + fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { + webidl::ast::Type { + extended_attributes: self.extended_attributes.clone(), + kind: self.kind.apply_typedefs(record), + nullable: self.nullable, + } + } +} + +impl ApplyTypedefs for webidl::ast::ReturnType { + fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { + match self { + webidl::ast::ReturnType::NonVoid(ty) => + webidl::ast::ReturnType::NonVoid(Box::new(ty.apply_typedefs(record))), + _ => self.clone(), + } + } +} + +impl ApplyTypedefs for webidl::ast::StringType { + fn apply_typedefs<'a>(&self, _: &FirstPassRecord<'a>) -> Self { + *self + } +} + +impl ApplyTypedefs for webidl::ast::ConstType { + fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { + match self { + webidl::ast::ConstType::Identifier(identifier) => + record + .typedefs + .get(identifier) + .map(|ty| type_kind_to_const_type(&ty.kind)) + .unwrap_or(self.clone()), + _ => self.clone(), + } + } +} + +impl ApplyTypedefs for webidl::ast::TypeKind { + fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { + match self { + webidl::ast::TypeKind::FrozenArray(ty) => + webidl::ast::TypeKind::FrozenArray(Box::new(ty.apply_typedefs(record))), + webidl::ast::TypeKind::Identifier(identifier) => record + .typedefs + .get(identifier) + .map(|ty| ty.kind.clone()) + .unwrap_or(self.clone()), + webidl::ast::TypeKind::Promise(ty) => + webidl::ast::TypeKind::Promise(ty.apply_typedefs(record)), + webidl::ast::TypeKind::Record(string_type, ty) => webidl::ast::TypeKind::Record( + string_type.apply_typedefs(record), + Box::new(ty.apply_typedefs(record)), + ), + webidl::ast::TypeKind::Union(types) => webidl::ast::TypeKind::Union( + types + .iter() + .map(|ty| Box::new(ty.apply_typedefs(record))) + .collect(), + ), + _ => self.clone(), + } + } +} + +impl ApplyTypedefs for webidl::ast::Argument { + fn apply_typedefs<'a>(&self, record: &FirstPassRecord<'a>) -> Self { + webidl::ast::Argument { + extended_attributes: self.extended_attributes.clone(), + default: self.default.clone(), + name: self.name.clone(), + optional: self.optional, + type_: Box::new(self.type_.apply_typedefs(record)), + variadic: self.variadic, + } + } +} + /// Implemented on an AST type node to generate a snake case name. trait TypeToString { fn type_to_string(&self) -> String;