From 7fda07f797003e9ca2f367ab12f04f0d6b111726 Mon Sep 17 00:00:00 2001 From: afdw Date: Mon, 30 Jul 2018 17:41:22 +0300 Subject: [PATCH] Add renaming of conflicting constructors and operations (#579) * Add renaming of conflicting constructors and operations * Rename conflicting to overloaded * Fix newlines * Use or_insert_with, add a comment to TypeToString * Use more Rust-like names * Use opt instead of nullable * Use argument names instead of argument types if possible * Drop new for overloaded constructots * Remove extra newline * Move WebIDL files from unavailable_overloaded_fn * Move RTCDataChannel, RTCPeerConnection and Selection to unavailable_option_primitive --- .../AudioNode.webidl | 0 .../CanvasRenderingContext2D.webidl | 0 .../DOMMatrix.webidl | 0 .../DataTransferItemList.webidl | 0 .../FormData.webidl | 0 .../IDBKeyRange.webidl | 2 +- .../ImageData.webidl | 0 .../MediaStream.webidl | 0 .../PeerConnectionImplEnums.webidl | 0 .../PresentationConnection.webidl | 0 .../SpeechSynthesisUtterance.webidl | 0 .../TestFunctions.webidl | 0 .../URL.webidl | 0 .../WebKitCSSMatrix.webidl | 0 .../WebSocket.webidl | 0 .../Window.webidl | 0 .../XMLHttpRequest.webidl | 0 .../RTCDataChannel.webidl | 0 .../RTCPeerConnection.webidl | 0 .../Selection.webidl | 0 .../unavailable_overloaded_fn/README.md | 2 - crates/webidl/src/first_pass.rs | 264 +++++++++++++++--- crates/webidl/src/lib.rs | 12 +- crates/webidl/src/util.rs | 166 ++++++++++- 24 files changed, 400 insertions(+), 46 deletions(-) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/AudioNode.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/CanvasRenderingContext2D.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/DOMMatrix.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/DataTransferItemList.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/FormData.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/IDBKeyRange.webidl (97%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/ImageData.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/MediaStream.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/PeerConnectionImplEnums.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/PresentationConnection.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/SpeechSynthesisUtterance.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/TestFunctions.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/URL.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/WebKitCSSMatrix.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/WebSocket.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => enabled}/Window.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => unavailable_enum_ident}/XMLHttpRequest.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => unavailable_option_primitive}/RTCDataChannel.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => unavailable_option_primitive}/RTCPeerConnection.webidl (100%) rename crates/web-sys/webidls/{unavailable_overloaded_fn => unavailable_option_primitive}/Selection.webidl (100%) delete mode 100644 crates/web-sys/webidls/unavailable_overloaded_fn/README.md diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/AudioNode.webidl b/crates/web-sys/webidls/enabled/AudioNode.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/AudioNode.webidl rename to crates/web-sys/webidls/enabled/AudioNode.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/CanvasRenderingContext2D.webidl b/crates/web-sys/webidls/enabled/CanvasRenderingContext2D.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/CanvasRenderingContext2D.webidl rename to crates/web-sys/webidls/enabled/CanvasRenderingContext2D.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/DOMMatrix.webidl b/crates/web-sys/webidls/enabled/DOMMatrix.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/DOMMatrix.webidl rename to crates/web-sys/webidls/enabled/DOMMatrix.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/DataTransferItemList.webidl b/crates/web-sys/webidls/enabled/DataTransferItemList.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/DataTransferItemList.webidl rename to crates/web-sys/webidls/enabled/DataTransferItemList.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/FormData.webidl b/crates/web-sys/webidls/enabled/FormData.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/FormData.webidl rename to crates/web-sys/webidls/enabled/FormData.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/IDBKeyRange.webidl b/crates/web-sys/webidls/enabled/IDBKeyRange.webidl similarity index 97% rename from crates/web-sys/webidls/unavailable_overloaded_fn/IDBKeyRange.webidl rename to crates/web-sys/webidls/enabled/IDBKeyRange.webidl index 1caba7618..18650e666 100644 --- a/crates/web-sys/webidls/unavailable_overloaded_fn/IDBKeyRange.webidl +++ b/crates/web-sys/webidls/enabled/IDBKeyRange.webidl @@ -20,7 +20,7 @@ interface IDBKeyRange { [Constant] readonly attribute boolean upperOpen; [Throws] - boolean includes(any key); + boolean _includes(any key); [NewObject, Throws] diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/ImageData.webidl b/crates/web-sys/webidls/enabled/ImageData.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/ImageData.webidl rename to crates/web-sys/webidls/enabled/ImageData.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/MediaStream.webidl b/crates/web-sys/webidls/enabled/MediaStream.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/MediaStream.webidl rename to crates/web-sys/webidls/enabled/MediaStream.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/PeerConnectionImplEnums.webidl b/crates/web-sys/webidls/enabled/PeerConnectionImplEnums.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/PeerConnectionImplEnums.webidl rename to crates/web-sys/webidls/enabled/PeerConnectionImplEnums.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/PresentationConnection.webidl b/crates/web-sys/webidls/enabled/PresentationConnection.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/PresentationConnection.webidl rename to crates/web-sys/webidls/enabled/PresentationConnection.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/SpeechSynthesisUtterance.webidl b/crates/web-sys/webidls/enabled/SpeechSynthesisUtterance.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/SpeechSynthesisUtterance.webidl rename to crates/web-sys/webidls/enabled/SpeechSynthesisUtterance.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/TestFunctions.webidl b/crates/web-sys/webidls/enabled/TestFunctions.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/TestFunctions.webidl rename to crates/web-sys/webidls/enabled/TestFunctions.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/URL.webidl b/crates/web-sys/webidls/enabled/URL.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/URL.webidl rename to crates/web-sys/webidls/enabled/URL.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/WebKitCSSMatrix.webidl b/crates/web-sys/webidls/enabled/WebKitCSSMatrix.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/WebKitCSSMatrix.webidl rename to crates/web-sys/webidls/enabled/WebKitCSSMatrix.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/WebSocket.webidl b/crates/web-sys/webidls/enabled/WebSocket.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/WebSocket.webidl rename to crates/web-sys/webidls/enabled/WebSocket.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/Window.webidl b/crates/web-sys/webidls/enabled/Window.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/Window.webidl rename to crates/web-sys/webidls/enabled/Window.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/XMLHttpRequest.webidl b/crates/web-sys/webidls/unavailable_enum_ident/XMLHttpRequest.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/XMLHttpRequest.webidl rename to crates/web-sys/webidls/unavailable_enum_ident/XMLHttpRequest.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/RTCDataChannel.webidl b/crates/web-sys/webidls/unavailable_option_primitive/RTCDataChannel.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/RTCDataChannel.webidl rename to crates/web-sys/webidls/unavailable_option_primitive/RTCDataChannel.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/RTCPeerConnection.webidl b/crates/web-sys/webidls/unavailable_option_primitive/RTCPeerConnection.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/RTCPeerConnection.webidl rename to crates/web-sys/webidls/unavailable_option_primitive/RTCPeerConnection.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/Selection.webidl b/crates/web-sys/webidls/unavailable_option_primitive/Selection.webidl similarity index 100% rename from crates/web-sys/webidls/unavailable_overloaded_fn/Selection.webidl rename to crates/web-sys/webidls/unavailable_option_primitive/Selection.webidl diff --git a/crates/web-sys/webidls/unavailable_overloaded_fn/README.md b/crates/web-sys/webidls/unavailable_overloaded_fn/README.md deleted file mode 100644 index b396d0e93..000000000 --- a/crates/web-sys/webidls/unavailable_overloaded_fn/README.md +++ /dev/null @@ -1,2 +0,0 @@ -These webidl files are unavailable because they have multiple functions with the same name and -different arguments (overloaded functions), and web-sys does not support these. diff --git a/crates/webidl/src/first_pass.rs b/crates/webidl/src/first_pass.rs index a2fd089a0..9ffe859a6 100644 --- a/crates/webidl/src/first_pass.rs +++ b/crates/webidl/src/first_pass.rs @@ -18,13 +18,34 @@ use super::Result; /// Collection of constructs that may use partial. #[derive(Default)] pub(crate) struct FirstPassRecord<'a> { - pub(crate) interfaces: BTreeSet, + pub(crate) interfaces: BTreeMap, pub(crate) dictionaries: BTreeSet, pub(crate) enums: BTreeSet, /// The mixins, mapping their name to the webidl ast node for the mixin. pub(crate) mixins: BTreeMap>, } +/// We need to collect interface data during the first pass, to be used later. +#[derive(Default)] +pub(crate) struct InterfaceData { + /// Whether only partial interfaces were encountered + pub(crate) partial: bool, + pub(crate) operations: BTreeMap, +} + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub(crate) enum OperationId { + Constructor, + Operation(Option) +} + +#[derive(Default)] +pub(crate) struct OperationData { + pub(crate) overloaded: bool, + /// Map from argument names to whether they are the same for multiple overloads + pub(crate) argument_names_same: BTreeMap, bool>, +} + /// We need to collect mixin data during the first pass, to be used later. #[derive(Default)] pub(crate) struct MixinData<'a> { @@ -37,30 +58,30 @@ pub(crate) struct MixinData<'a> { } /// Implemented on an AST node to populate the `FirstPassRecord` struct. -pub(crate) trait FirstPass { +pub(crate) trait FirstPass { /// Populate `record` with any constructs in `self`. - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()>; + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, ctx: Ctx) -> Result<()>; } -impl FirstPass for [webidl::ast::Definition] { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +impl FirstPass<()> for [webidl::ast::Definition] { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { for def in self { - def.first_pass(record)?; + def.first_pass(record, ())?; } Ok(()) } } -impl FirstPass for webidl::ast::Definition { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +impl FirstPass<()> for webidl::ast::Definition { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { use webidl::ast::Definition::*; match self { - Dictionary(dictionary) => dictionary.first_pass(record), - Enum(enum_) => enum_.first_pass(record), - Interface(interface) => interface.first_pass(record), - Mixin(mixin) => mixin.first_pass(record), + Dictionary(dictionary) => dictionary.first_pass(record, ()), + Enum(enum_) => enum_.first_pass(record, ()), + Interface(interface) => interface.first_pass(record, ()), + Mixin(mixin) => mixin.first_pass(record, ()), _ => { // Other definitions aren't currently used in the first pass Ok(()) @@ -69,12 +90,12 @@ impl FirstPass for webidl::ast::Definition { } } -impl FirstPass for webidl::ast::Dictionary { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +impl FirstPass<()> for webidl::ast::Dictionary { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { use webidl::ast::Dictionary::*; match self { - NonPartial(dictionary) => dictionary.first_pass(record), + NonPartial(dictionary) => dictionary.first_pass(record, ()), _ => { // Other dictionaries aren't currently used in the first pass Ok(()) @@ -83,8 +104,8 @@ impl FirstPass for webidl::ast::Dictionary { } } -impl FirstPass for webidl::ast::NonPartialDictionary { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +impl FirstPass<()> for webidl::ast::NonPartialDictionary { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { if record.dictionaries.insert(self.name.clone()) { warn!("Encountered multiple declarations of {}", self.name); } @@ -93,8 +114,8 @@ impl FirstPass for webidl::ast::NonPartialDictionary { } } -impl FirstPass for webidl::ast::Enum { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +impl FirstPass<()> for webidl::ast::Enum { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { if record.enums.insert(self.name.clone()) { warn!("Encountered multiple declarations of {}", self.name); } @@ -103,43 +124,212 @@ impl FirstPass for webidl::ast::Enum { } } -impl FirstPass for webidl::ast::Interface { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +fn first_pass_operation<'a>( + record: &mut FirstPassRecord<'a>, + self_name: &str, + id: OperationId, + arguments: &[webidl::ast::Argument], +) -> Result<()> { + record + .interfaces + .get_mut(self_name) + .unwrap() + .operations + .entry(id) + .and_modify(|operation_data| operation_data.overloaded = true) + .or_insert_with(|| + OperationData { + overloaded: false, + argument_names_same: Default::default(), + } + ) + .argument_names_same + .entry(arguments.iter().map(|argument| argument.name.clone()).collect()) + .and_modify(|same_argument_names| *same_argument_names = true) + .or_insert(false); + + Ok(()) +} + +impl FirstPass<()> for webidl::ast::Interface { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { use webidl::ast::Interface::*; match self { - NonPartial(interface) => interface.first_pass(record), - _ => { - // Other interfaces aren't currently used in the first pass + Partial(interface) => interface.first_pass(record, ()), + NonPartial(interface) => interface.first_pass(record, ()), + // TODO + Callback(..) => { + warn!("Unsupported WebIDL interface: {:?}", self); Ok(()) } } } } -impl FirstPass for webidl::ast::NonPartialInterface { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { - if record.interfaces.insert(self.name.clone()) { - warn!("Encountered multiple declarations of {}", self.name); +impl FirstPass<()> for webidl::ast::NonPartialInterface { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { + record + .interfaces + .entry(self.name.clone()) + .and_modify(|interface_data| { + if interface_data.partial { + interface_data.partial = false; + } else { + warn!("Encountered multiple declarations of {}", self.name); + } + }) + .or_insert_with(|| + InterfaceData { + partial: false, + operations: Default::default(), + }, + ); + + if ::util::is_chrome_only(&self.extended_attributes) { + return Ok(()) + } + + for extended_attribute in &self.extended_attributes { + extended_attribute.first_pass(record, &self.name)?; + } + + for member in &self.members { + member.first_pass(record, &self.name)?; } Ok(()) } } -impl FirstPass for webidl::ast::Mixin { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { - use webidl::ast::Mixin::*; +impl FirstPass<()> for webidl::ast::PartialInterface { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { + record + .interfaces + .entry(self.name.clone()) + .or_insert_with(|| + InterfaceData { + partial: true, + operations: Default::default(), + }, + ); + if ::util::is_chrome_only(&self.extended_attributes) { + return Ok(()) + } + + for member in &self.members { + member.first_pass(record, &self.name)?; + } + + Ok(()) + } +} + +impl<'b> FirstPass<&'b str> for webidl::ast::ExtendedAttribute { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { match self { - NonPartial(mixin) => mixin.first_pass(record), - Partial(mixin) => mixin.first_pass(record), + webidl::ast::ExtendedAttribute::ArgumentList( + webidl::ast::ArgumentListExtendedAttribute { arguments, name }, + ) + if name == "Constructor" => + { + first_pass_operation( + record, + self_name, + OperationId::Constructor, + &arguments, + ) + } + webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name)) + if name == "Constructor" => + { + first_pass_operation( + record, + self_name, + OperationId::Constructor, + &[], + ) + } + webidl::ast::ExtendedAttribute::NamedArgumentList( + webidl::ast::NamedArgumentListExtendedAttribute { + lhs_name, + rhs_arguments, + .. + }, + ) + if lhs_name == "NamedConstructor" => + { + first_pass_operation( + record, + self_name, + OperationId::Constructor, + &rhs_arguments, + ) + }, + _ => Ok(()) } } } -impl FirstPass for webidl::ast::NonPartialMixin { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +impl<'b> FirstPass<&'b str> for webidl::ast::InterfaceMember { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { + match self { + webidl::ast::InterfaceMember::Operation(op) => op.first_pass(record, self_name), + _ => Ok(()), + } + } +} + +impl<'b> FirstPass<&'b str> for webidl::ast::Operation { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { + match self { + webidl::ast::Operation::Regular(op) => op.first_pass(record, self_name), + webidl::ast::Operation::Static(op) => op.first_pass(record, self_name), + // TODO + webidl::ast::Operation::Special(_) | webidl::ast::Operation::Stringifier(_) => { + warn!("Unsupported WebIDL operation: {:?}", self); + Ok(()) + } + } + } +} + +impl<'b> FirstPass<&'b str> for webidl::ast::RegularOperation { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { + first_pass_operation( + record, + self_name, + OperationId::Operation(self.name.clone()), + &self.arguments, + ) + } +} + +impl<'b> FirstPass<&'b str> for webidl::ast::StaticOperation { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> { + first_pass_operation( + record, + self_name, + OperationId::Operation(self.name.clone()), + &self.arguments, + ) + } +} + +impl FirstPass<()> for webidl::ast::Mixin { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { + use webidl::ast::Mixin::*; + + match self { + NonPartial(mixin) => mixin.first_pass(record, ()), + Partial(mixin) => mixin.first_pass(record, ()), + } + } +} + +impl FirstPass<()> for webidl::ast::NonPartialMixin { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { let entry = record .mixins .entry(self.name.clone()) @@ -155,8 +345,8 @@ impl FirstPass for webidl::ast::NonPartialMixin { } } -impl FirstPass for webidl::ast::PartialMixin { - fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>) -> Result<()> { +impl FirstPass<()> for webidl::ast::PartialMixin { + fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> { let entry = record .mixins .entry(self.name.clone()) diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index ca013d931..19778c9ea 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -75,7 +75,7 @@ fn parse(webidl_source: &str) -> Result { }; let mut first_pass_record = Default::default(); - definitions.first_pass(&mut first_pass_record)?; + definitions.first_pass(&mut first_pass_record, ())?; let mut program = Default::default(); definitions.webidl_parse(&mut program, &first_pass_record, ())?; @@ -309,7 +309,7 @@ impl WebidlParse<()> for webidl::ast::PartialInterface { return Ok(()); } - if !first_pass.interfaces.contains(&self.name) { + if !first_pass.interfaces.contains_key(&self.name) { warn!( "Partial interface {} missing non-partial interface", self.name @@ -332,6 +332,12 @@ 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 (overloaded, same_argument_names) = first_pass.get_operation_overloading( + arguments, + ::first_pass::OperationId::Constructor, + &interface.name, + ); + let self_ty = ident_ty(rust_ident(camel_case_ident(&interface.name).as_str())); let kind = backend::ast::ImportFunctionKind::Method { @@ -359,6 +365,8 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte first_pass .create_function( "new", + overloaded, + same_argument_names, arguments .iter() .map(|arg| (&*arg.name, &*arg.type_, arg.variadic)), diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 2050cf557..e5d1cc500 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -142,6 +142,92 @@ pub enum TypePosition { Return, } +/// Implemented on an AST type node to generate a snake case name. +trait TypeToString { + fn type_to_string(&self) -> String; +} + +impl TypeToString for webidl::ast::Type { + fn type_to_string(&self) -> String { + if self.nullable { + "opt_".to_owned() + &self.kind.type_to_string() + } else { + self.kind.type_to_string() + } + } +} + +impl TypeToString for webidl::ast::ReturnType { + fn type_to_string(&self) -> String { + match self { + webidl::ast::ReturnType::NonVoid(ty) => (*ty).type_to_string(), + webidl::ast::ReturnType::Void => "void".to_owned(), + } + } +} + +impl TypeToString for webidl::ast::StringType { + fn type_to_string(&self) -> String { + match self { + webidl::ast::StringType::ByteString => "byte_str".to_owned(), + webidl::ast::StringType::DOMString => "dom_str".to_owned(), + webidl::ast::StringType::USVString => "usv_str".to_owned(), + } + } +} + +impl TypeToString for webidl::ast::TypeKind { + fn type_to_string(&self) -> String { + match self { + webidl::ast::TypeKind::Any => "any".to_owned(), + webidl::ast::TypeKind::ArrayBuffer => "array_buffer".to_owned(), + webidl::ast::TypeKind::Boolean => "bool".to_owned(), + webidl::ast::TypeKind::Byte => "i8".to_owned(), + webidl::ast::TypeKind::ByteString => "byte_str".to_owned(), + webidl::ast::TypeKind::DOMString => "dom_str".to_owned(), + webidl::ast::TypeKind::DataView => "data_view".to_owned(), + webidl::ast::TypeKind::Error => "error".to_owned(), + webidl::ast::TypeKind::Float32Array => "f32_array".to_owned(), + webidl::ast::TypeKind::Float64Array => "f64_array".to_owned(), + webidl::ast::TypeKind::FrozenArray(ty) => "frozen_array_of_".to_owned() + &ty.type_to_string(), + webidl::ast::TypeKind::Identifier(identifier) => identifier.to_snake_case(), + webidl::ast::TypeKind::Int16Array => "i16_array".to_owned(), + webidl::ast::TypeKind::Int32Array => "i32_array".to_owned(), + webidl::ast::TypeKind::Int8Array => "i8_array".to_owned(), + webidl::ast::TypeKind::Octet => "u8".to_owned(), + webidl::ast::TypeKind::Object => "object".to_owned(), + webidl::ast::TypeKind::Promise(ty) => "promise_of_".to_owned() + &(*ty).type_to_string(), + webidl::ast::TypeKind::Record(string_type, ty) => format!( + "record_from_{}_to_{}", + string_type.type_to_string(), + (*ty).type_to_string() + ), + webidl::ast::TypeKind::RestrictedDouble => "restricted_f64".to_owned(), + webidl::ast::TypeKind::RestrictedFloat => "restricted_f32".to_owned(), + webidl::ast::TypeKind::Sequence(ty) => "sequence_of_".to_owned() + &ty.type_to_string(), + webidl::ast::TypeKind::SignedLong => "i32".to_owned(), + webidl::ast::TypeKind::SignedLongLong => "i64".to_owned(), + webidl::ast::TypeKind::SignedShort => "i16".to_owned(), + webidl::ast::TypeKind::Symbol => "symbol".to_owned(), + webidl::ast::TypeKind::USVString => "usv_str".to_owned(), + webidl::ast::TypeKind::Uint16Array => "u16_array".to_owned(), + webidl::ast::TypeKind::Uint32Array => "u32_array".to_owned(), + webidl::ast::TypeKind::Uint8Array => "u8_array".to_owned(), + webidl::ast::TypeKind::Uint8ClampedArray => "u8_clamped_array".to_owned(), + webidl::ast::TypeKind::Union(types) => "union_of_".to_owned() + &types + .iter() + .map(|ty| (*ty).type_to_string()) + .collect::>() + .join("_and_"), + webidl::ast::TypeKind::UnrestrictedDouble => "unrestricted_f64".to_owned(), + webidl::ast::TypeKind::UnrestrictedFloat => "unrestricted_f32".to_owned(), + webidl::ast::TypeKind::UnsignedLong => "u32".to_owned(), + webidl::ast::TypeKind::UnsignedLongLong => "u64".to_owned(), + webidl::ast::TypeKind::UnsignedShort => "u16".to_owned(), + } + } +} + impl<'a> FirstPassRecord<'a> { /// Use information from the first pass to work out the correct Rust type to use for /// a given WebIDL type. @@ -172,7 +258,7 @@ impl<'a> FirstPassRecord<'a> { // bindings. webidl::ast::TypeKind::Identifier(ref id) => { let ty = ident_ty(rust_ident(camel_case_ident(&id).as_str())); - if self.interfaces.contains(id) { + if self.interfaces.contains_key(id) { if pos == TypePosition::Argument { shared_ref(ty) } else { @@ -320,6 +406,8 @@ impl<'a> FirstPassRecord<'a> { pub fn create_function<'b, I>( &self, name: &str, + overloaded: bool, + same_argument_names: bool, arguments: I, mut ret: Option, kind: backend::ast::ImportFunctionKind, @@ -330,10 +418,36 @@ impl<'a> FirstPassRecord<'a> { where I: Iterator, { - let rust_name = rust_ident(&name.to_snake_case()); + let arguments: Vec<_> = arguments.collect(); + let rust_name = rust_ident( + &if overloaded && !arguments.is_empty() { + let argument_type_names = arguments + .iter() + .map(|&(name, ty, variadic)| { + if same_argument_names { + if variadic { + "variadic_".to_owned() + &ty.type_to_string() + } else { + ty.type_to_string() + } + } else { + name.to_snake_case() + } + }) + .collect::>() + .join("_and_"); + if name == "new" { + "with_".to_owned() + &argument_type_names + } else { + name.to_snake_case() + "_with_" + &argument_type_names + } + } else { + name.to_snake_case() + } + ); let name = raw_ident(name); - let arguments = self.webidl_arguments_to_syn_arg_captured(arguments, &kind)?; + let arguments = self.webidl_arguments_to_syn_arg_captured(arguments.into_iter(), &kind)?; let js_ret = ret.clone(); @@ -378,6 +492,12 @@ impl<'a> FirstPassRecord<'a> { is_static: bool, catch: bool, ) -> Option { + let (overloaded, same_argument_names) = self.get_operation_overloading( + arguments, + ::first_pass::OperationId::Operation(name.cloned()), + self_name, + ); + let name = match name { None => { warn!("Operations without a name are unsupported"); @@ -411,6 +531,8 @@ impl<'a> FirstPassRecord<'a> { self.create_function( &name, + overloaded, + same_argument_names, arguments .iter() .map(|arg| (&*arg.name, &*arg.type_, arg.variadic)), @@ -422,6 +544,40 @@ impl<'a> FirstPassRecord<'a> { ) } + /// Whether operation is overloaded and + /// whether there overloads with same argument names for given argument types + pub fn get_operation_overloading( + &self, + arguments: &[webidl::ast::Argument], + id: ::first_pass::OperationId, + self_name: &str, + ) -> (bool, bool) { + self + .interfaces + .get(self_name) + .map(|interface_data| { + interface_data + .operations + .get(&id) + .map(|operation_data| + ( + operation_data.overloaded, + *operation_data + .argument_names_same + .get( + &arguments + .iter() + .map(|argument| argument.name.clone()) + .collect::>() + ) + .unwrap_or(&false) + ) + ) + .unwrap_or((false, false)) + }) + .unwrap_or((false, false)) + } + /// Create a wasm-bindgen getter method, if possible. pub fn create_getter( &self, @@ -450,7 +606,7 @@ impl<'a> FirstPassRecord<'a> { }; let doc_comment = Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name)))); - self.create_function(name, iter::empty(), ret, kind, is_structural, catch, doc_comment) + self.create_function(name, false, false, iter::empty(), ret, kind, is_structural, catch, doc_comment) } /// Create a wasm-bindgen setter method, if possible. @@ -475,6 +631,8 @@ impl<'a> FirstPassRecord<'a> { self.create_function( &format!("set_{}", name), + false, + false, iter::once((name, ty, false)), None, kind,