Support named "special" operations in WebIDL

This commit adds support for two different features of the "special" operations
in WebIDL. First, it implements the desugaring [described by WebIDL][1] where
this:

    interface Dictionary {
      getter double getProperty(DOMString propertyName);
      setter void setProperty(DOMString propertyName, double propertyValue);
    };

becomes ...

    interface Dictionary {
      double getProperty(DOMString propertyName);
      void setProperty(DOMString propertyName, double propertyValue);

      getter double (DOMString propertyName);
      setter void (DOMString propertyName, double propertyValue);
    };

where specifically a named `getter` generates both a getter and a named
function.

Second it implements the distinction between two different types of getters in
WebIDL, described as:

> Getters and setters come in two varieties: ones that take a DOMString as a
> property name, known as named property getters and named property setters, and
> ones that take an unsigned long as a property index, known as indexed property
> getters and indexed property setters.

The name `get` is given to DOMString arguments, and the name `get_idx` is given
to index property getters.

[1]: https://heycam.github.io/webidl/#idl-special-operations
This commit is contained in:
Alex Crichton
2018-08-07 15:50:27 -07:00
parent c0c27775f3
commit 03eb1b1d01
4 changed files with 85 additions and 61 deletions

View File

@ -44,7 +44,7 @@ use proc_macro2::{Ident, Span};
use weedle::argument::Argument;
use weedle::attribute::{ExtendedAttribute, ExtendedAttributeList};
use first_pass::{FirstPass, FirstPassRecord};
use first_pass::{FirstPass, FirstPassRecord, OperationId};
use util::{public, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, mdn_doc};
use idl_type::{IdlType, ToIdlType};
@ -646,6 +646,7 @@ fn member_operation<'src>(
identifier: &Option<weedle::common::Identifier<'src>>,
) -> Result<()> {
use weedle::interface::StringifierOrStatic::*;
use weedle::interface::Special;
if util::is_chrome_only(attrs) {
return Ok(());
@ -660,33 +661,52 @@ fn member_operation<'src>(
None => false,
};
for import_function in first_pass.create_basic_method(
args,
match identifier.map(|s| s.0) {
None if specials.is_empty() => ::first_pass::OperationId::Operation(None),
None if specials.len() == 1 => match specials[0] {
weedle::interface::Special::Getter(_) => ::first_pass::OperationId::IndexingGetter,
weedle::interface::Special::Setter(_) => ::first_pass::OperationId::IndexingSetter,
weedle::interface::Special::Deleter(_) => ::first_pass::OperationId::IndexingDeleter,
weedle::interface::Special::LegacyCaller(_) => return Ok(()),
},
Some(ref name) if specials.is_empty() => ::first_pass::OperationId::Operation(Some(name.clone())),
_ => {
warn!("Unsupported specials on type {:?}", (self_name, identifier));
return Ok(())
}
},
return_type,
self_name,
is_static,
specials.len() == 1 || first_pass
.interfaces
.get(self_name)
.map(|interface_data| interface_data.global)
.unwrap_or(false),
util::throws(attrs),
) {
program.imports.push(wrap_import_function(import_function));
let mut operation_ids = vec![
OperationId::Operation(identifier.map(|s| s.0)),
];
if specials.len() > 1 {
warn!(
"Unsupported specials ({:?}) on type {:?}",
specials,
(self_name, identifier),
);
return Ok(())
} else if specials.len() == 1 {
let id = match specials[0] {
Special::Getter(weedle::term::Getter) => OperationId::IndexingGetter,
Special::Setter(weedle::term::Setter) => OperationId::IndexingSetter,
Special::Deleter(weedle::term::Deleter) => OperationId::IndexingDeleter,
Special::LegacyCaller(weedle::term::LegacyCaller) => return Ok(()),
};
operation_ids.push(id);
}
for id in operation_ids {
let methods = first_pass
.create_basic_method(
args,
id,
return_type,
self_name,
is_static,
match id {
OperationId::IndexingGetter |
OperationId::IndexingSetter |
OperationId::IndexingDeleter => true,
_ => {
first_pass
.interfaces
.get(self_name)
.map(|interface_data| interface_data.global)
.unwrap_or(false)
}
},
util::throws(attrs),
);
for method in methods {
program.imports.push(wrap_import_function(method));
}
}
Ok(())
}