summaryrefslogtreecommitdiffstats
path: root/third_party/rust/weedle2/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/weedle2/src')
-rw-r--r--third_party/rust/weedle2/src/argument.rs76
-rw-r--r--third_party/rust/weedle2/src/attribute.rs99
-rw-r--r--third_party/rust/weedle2/src/common.rs214
-rw-r--r--third_party/rust/weedle2/src/dictionary.rs33
-rw-r--r--third_party/rust/weedle2/src/interface.rs249
-rw-r--r--third_party/rust/weedle2/src/lib.rs408
-rw-r--r--third_party/rust/weedle2/src/literal.rs269
-rw-r--r--third_party/rust/weedle2/src/macros.rs564
-rw-r--r--third_party/rust/weedle2/src/mixin.rs60
-rw-r--r--third_party/rust/weedle2/src/namespace.rs52
-rw-r--r--third_party/rust/weedle2/src/term.rs699
-rw-r--r--third_party/rust/weedle2/src/types.rs385
-rw-r--r--third_party/rust/weedle2/src/whitespace.rs34
13 files changed, 3142 insertions, 0 deletions
diff --git a/third_party/rust/weedle2/src/argument.rs b/third_party/rust/weedle2/src/argument.rs
new file mode 100644
index 0000000000..8c0e085f20
--- /dev/null
+++ b/third_party/rust/weedle2/src/argument.rs
@@ -0,0 +1,76 @@
+use crate::attribute::ExtendedAttributeList;
+use crate::common::{Default, Identifier, Punctuated};
+use crate::types::{AttributedType, Type};
+
+/// Parses a list of argument. Ex: `double v1, double v2, double v3, optional double alpha`
+pub type ArgumentList<'a> = Punctuated<Argument<'a>, term!(,)>;
+
+ast_types! {
+ /// Parses an argument. Ex: `double v1|double... v1s`
+ enum Argument<'a> {
+ /// Parses `[attributes]? optional? attributedtype identifier ( = default )?`
+ ///
+ /// Note: `= default` is only allowed if `optional` is present
+ Single(struct SingleArgument<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ optional: Option<term!(optional)>,
+ type_: AttributedType<'a>,
+ identifier: Identifier<'a>,
+ default: Option<Default<'a>> = nom::combinator::map(
+ nom::combinator::cond(optional.is_some(), weedle!(Option<Default<'a>>)),
+ |default| default.unwrap_or(None)
+ ),
+ }),
+ /// Parses `[attributes]? type... identifier`
+ Variadic(struct VariadicArgument<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ type_: Type<'a>,
+ ellipsis: term!(...),
+ identifier: Identifier<'a>,
+ }),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::literal::{DecLit, DefaultValue, IntegerLit};
+ use crate::Parse;
+
+ test!(should_parse_single_argument { "short a" =>
+ "";
+ SingleArgument;
+ attributes.is_none();
+ optional.is_none();
+ identifier.0 == "a";
+ default.is_none();
+ });
+
+ test!(should_parse_variadic_argument { "short... a" =>
+ "";
+ VariadicArgument;
+ attributes.is_none();
+ identifier.0 == "a";
+ });
+
+ test!(should_parse_optional_single_argument { "optional short a" =>
+ "";
+ SingleArgument;
+ attributes.is_none();
+ optional.is_some();
+ identifier.0 == "a";
+ default.is_none();
+ });
+
+ test!(should_parse_optional_single_argument_with_default { "optional short a = 5" =>
+ "";
+ SingleArgument;
+ attributes.is_none();
+ optional.is_some();
+ identifier.0 == "a";
+ default == Some(Default {
+ assign: term!(=),
+ value: DefaultValue::Integer(IntegerLit::Dec(DecLit("5"))),
+ });
+ });
+}
diff --git a/third_party/rust/weedle2/src/attribute.rs b/third_party/rust/weedle2/src/attribute.rs
new file mode 100644
index 0000000000..0a70450023
--- /dev/null
+++ b/third_party/rust/weedle2/src/attribute.rs
@@ -0,0 +1,99 @@
+use crate::argument::ArgumentList;
+use crate::common::{Bracketed, Identifier, Parenthesized, Punctuated};
+use crate::literal::StringLit;
+
+/// Parses a list of attributes. Ex: `[ attribute1, attribute2 ]`
+pub type ExtendedAttributeList<'a> = Bracketed<Punctuated<ExtendedAttribute<'a>, term!(,)>>;
+
+/// Matches comma separated identifier list
+pub type IdentifierList<'a> = Punctuated<Identifier<'a>, term!(,)>;
+
+ast_types! {
+ /// Parses on of the forms of attribute
+ enum ExtendedAttribute<'a> {
+ /// Parses an argument list. Ex: `Constructor((double x, double y))`
+ ///
+ /// (( )) means ( ) chars
+ ArgList(struct ExtendedAttributeArgList<'a> {
+ identifier: Identifier<'a>,
+ args: Parenthesized<ArgumentList<'a>>,
+ }),
+ /// Parses a named argument list. Ex: `NamedConstructor=Image((DOMString src))`
+ ///
+ /// (( )) means ( ) chars
+ NamedArgList(struct ExtendedAttributeNamedArgList<'a> {
+ lhs_identifier: Identifier<'a>,
+ assign: term!(=),
+ rhs_identifier: Identifier<'a>,
+ args: Parenthesized<ArgumentList<'a>>,
+
+ }),
+ /// Parses an identifier list. Ex: `Exposed=((Window,Worker))`
+ ///
+ /// (( )) means ( ) chars
+ IdentList(struct ExtendedAttributeIdentList<'a> {
+ identifier: Identifier<'a>,
+ assign: term!(=),
+ list: Parenthesized<IdentifierList<'a>>,
+ }),
+ /// Parses an attribute with an identifier. Ex: `PutForwards=name`
+ #[derive(Copy)]
+ Ident(struct ExtendedAttributeIdent<'a> {
+ lhs_identifier: Identifier<'a>,
+ assign: term!(=),
+ rhs: IdentifierOrString<'a>,
+ }),
+ /// Parses a plain attribute. Ex: `Replaceable`
+ #[derive(Copy)]
+ NoArgs(struct ExtendedAttributeNoArgs<'a>(
+ Identifier<'a>,
+ )),
+ }
+
+ /// Parses `stringifier|static`
+ #[derive(Copy)]
+ enum IdentifierOrString<'a> {
+ Identifier(Identifier<'a>),
+ String(StringLit<'a>),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::Parse;
+
+ test!(should_parse_attribute_no_args { "Replaceable" =>
+ "";
+ ExtendedAttributeNoArgs => ExtendedAttributeNoArgs(Identifier("Replaceable"))
+ });
+
+ test!(should_parse_attribute_arg_list { "Constructor(double x, double y)" =>
+ "";
+ ExtendedAttributeArgList;
+ identifier.0 == "Constructor";
+ args.body.list.len() == 2;
+ });
+
+ test!(should_parse_attribute_ident { "PutForwards=name" =>
+ "";
+ ExtendedAttributeIdent;
+ lhs_identifier.0 == "PutForwards";
+ rhs == IdentifierOrString::Identifier(Identifier("name"));
+ });
+
+ test!(should_parse_ident_list { "Exposed=(Window,Worker)" =>
+ "";
+ ExtendedAttributeIdentList;
+ identifier.0 == "Exposed";
+ list.body.list.len() == 2;
+ });
+
+ test!(should_parse_named_arg_list { "NamedConstructor=Image(DOMString src)" =>
+ "";
+ ExtendedAttributeNamedArgList;
+ lhs_identifier.0 == "NamedConstructor";
+ rhs_identifier.0 == "Image";
+ args.body.list.len() == 1;
+ });
+}
diff --git a/third_party/rust/weedle2/src/common.rs b/third_party/rust/weedle2/src/common.rs
new file mode 100644
index 0000000000..fadf89ba8b
--- /dev/null
+++ b/third_party/rust/weedle2/src/common.rs
@@ -0,0 +1,214 @@
+use crate::literal::DefaultValue;
+use crate::{term, IResult, Parse};
+
+pub(crate) fn is_alphanum_underscore_dash(token: char) -> bool {
+ nom::AsChar::is_alphanum(token) || matches!(token, '_' | '-')
+}
+
+fn marker<S>(i: &str) -> IResult<&str, S>
+where
+ S: ::std::default::Default,
+{
+ Ok((i, S::default()))
+}
+
+impl<'a, T: Parse<'a>> Parse<'a> for Option<T> {
+ parser!(nom::combinator::opt(weedle!(T)));
+}
+
+impl<'a, T: Parse<'a>> Parse<'a> for Box<T> {
+ parser!(nom::combinator::map(weedle!(T), Box::new));
+}
+
+/// Parses `item1 item2 item3...`
+impl<'a, T: Parse<'a>> Parse<'a> for Vec<T> {
+ parser!(nom::multi::many0(T::parse));
+}
+
+impl<'a, T: Parse<'a>, U: Parse<'a>> Parse<'a> for (T, U) {
+ parser!(nom::sequence::tuple((T::parse, U::parse)));
+}
+
+impl<'a, T: Parse<'a>, U: Parse<'a>, V: Parse<'a>> Parse<'a> for (T, U, V) {
+ parser!(nom::sequence::tuple((T::parse, U::parse, V::parse)));
+}
+
+ast_types! {
+ /// Parses `( body )`
+ #[derive(Copy, Default)]
+ struct Parenthesized<T> where [T: Parse<'a>] {
+ open_paren: term::OpenParen,
+ body: T,
+ close_paren: term::CloseParen,
+ }
+
+ /// Parses `[ body ]`
+ #[derive(Copy, Default)]
+ struct Bracketed<T> where [T: Parse<'a>] {
+ open_bracket: term::OpenBracket,
+ body: T,
+ close_bracket: term::CloseBracket,
+ }
+
+ /// Parses `{ body }`
+ #[derive(Copy, Default)]
+ struct Braced<T> where [T: Parse<'a>] {
+ open_brace: term::OpenBrace,
+ body: T,
+ close_brace: term::CloseBrace,
+ }
+
+ /// Parses `< body >`
+ #[derive(Copy, Default)]
+ struct Generics<T> where [T: Parse<'a>] {
+ open_angle: term::LessThan,
+ body: T,
+ close_angle: term::GreaterThan,
+ }
+
+ /// Parses `(item1, item2, item3,...)?`
+ struct Punctuated<T, S> where [T: Parse<'a>, S: Parse<'a> + ::std::default::Default] {
+ list: Vec<T> = nom::multi::separated_list0(weedle!(S), weedle!(T)),
+ separator: S = marker,
+ }
+
+ /// Parses `item1, item2, item3, ...`
+ struct PunctuatedNonEmpty<T, S> where [T: Parse<'a>, S: Parse<'a> + ::std::default::Default] {
+ list: Vec<T> = nom::sequence::terminated(
+ nom::multi::separated_list1(weedle!(S), weedle!(T)),
+ nom::combinator::opt(weedle!(S))
+ ),
+ separator: S = marker,
+ }
+
+ /// Represents an identifier
+ ///
+ /// Follows `/_?[A-Za-z][0-9A-Z_a-z-]*/`
+ #[derive(Copy)]
+ struct Identifier<'a>(
+ // See https://heycam.github.io/webidl/#idl-names for why the leading
+ // underscore is trimmed
+ &'a str = crate::whitespace::ws(nom::sequence::preceded(
+ nom::combinator::opt(nom::character::complete::char('_')),
+ nom::combinator::recognize(nom::sequence::tuple((
+ nom::bytes::complete::take_while1(nom::AsChar::is_alphanum),
+ nom::bytes::complete::take_while(is_alphanum_underscore_dash),
+ )))
+ )),
+ )
+
+ /// Parses rhs of an assignment expression. Ex: `= 45`
+ #[derive(Copy)]
+ struct Default<'a> {
+ assign: term!(=),
+ value: DefaultValue<'a>,
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ test!(should_parse_optional_present { "one" =>
+ "";
+ Option<Identifier>;
+ is_some();
+ });
+
+ test!(should_parse_optional_not_present { "" =>
+ "";
+ Option<Identifier>;
+ is_none();
+ });
+
+ test!(should_parse_boxed { "one" =>
+ "";
+ Box<Identifier>;
+ });
+
+ test!(should_parse_vec { "one two three" =>
+ "";
+ Vec<Identifier>;
+ len() == 3;
+ });
+
+ test!(should_parse_parenthesized { "( one )" =>
+ "";
+ Parenthesized<Identifier>;
+ body.0 == "one";
+ });
+
+ test!(should_parse_bracketed { "[ one ]" =>
+ "";
+ Bracketed<Identifier>;
+ body.0 == "one";
+ });
+
+ test!(should_parse_braced { "{ one }" =>
+ "";
+ Braced<Identifier>;
+ body.0 == "one";
+ });
+
+ test!(should_parse_generics { "<one>" =>
+ "";
+ Generics<Identifier>;
+ body.0 == "one";
+ });
+
+ test!(should_parse_generics_two { "<one, two>" =>
+ "";
+ Generics<(Identifier, term!(,), Identifier)> =>
+ Generics {
+ open_angle: term!(<),
+ body: (Identifier("one"), term!(,), Identifier("two")),
+ close_angle: term!(>),
+ }
+ });
+
+ test!(should_parse_comma_separated_values { "one, two, three" =>
+ "";
+ Punctuated<Identifier, term!(,)>;
+ list.len() == 3;
+ });
+
+ test!(err should_not_parse_comma_separated_values_empty { "" =>
+ PunctuatedNonEmpty<Identifier, term!(,)>
+ });
+
+ test!(should_parse_identifier { "hello" =>
+ "";
+ Identifier;
+ 0 == "hello";
+ });
+
+ test!(should_parse_numbered_identifier { "hello5" =>
+ "";
+ Identifier;
+ 0 == "hello5";
+ });
+
+ test!(should_parse_underscored_identifier { "_hello_" =>
+ "";
+ Identifier;
+ 0 == "hello_";
+ });
+
+ test!(should_parse_identifier_surrounding_with_spaces { " hello " =>
+ "";
+ Identifier;
+ 0 == "hello";
+ });
+
+ test!(should_parse_identifier_preceding_others { "hello note" =>
+ "note";
+ Identifier;
+ 0 == "hello";
+ });
+
+ test!(should_parse_identifier_attached_to_symbol { "hello=" =>
+ "=";
+ Identifier;
+ 0 == "hello";
+ });
+}
diff --git a/third_party/rust/weedle2/src/dictionary.rs b/third_party/rust/weedle2/src/dictionary.rs
new file mode 100644
index 0000000000..3c9b23cac5
--- /dev/null
+++ b/third_party/rust/weedle2/src/dictionary.rs
@@ -0,0 +1,33 @@
+use crate::attribute::ExtendedAttributeList;
+use crate::common::{Default, Identifier};
+use crate::types::Type;
+
+/// Parses dictionary members
+pub type DictionaryMembers<'a> = Vec<DictionaryMember<'a>>;
+
+ast_types! {
+ /// Parses dictionary member `[attributes]? required? type identifier ( = default )?;`
+ struct DictionaryMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ required: Option<term!(required)>,
+ type_: Type<'a>,
+ identifier: Identifier<'a>,
+ default: Option<Default<'a>>,
+ semi_colon: term!(;),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::Parse;
+
+ test!(should_parse_dictionary_member { "required long num = 5;" =>
+ "";
+ DictionaryMember;
+ attributes.is_none();
+ required.is_some();
+ identifier.0 == "num";
+ default.is_some();
+ });
+}
diff --git a/third_party/rust/weedle2/src/interface.rs b/third_party/rust/weedle2/src/interface.rs
new file mode 100644
index 0000000000..5e30909c38
--- /dev/null
+++ b/third_party/rust/weedle2/src/interface.rs
@@ -0,0 +1,249 @@
+use crate::argument::ArgumentList;
+use crate::attribute::ExtendedAttributeList;
+use crate::common::{Generics, Identifier, Parenthesized};
+use crate::literal::ConstValue;
+use crate::types::{AttributedType, ConstType, ReturnType};
+
+/// Parses interface members
+pub type InterfaceMembers<'a> = Vec<InterfaceMember<'a>>;
+
+ast_types! {
+ /// Parses inheritance clause `: identifier`
+ #[derive(Copy)]
+ struct Inheritance<'a> {
+ colon: term!(:),
+ identifier: Identifier<'a>,
+ }
+
+ /// Parses one of the interface member variants
+ enum InterfaceMember<'a> {
+ /// Parses a const interface member `[attributes]? const type identifier = value;`
+ Const(struct ConstMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ const_: term!(const),
+ const_type: ConstType<'a>,
+ identifier: Identifier<'a>,
+ assign: term!(=),
+ const_value: ConstValue<'a>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? (stringifier|inherit|static)? readonly? attribute attributedtype identifier;`
+ Attribute(struct AttributeInterfaceMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ modifier: Option<StringifierOrInheritOrStatic>,
+ readonly: Option<term!(readonly)>,
+ attribute: term!(attribute),
+ type_: AttributedType<'a>,
+ identifier: Identifier<'a>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? constructor(( args ));`
+ ///
+ /// (( )) means ( ) chars
+ Constructor(struct ConstructorInterfaceMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ constructor: term!(constructor),
+ args: Parenthesized<ArgumentList<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? (stringifier|static)? special? returntype identifier? (( args ));`
+ ///
+ /// (( )) means ( ) chars
+ Operation(struct OperationInterfaceMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ modifier: Option<StringifierOrStatic>,
+ special: Option<Special>,
+ return_type: ReturnType<'a>,
+ identifier: Option<Identifier<'a>>,
+ args: Parenthesized<ArgumentList<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses an iterable declaration `[attributes]? (iterable<attributedtype> | iterable<attributedtype, attributedtype>) ;`
+ Iterable(enum IterableInterfaceMember<'a> {
+ /// Parses an iterable declaration `[attributes]? iterable<attributedtype>;`
+ Single(struct SingleTypedIterable<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ iterable: term!(iterable),
+ generics: Generics<AttributedType<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses an iterable declaration `[attributes]? iterable<attributedtype, attributedtype>;`
+ Double(struct DoubleTypedIterable<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ iterable: term!(iterable),
+ generics: Generics<(AttributedType<'a>, term!(,), AttributedType<'a>)>,
+ semi_colon: term!(;),
+ }),
+ }),
+ /// Parses an async iterable declaration `[attributes]? async (iterable<attributedtype> | iterable<attributedtype, attributedtype>) (( args ))? ;`
+ AsyncIterable(enum AsyncIterableInterfaceMember<'a> {
+ /// Parses an async iterable declaration `[attributes]? async iterable<attributedtype> (( args ))? ;`
+ Single(struct SingleTypedAsyncIterable<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ async_iterable: (term!(async), term!(iterable)),
+ generics: Generics<AttributedType<'a>>,
+ args: Option<Parenthesized<ArgumentList<'a>>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses an async iterable declaration `[attributes]? async iterable<attributedtype, attributedtype> (( args ))? ;`
+ Double(struct DoubleTypedAsyncIterable<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ async_iterable: (term!(async), term!(iterable)),
+ generics: Generics<(AttributedType<'a>, term!(,), AttributedType<'a>)>,
+ args: Option<Parenthesized<ArgumentList<'a>>>,
+ semi_colon: term!(;),
+ }),
+ }),
+ /// Parses an maplike declaration `[attributes]? readonly? maplike<attributedtype, attributedtype>;`
+ Maplike(struct MaplikeInterfaceMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ readonly: Option<term!(readonly)>,
+ maplike: term!(maplike),
+ generics: Generics<(AttributedType<'a>, term!(,), AttributedType<'a>)>,
+ semi_colon: term!(;),
+ }),
+ Setlike(struct SetlikeInterfaceMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ readonly: Option<term!(readonly)>,
+ setlike: term!(setlike),
+ generics: Generics<AttributedType<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `stringifier;`
+ #[derive(Default)]
+ Stringifier(struct StringifierMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ stringifier: term!(stringifier),
+ semi_colon: term!(;),
+ }),
+ }
+
+ /// Parses one of the special keyword `getter|setter|deleter`
+ #[derive(Copy)]
+ enum Special {
+ Getter(term!(getter)),
+ Setter(term!(setter)),
+ Deleter(term!(deleter)),
+ LegacyCaller(term!(legacycaller)),
+ }
+
+ /// Parses `stringifier|inherit|static`
+ #[derive(Copy)]
+ enum StringifierOrInheritOrStatic {
+ Stringifier(term!(stringifier)),
+ Inherit(term!(inherit)),
+ Static(term!(static)),
+ }
+
+ /// Parses `stringifier|static`
+ #[derive(Copy)]
+ enum StringifierOrStatic {
+ Stringifier(term!(stringifier)),
+ Static(term!(static)),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::Parse;
+
+ test!(should_parse_stringifier_member { "stringifier;" =>
+ "";
+ StringifierMember;
+ });
+
+ test!(should_parse_stringifier_or_static { "static" =>
+ "";
+ StringifierOrStatic;
+ });
+
+ test!(should_parse_stringifier_or_inherit_or_static { "inherit" =>
+ "";
+ StringifierOrInheritOrStatic;
+ });
+
+ test!(should_parse_setlike_interface_member { "readonly setlike<long>;" =>
+ "";
+ SetlikeInterfaceMember;
+ attributes.is_none();
+ readonly == Some(term!(readonly));
+ });
+
+ test!(should_parse_maplike_interface_member { "readonly maplike<long, short>;" =>
+ "";
+ MaplikeInterfaceMember;
+ attributes.is_none();
+ readonly == Some(term!(readonly));
+ });
+
+ test!(should_parse_attribute_interface_member { "readonly attribute unsigned long width;" =>
+ "";
+ AttributeInterfaceMember;
+ attributes.is_none();
+ readonly == Some(term!(readonly));
+ identifier.0 == "width";
+ });
+
+ test!(should_parse_double_typed_iterable { "iterable<long, long>;" =>
+ "";
+ DoubleTypedIterable;
+ attributes.is_none();
+ });
+
+ test!(should_parse_single_typed_iterable { "iterable<long>;" =>
+ "";
+ SingleTypedIterable;
+ attributes.is_none();
+ });
+
+ test!(should_parse_double_typed_async_iterable { "async iterable<long, long>;" =>
+ "";
+ DoubleTypedAsyncIterable;
+ attributes.is_none();
+ args.is_none();
+ });
+
+ test!(should_parse_double_typed_async_iterable_with_args { "async iterable<long, long>(long a);" =>
+ "";
+ DoubleTypedAsyncIterable;
+ attributes.is_none();
+ args.is_some();
+ });
+
+ test!(should_parse_single_typed_async_iterable { "async iterable<long>;" =>
+ "";
+ SingleTypedAsyncIterable;
+ attributes.is_none();
+ args.is_none();
+ });
+
+ test!(should_parse_single_typed_async_iterable_with_args { "async iterable<long>(long a);" =>
+ "";
+ SingleTypedAsyncIterable;
+ attributes.is_none();
+ args.is_some();
+ });
+
+ test!(should_parse_constructor_interface_member { "constructor(long a);" =>
+ "";
+ ConstructorInterfaceMember;
+ attributes.is_none();
+ });
+
+ test!(should_parse_operation_interface_member { "undefined readString(long a, long b);" =>
+ "";
+ OperationInterfaceMember;
+ attributes.is_none();
+ modifier.is_none();
+ special.is_none();
+ identifier.is_some();
+ });
+
+ test!(should_parse_const_member { "const long name = 5;" =>
+ "";
+ ConstMember;
+ attributes.is_none();
+ identifier.0 == "name";
+ });
+}
diff --git a/third_party/rust/weedle2/src/lib.rs b/third_party/rust/weedle2/src/lib.rs
new file mode 100644
index 0000000000..610a34fa14
--- /dev/null
+++ b/third_party/rust/weedle2/src/lib.rs
@@ -0,0 +1,408 @@
+//! Weedle - A WebIDL Parser
+//!
+//! Parses valid WebIDL definitions & produces a data structure starting from
+//! [`Definitions`](struct.Definitions.html).
+//!
+//! ### Example
+//!
+//! ```
+//! extern crate weedle;
+//!
+//! let parsed = weedle::parse("
+//! interface Window {
+//! readonly attribute Storage sessionStorage;
+//! };
+//! ").unwrap();
+//! println!("{:?}", parsed);
+//! ```
+//!
+//! Note:
+//! This parser follows the grammar given at [WebIDL](https://heycam.github.io/webidl).
+//!
+//! If any flaws found when parsing string with a valid grammar, create an issue.
+
+use self::argument::ArgumentList;
+use self::attribute::ExtendedAttributeList;
+use self::common::{Braced, Identifier, Parenthesized, PunctuatedNonEmpty};
+use self::dictionary::DictionaryMembers;
+use self::interface::{Inheritance, InterfaceMembers};
+use self::literal::StringLit;
+use self::mixin::MixinMembers;
+use self::namespace::NamespaceMembers;
+use self::types::{AttributedType, ReturnType};
+pub use nom::{error::Error, Err, IResult};
+
+#[macro_use]
+mod macros;
+#[macro_use]
+mod whitespace;
+#[macro_use]
+pub mod term;
+pub mod argument;
+pub mod attribute;
+pub mod common;
+pub mod dictionary;
+pub mod interface;
+pub mod literal;
+pub mod mixin;
+pub mod namespace;
+pub mod types;
+
+/// A convenient parse function
+///
+/// ### Example
+///
+/// ```
+/// extern crate weedle;
+///
+/// let parsed = weedle::parse("
+/// interface Window {
+/// readonly attribute Storage sessionStorage;
+/// };
+/// ").unwrap();
+///
+/// println!("{:?}", parsed);
+/// ```
+pub fn parse(raw: &str) -> Result<Definitions<'_>, Err<Error<&str>>> {
+ let (remaining, parsed) = Definitions::parse(raw)?;
+ assert!(
+ remaining.is_empty(),
+ "There is redundant raw data after parsing"
+ );
+ Ok(parsed)
+}
+
+pub trait Parse<'a>: Sized {
+ fn parse(input: &'a str) -> IResult<&'a str, Self>;
+}
+
+/// Parses WebIDL definitions. It is the root struct for a complete WebIDL definition.
+///
+/// ### Example
+/// ```
+/// use weedle::{Definitions, Parse};
+///
+/// let (_, parsed) = Definitions::parse("
+/// interface Window {
+/// readonly attribute Storage sessionStorage;
+/// };
+/// ").unwrap();
+///
+/// println!("{:?}", parsed);
+/// ```
+///
+/// It is recommended to use [`parse`](fn.parse.html) instead.
+pub type Definitions<'a> = Vec<Definition<'a>>;
+
+ast_types! {
+ /// Parses a definition
+ enum Definition<'a> {
+ /// Parses `[attributes]? callback identifier = type ( (arg1, arg2, ..., argN)? );`
+ Callback(struct CallbackDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ callback: term!(callback),
+ identifier: Identifier<'a>,
+ assign: term!(=),
+ return_type: ReturnType<'a>,
+ arguments: Parenthesized<ArgumentList<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? callback interface identifier ( : inheritance )? { members };`
+ CallbackInterface(struct CallbackInterfaceDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ callback: term!(callback),
+ interface: term!(interface),
+ identifier: Identifier<'a>,
+ inheritance: Option<Inheritance<'a>>,
+ members: Braced<InterfaceMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? interface identifier ( : inheritance )? { members };`
+ Interface(struct InterfaceDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ interface: term!(interface),
+ identifier: Identifier<'a>,
+ inheritance: Option<Inheritance<'a>>,
+ members: Braced<InterfaceMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? interface mixin identifier { members };`
+ InterfaceMixin(struct InterfaceMixinDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ interface: term!(interface),
+ mixin: term!(mixin),
+ identifier: Identifier<'a>,
+ members: Braced<MixinMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? namespace identifier { members };`
+ Namespace(struct NamespaceDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ namespace: term!(namespace),
+ identifier: Identifier<'a>,
+ members: Braced<NamespaceMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? dictionary identifier ( : inheritance )? { members };`
+ Dictionary(struct DictionaryDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ dictionary: term!(dictionary),
+ identifier: Identifier<'a>,
+ inheritance: Option<Inheritance<'a>>,
+ members: Braced<DictionaryMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? partial interface identifier { members };`
+ PartialInterface(struct PartialInterfaceDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ partial: term!(partial),
+ interface: term!(interface),
+ identifier: Identifier<'a>,
+ members: Braced<InterfaceMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? partial interface mixin identifier { members };`
+ PartialInterfaceMixin(struct PartialInterfaceMixinDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ partial: term!(partial),
+ interface: term!(interface),
+ mixin: term!(mixin),
+ identifier: Identifier<'a>,
+ members: Braced<MixinMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? partial dictionary identifier { members };`
+ PartialDictionary(struct PartialDictionaryDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ partial: term!(partial),
+ dictionary: term!(dictionary),
+ identifier: Identifier<'a>,
+ members: Braced<DictionaryMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? partial namespace identifier { members };`
+ PartialNamespace(struct PartialNamespaceDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ partial: term!(partial),
+ namespace: term!(namespace),
+ identifier: Identifier<'a>,
+ members: Braced<NamespaceMembers<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? enum identifier { values };`
+ Enum(struct EnumDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ enum_: term!(enum),
+ identifier: Identifier<'a>,
+ values: Braced<EnumValueList<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? typedef attributedtype identifier;`
+ Typedef(struct TypedefDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ typedef: term!(typedef),
+ type_: AttributedType<'a>,
+ identifier: Identifier<'a>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? identifier includes identifier;`
+ IncludesStatement(struct IncludesStatementDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ lhs_identifier: Identifier<'a>,
+ includes: term!(includes),
+ rhs_identifier: Identifier<'a>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? identifier implements identifier;`
+ Implements(struct ImplementsDefinition<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ lhs_identifier: Identifier<'a>,
+ includes: term!(implements),
+ rhs_identifier: Identifier<'a>,
+ semi_colon: term!(;),
+ }),
+ }
+}
+
+/// Parses a non-empty enum value list
+pub type EnumValueList<'a> = PunctuatedNonEmpty<StringLit<'a>, term!(,)>;
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ test!(should_parse_includes_statement { "first includes second;" =>
+ "";
+ IncludesStatementDefinition;
+ attributes.is_none();
+ lhs_identifier.0 == "first";
+ rhs_identifier.0 == "second";
+ });
+
+ test!(should_parse_typedef { "typedef short Short;" =>
+ "";
+ TypedefDefinition;
+ attributes.is_none();
+ identifier.0 == "Short";
+ });
+
+ test!(should_parse_enum { r#"enum name { "first", "second" }; "# =>
+ "";
+ EnumDefinition;
+ attributes.is_none();
+ identifier.0 == "name";
+ values.body.list.len() == 2;
+ });
+
+ test!(should_parse_dictionary { "dictionary A { long c; long g; };" =>
+ "";
+ DictionaryDefinition;
+ attributes.is_none();
+ identifier.0 == "A";
+ inheritance.is_none();
+ members.body.len() == 2;
+ });
+
+ test!(should_parse_dictionary_inherited { "dictionary C : B { long e; long f; };" =>
+ "";
+ DictionaryDefinition;
+ attributes.is_none();
+ identifier.0 == "C";
+ inheritance.is_some();
+ members.body.len() == 2;
+ });
+
+ test!(should_parse_partial_namespace { "
+ partial namespace VectorUtils {
+ readonly attribute Vector unit;
+ double dotProduct(Vector x, Vector y);
+ Vector crossProduct(Vector x, Vector y);
+ };
+ " =>
+ "";
+ PartialNamespaceDefinition;
+ attributes.is_none();
+ identifier.0 == "VectorUtils";
+ members.body.len() == 3;
+ });
+
+ test!(should_parse_partial_dictionary { "partial dictionary C { long e; long f; };" =>
+ "";
+ PartialDictionaryDefinition;
+ attributes.is_none();
+ identifier.0 == "C";
+ members.body.len() == 2;
+ });
+
+ test!(should_parse_partial_interface_mixin { "
+ partial interface mixin WindowSessionStorage {
+ readonly attribute Storage sessionStorage;
+ };
+ " =>
+ "";
+ PartialInterfaceMixinDefinition;
+ attributes.is_none();
+ identifier.0 == "WindowSessionStorage";
+ members.body.len() == 1;
+ });
+
+ test!(should_parse_partial_interface { "
+ partial interface Window {
+ readonly attribute Storage sessionStorage;
+ };
+ " =>
+ "";
+ PartialInterfaceDefinition;
+ attributes.is_none();
+ identifier.0 == "Window";
+ members.body.len() == 1;
+ });
+
+ test!(should_parse_namespace { "
+ namespace VectorUtils {
+ readonly attribute Vector unit;
+ double dotProduct(Vector x, Vector y);
+ Vector crossProduct(Vector x, Vector y);
+ };
+ " =>
+ "";
+ NamespaceDefinition;
+ attributes.is_none();
+ identifier.0 == "VectorUtils";
+ members.body.len() == 3;
+ });
+
+ test!(should_parse_interface_mixin { "
+ interface mixin WindowSessionStorage {
+ readonly attribute Storage sessionStorage;
+ };
+ " =>
+ "";
+ InterfaceMixinDefinition;
+ attributes.is_none();
+ identifier.0 == "WindowSessionStorage";
+ members.body.len() == 1;
+ });
+
+ test!(should_parse_interface { "
+ interface Window {
+ readonly attribute Storage sessionStorage;
+ };
+ " =>
+ "";
+ InterfaceDefinition;
+ attributes.is_none();
+ identifier.0 == "Window";
+ members.body.len() == 1;
+ });
+
+ test!(should_parse_callback_interface {"
+ callback interface Options {
+ attribute DOMString? option1;
+ attribute DOMString? option2;
+ attribute long? option3;
+ };
+ " =>
+ "";
+ CallbackInterfaceDefinition;
+ attributes.is_none();
+ identifier.0 == "Options";
+ members.body.len() == 3;
+ });
+
+ test!(should_parse_callback { "callback AsyncOperationCallback = undefined (DOMString status);" =>
+ "";
+ CallbackDefinition;
+ attributes.is_none();
+ identifier.0 == "AsyncOperationCallback";
+ arguments.body.list.len() == 1;
+ });
+
+ test!(should_parse_with_line_comments { "
+ // This is a comment
+ callback AsyncOperationCallback = undefined (DOMString status);
+ " =>
+ "";
+ CallbackDefinition;
+ });
+
+ test!(should_parse_with_block_comments { "
+ /* This is a comment */
+ callback AsyncOperationCallback = undefined (DOMString status);
+ " =>
+ "";
+ CallbackDefinition;
+ });
+
+ test!(should_parse_with_multiple_comments { "
+ // This is a comment
+ // This is a comment
+ // This is a comment
+
+ // This is a comment
+ callback AsyncOperationCallback = undefined (DOMString status);
+ " =>
+ "";
+ CallbackDefinition;
+ });
+}
diff --git a/third_party/rust/weedle2/src/literal.rs b/third_party/rust/weedle2/src/literal.rs
new file mode 100644
index 0000000000..295afe583d
--- /dev/null
+++ b/third_party/rust/weedle2/src/literal.rs
@@ -0,0 +1,269 @@
+ast_types! {
+ /// Represents an integer value
+ #[derive(Copy)]
+ enum IntegerLit<'a> {
+ /// Parses `-?[1-9][0-9]*`
+ #[derive(Copy)]
+ Dec(struct DecLit<'a>(
+ &'a str = crate::whitespace::ws(nom::combinator::recognize(nom::sequence::tuple((
+ nom::combinator::opt(nom::character::complete::char('-')),
+ nom::character::complete::one_of("123456789"),
+ nom::bytes::complete::take_while(nom::AsChar::is_dec_digit)
+ )))),
+ )),
+ /// Parses `-?0[Xx][0-9A-Fa-f]+)`
+ #[derive(Copy)]
+ Hex(struct HexLit<'a>(
+ &'a str = crate::whitespace::ws(nom::combinator::recognize(nom::sequence::tuple((
+ nom::combinator::opt(nom::character::complete::char('-')),
+ nom::character::complete::char('0'),
+ nom::character::complete::one_of("xX"),
+ nom::bytes::complete::take_while(nom::AsChar::is_hex_digit)
+ )))),
+ )),
+ /// Parses `-?0[0-7]*`
+ #[derive(Copy)]
+ Oct(struct OctLit<'a>(
+ &'a str = crate::whitespace::ws(nom::combinator::recognize(nom::sequence::tuple((
+ nom::combinator::opt(nom::character::complete::char('-')),
+ nom::character::complete::char('0'),
+ nom::bytes::complete::take_while(nom::AsChar::is_oct_digit)
+ )))),
+ )),
+ }
+
+ /// Represents a string value
+ ///
+ /// Follow `/"[^"]*"/`
+ #[derive(Copy)]
+ struct StringLit<'a>(
+ &'a str = crate::whitespace::ws(nom::sequence::delimited(
+ nom::character::complete::char('"'),
+ nom::bytes::complete::take_while(|c| c != '"'),
+ nom::character::complete::char('"'),
+ )),
+ )
+
+ /// Represents a default literal value. Ex: `34|34.23|"value"|[ ]|true|false|null`
+ #[derive(Copy)]
+ enum DefaultValue<'a> {
+ Boolean(BooleanLit),
+ /// Represents `[ ]`
+ #[derive(Copy, Default)]
+ EmptyArray(struct EmptyArrayLit {
+ open_bracket: term!(OpenBracket),
+ close_bracket: term!(CloseBracket),
+ }),
+ /// Represents `{ }`
+ #[derive(Copy, Default)]
+ EmptyDictionary(struct EmptyDictionaryLit {
+ open_brace: term!(OpenBrace),
+ close_brace: term!(CloseBrace),
+ }),
+ Float(FloatLit<'a>),
+ Integer(IntegerLit<'a>),
+ Null(term!(null)),
+ String(StringLit<'a>),
+ }
+
+ /// Represents `true`, `false`, `34.23`, `null`, `56`, ...
+ #[derive(Copy)]
+ enum ConstValue<'a> {
+ Boolean(BooleanLit),
+ Float(FloatLit<'a>),
+ Integer(IntegerLit<'a>),
+ Null(term!(null)),
+ }
+
+ /// Represents either `true` or `false`
+ #[derive(Copy)]
+ struct BooleanLit(
+ bool = nom::branch::alt((
+ nom::combinator::value(true, weedle!(term!(true))),
+ nom::combinator::value(false, weedle!(term!(false))),
+ )),
+ )
+
+ /// Represents a floating point value, `NaN`, `Infinity`, '+Infinity`
+ #[derive(Copy)]
+ enum FloatLit<'a> {
+ /// Parses `/-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)/`
+ #[derive(Copy)]
+ Value(struct FloatValueLit<'a>(
+ &'a str = crate::whitespace::ws(nom::combinator::recognize(nom::sequence::tuple((
+ nom::combinator::opt(nom::character::complete::char('-')),
+ nom::branch::alt((
+ nom::combinator::value((), nom::sequence::tuple((
+ // (?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)
+ nom::branch::alt((
+ nom::sequence::tuple((
+ nom::bytes::complete::take_while1(nom::AsChar::is_dec_digit),
+ nom::character::complete::char('.'),
+ nom::bytes::complete::take_while(nom::AsChar::is_dec_digit),
+ )),
+ nom::sequence::tuple((
+ nom::bytes::complete::take_while(nom::AsChar::is_dec_digit),
+ nom::character::complete::char('.'),
+ nom::bytes::complete::take_while1(nom::AsChar::is_dec_digit),
+ )),
+ )),
+ // (?:[Ee][+-]?[0-9]+)?
+ nom::combinator::opt(nom::sequence::tuple((
+ nom::character::complete::one_of("eE"),
+ nom::combinator::opt(nom::character::complete::one_of("+-")),
+ nom::bytes::complete::take_while1(nom::AsChar::is_dec_digit),
+ ))),
+ ))),
+ // [0-9]+[Ee][+-]?[0-9]+
+ nom::combinator::value((), nom::sequence::tuple((
+ nom::bytes::complete::take_while1(nom::AsChar::is_dec_digit),
+ nom::character::complete::one_of("eE"),
+ nom::combinator::opt(nom::character::complete::one_of("+-")),
+ nom::bytes::complete::take_while1(nom::AsChar::is_dec_digit),
+ ))),
+ )),
+ )))),
+ )),
+ NegInfinity(term!(-Infinity)),
+ Infinity(term!(Infinity)),
+ NaN(term!(NaN)),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::term::*;
+ use crate::Parse;
+
+ test!(should_parse_integer { "45" =>
+ "";
+ IntegerLit => IntegerLit::Dec(DecLit("45"))
+ });
+
+ test!(should_parse_integer_surrounding_with_spaces { " 123123 " =>
+ "";
+ IntegerLit => IntegerLit::Dec(DecLit("123123"))
+ });
+
+ test!(should_parse_integer_preceding_others { "3453 string" =>
+ "string";
+ IntegerLit => IntegerLit::Dec(DecLit("3453"))
+ });
+
+ test!(should_parse_neg_integer { "-435" =>
+ "";
+ IntegerLit => IntegerLit::Dec(DecLit("-435"))
+ });
+
+ test!(should_parse_hex_number { "0X08" =>
+ "";
+ IntegerLit => IntegerLit::Hex(HexLit("0X08"))
+ });
+
+ test!(should_parse_hex_large_number { "0xA" =>
+ "";
+ IntegerLit => IntegerLit::Hex(HexLit("0xA"))
+ });
+
+ test!(should_parse_zero { "0" =>
+ "";
+ IntegerLit => IntegerLit::Oct(OctLit("0"))
+ });
+
+ test!(should_parse_oct_number { "-07561" =>
+ "";
+ IntegerLit => IntegerLit::Oct(OctLit("-07561"))
+ });
+
+ test!(should_parse_float { "45.434" =>
+ "";
+ FloatLit => FloatLit::Value(FloatValueLit("45.434"))
+ });
+
+ test!(should_parse_float_surrounding_with_spaces { " 2345.2345 " =>
+ "";
+ FloatLit => FloatLit::Value(FloatValueLit("2345.2345"))
+ });
+
+ test!(should_parse_float_preceding_others { "3453.32334 string" =>
+ "string";
+ FloatLit => FloatLit::Value(FloatValueLit("3453.32334"))
+ });
+
+ test!(should_parse_neg_float { "-435.3435" =>
+ "";
+ FloatLit => FloatLit::Value(FloatValueLit("-435.3435"))
+ });
+
+ test!(should_parse_float_exp { "3e23" =>
+ "";
+ FloatLit => FloatLit::Value(FloatValueLit("3e23"))
+ });
+
+ test!(should_parse_float_exp_with_decimal { "5.3434e23" =>
+ "";
+ FloatLit => FloatLit::Value(FloatValueLit("5.3434e23"))
+ });
+
+ test!(should_parse_neg_infinity { "-Infinity" =>
+ "";
+ FloatLit => FloatLit::NegInfinity(term!(-Infinity))
+ });
+
+ test!(should_parse_infinity { "Infinity" =>
+ "";
+ FloatLit => FloatLit::Infinity(term!(Infinity))
+ });
+
+ test!(should_parse_string { r#""this is a string""# =>
+ "";
+ StringLit => StringLit("this is a string")
+ });
+
+ test!(should_parse_string_surround_with_spaces { r#" "this is a string" "# =>
+ "";
+ StringLit => StringLit("this is a string")
+ });
+
+ test!(should_parse_string_followed_by_string { r#" "this is first" "this is second" "# =>
+ r#""this is second" "#;
+ StringLit => StringLit("this is first")
+ });
+
+ test!(should_parse_string_with_spaces { r#" " this is a string " "# =>
+ "";
+ StringLit => StringLit(" this is a string ")
+ });
+
+ test!(should_parse_string_with_comment { r#" "// this is still a string"
+ "# =>
+ "";
+ StringLit => StringLit("// this is still a string")
+ });
+
+ test!(should_parse_string_with_multiline_comment { r#" "/*" "*/" "# =>
+ r#""*/" "#;
+ StringLit => StringLit("/*")
+ });
+
+ test!(should_parse_null { "null" =>
+ "";
+ Null => Null
+ });
+
+ test!(should_parse_empty_array { "[]" =>
+ "";
+ EmptyArrayLit => Default::default()
+ });
+
+ test!(should_parse_bool_true { "true" =>
+ "";
+ BooleanLit => BooleanLit(true)
+ });
+
+ test!(should_parse_bool_false { "false" =>
+ "";
+ BooleanLit => BooleanLit(false)
+ });
+}
diff --git a/third_party/rust/weedle2/src/macros.rs b/third_party/rust/weedle2/src/macros.rs
new file mode 100644
index 0000000000..0a29c499f9
--- /dev/null
+++ b/third_party/rust/weedle2/src/macros.rs
@@ -0,0 +1,564 @@
+macro_rules! parser {
+ ($parse:expr) => {
+ fn parse(input: &'a str) -> $crate::IResult<&'a str, Self> {
+ $parse(input)
+ }
+ };
+}
+
+macro_rules! weedle {
+ ($t:ty) => {
+ <$t as $crate::Parse<'a>>::parse
+ };
+}
+
+// nom::branch::alt supports at-most 21 parsers, increasing to 42 ones.
+macro_rules! alt {
+ ($member0:expr, $($member1:expr, $member2:expr,)*) => {
+ alt!(@as_expr $member0, $(nom::branch::alt(($member1, $member2)),)+)
+ };
+ ($($member0:expr, $member1:expr,)*) => {
+ alt!(@as_expr $(nom::branch::alt(($member0, $member1)),)+)
+ };
+ (@as_expr $($member:expr,)*) => {
+ nom::branch::alt(($($member,)+))
+ };
+}
+
+macro_rules! ast_types {
+ (@extract_type struct $name:ident<'a> $($rest:tt)*) => ($name<'a>);
+ (@extract_type struct $name:ident $($rest:tt)*) => ($name);
+ (@extract_type enum $name:ident<'a> $($rest:tt)*) => ($name<'a>);
+ (@extract_type enum $name:ident $($rest:tt)*) => ($name);
+
+ () => ();
+ (
+ $(#[$attr:meta])*
+ struct $name:ident<'a> {
+ $($fields:tt)*
+ }
+ $($rest:tt)*
+ ) => (
+ __ast_struct! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [ 'a ]
+ [ ]
+ { $($fields)* }
+ }
+ ast_types!($($rest)*);
+ );
+ (
+ $(#[$attr:meta])*
+ struct $name:ident<$($generics:ident),+> where [$($bounds:tt)+] {
+ $($fields:tt)*
+ }
+ $($rest:tt)*
+ ) => (
+ __ast_struct! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [$($generics)+]
+ [$($bounds)+]
+ { $($fields)* }
+ }
+ ast_types!($($rest)*);
+ );
+ (
+ $(#[$attr:meta])*
+ struct $name:ident {
+ $($fields:tt)*
+ }
+ $($rest:tt)*
+ ) => (
+ __ast_struct! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [ ]
+ [ ]
+ { $($fields)* }
+ }
+ ast_types!($($rest)*);
+ );
+
+ (
+ $(#[$attr:meta])*
+ struct $name:ident<'a> (
+ $($fields:tt)*
+ )
+ $($rest:tt)*
+ ) => (
+ __ast_tuple_struct! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [ 'a ]
+ ( $($fields)* )
+ }
+ ast_types!($($rest)*);
+ );
+ (
+ $(#[$attr:meta])*
+ struct $name:ident (
+ $($fields:tt)*
+ )
+ $($rest:tt)*
+ ) => (
+ __ast_tuple_struct! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [ ]
+ ( $($fields)* )
+ }
+ ast_types!($($rest)*);
+ );
+
+ (
+ $(#[$attr:meta])*
+ enum $name:ident<'a> {
+ $($variants:tt)*
+ }
+ $($rest:tt)*
+ ) => (
+ __ast_enum! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [ 'a ]
+ { $($variants)* }
+ }
+ ast_types!($($rest)*);
+ );
+ (
+ $(#[$attr:meta])*
+ enum $name:ident {
+ $($variants:tt)*
+ }
+ $($rest:tt)*
+ ) => (
+ __ast_enum! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [ ]
+ { $($variants)* }
+ }
+ ast_types!($($rest)*);
+ );
+}
+
+macro_rules! __ast_tuple_struct {
+ (@launch_pad
+ $(#[$attr:meta])*
+ $name:ident
+ [ $($maybe_a:tt)* ]
+ ( $inner:ty = $parser:expr, )
+ ) => (
+ $(#[$attr])*
+ #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub struct $name<$($maybe_a)*>(pub $inner);
+
+ impl<'a> $crate::Parse<'a> for $name<$($maybe_a)*> {
+ fn parse(input: &'a str) -> $crate::IResult<&'a str, Self> {
+ use nom::lib::std::result::Result::*;
+
+ match $parser(input) {
+ Err(e) => Err(e),
+ Ok((i, inner)) => Ok((i, $name(inner))),
+ }
+ }
+ }
+ );
+ (@launch_pad
+ $(#[$attr:meta])*
+ $name:ident
+ [ $($maybe_a:tt)* ]
+ ( $inner:ty, )
+ ) => (
+ __ast_tuple_struct! {
+ @launch_pad
+ $(#[$attr])*
+ $name
+ [ $($maybe_a)* ]
+ ( $inner = weedle!($inner), )
+ }
+ );
+}
+
+macro_rules! __ast_struct {
+ (@build_struct_decl
+ {
+ $(#[$attr:meta])*
+ $name:ident
+ [ $($generics:tt)* ]
+ $($field:ident : $type:ty)*
+ }
+ { }
+ ) => {
+ $(#[$attr])*
+ #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub struct $name<$($generics)*> {
+ $(pub $field : $type,)*
+ }
+ };
+ (@build_struct_decl
+ { $($prev:tt)* }
+ { $field:ident : $type:ty, $($rest:tt)* }
+ ) => (
+ __ast_struct! {
+ @build_struct_decl
+ { $($prev)* $field : $type }
+ { $($rest)* }
+ }
+ );
+ (@build_struct_decl
+ { $($prev:tt)* }
+ { $field:ident : $type:ty = $parser:expr, $($rest:tt)* }
+ ) => (
+ __ast_struct! {
+ @build_struct_decl
+ { $($prev)* $field : $type }
+ { $($rest)* }
+ }
+ );
+
+ (@build_parser
+ { $i:expr, $($field:ident)* }
+ { }
+ ) => ({
+ use nom::lib::std::result::Result::Ok;
+ Ok(($i, Self { $($field,)* }))
+ });
+ (@build_parser
+ { $i:expr, $($prev:tt)* }
+ { $field:ident : $type:ty = $parser:expr, $($rest:tt)* }
+ ) => ({
+ use nom::lib::std::result::Result::*;
+
+ match $parser($i) {
+ Err(e) => Err(e),
+ Ok((i, $field)) => {
+ __ast_struct! {
+ @build_parser
+ { i, $($prev)* $field }
+ { $($rest)* }
+ }
+ },
+ }
+ });
+ (@build_parser
+ { $($prev:tt)* }
+ { $field:ident : $type:ty, $($rest:tt)* }
+ ) => (
+ __ast_struct! {
+ @build_parser
+ { $($prev)* }
+ { $field : $type = weedle!($type), $($rest)* }
+ }
+ );
+
+ (
+ @launch_pad
+ $(#[$attr:meta])*
+ $name:ident
+ [ ]
+ [ ]
+ { $($fields:tt)* }
+ ) => {
+ __ast_struct! {
+ @build_struct_decl
+ {
+ $(#[$attr])*
+ $name
+ [ ]
+ }
+ { $($fields)* }
+ }
+
+ impl<'a> $crate::Parse<'a> for $name {
+ fn parse(input: &'a str) -> $crate::IResult<&'a str, Self> {
+ __ast_struct! {
+ @build_parser
+ { input, }
+ { $($fields)* }
+ }
+ }
+ }
+ };
+ (
+ @launch_pad
+ $(#[$attr:meta])*
+ $name:ident
+ [ 'a ]
+ [ ]
+ { $($fields:tt)* }
+ ) => {
+ __ast_struct! {
+ @build_struct_decl
+ {
+ $(#[$attr])*
+ $name
+ [ 'a ]
+ }
+ { $($fields)* }
+ }
+
+ impl<'a> $crate::Parse<'a> for $name<'a> {
+ fn parse(input: &'a str) -> $crate::IResult<&'a str, Self> {
+ __ast_struct! {
+ @build_parser
+ { input, }
+ { $($fields)* }
+ }
+ }
+ }
+ };
+ (
+ @launch_pad
+ $(#[$attr:meta])*
+ $name:ident
+ [$($generics:ident)+]
+ [$($bounds:tt)+]
+ { $($fields:tt)* }
+ ) => {
+ __ast_struct! {
+ @build_struct_decl
+ {
+ $(#[$attr])*
+ $name
+ [$($generics),+]
+ }
+ { $($fields)* }
+ }
+
+ impl<'a, $($generics),+> $crate::Parse<'a> for $name<$($generics),+> where $($bounds)+ {
+ fn parse(input: &'a str) -> $crate::IResult<&'a str, Self> {
+ __ast_struct! {
+ @build_parser
+ { input, }
+ { $($fields)* }
+ }
+ }
+ }
+ };
+}
+
+macro_rules! __ast_enum {
+ (@build_enum_decl
+ {
+ $(#[$attr:meta])*
+ $name:ident
+ [ $($maybe_a:tt)* ]
+ $($variant:ident($member:ty))*
+ }
+ { }
+ ) => (
+ $(#[$attr])*
+ #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub enum $name<$($maybe_a)*> {
+ $($variant($member),)*
+ }
+ );
+ (@build_enum_decl
+ { $($prev:tt)* }
+ { $variant:ident($member:ty), $($rest:tt)* }
+ ) => (
+ __ast_enum! {
+ @build_enum_decl
+ { $($prev)* $variant($member) }
+ { $($rest)* }
+ }
+ );
+ (@build_enum_decl
+ { $($prev:tt)* }
+ { $(#[$attr:meta])* $variant:ident( $($member:tt)* ), $($rest:tt)* }
+ ) => (
+ __ast_enum! {
+ @build_enum_decl
+ { $($prev)* $variant(ast_types! { @extract_type $($member)* }) }
+ { $($rest)* }
+ }
+ );
+
+ (@build_sub_types { }) => ();
+ (@build_sub_types
+ { $variant:ident($member:ty), $($rest:tt)* }
+ ) => (
+ __ast_enum! {
+ @build_sub_types
+ { $($rest)* }
+ }
+ );
+ (@build_sub_types
+ { $(#[$attr:meta])* $variant:ident( $($member:tt)* ), $($rest:tt)* }
+ ) => (
+ ast_types! {
+ $(#[$attr])*
+ $($member)*
+ }
+ __ast_enum! {
+ @build_sub_types
+ { $($rest)* }
+ }
+ );
+
+
+ (@build_conversions $name:ident [ $($maybe_a:tt)* ] { }) => ();
+ (@build_conversions
+ $name:ident
+ [ $($maybe_a:tt)* ]
+ { $variant:ident($member:ty), $($rest:tt)* }
+ ) => (
+ impl<$($maybe_a)*> From<$member> for $name<$($maybe_a)*> {
+ fn from(x: $member) -> Self {
+ $name::$variant(x)
+ }
+ }
+ __ast_enum! {
+ @build_conversions
+ $name
+ [ $($maybe_a)* ]
+ { $($rest)* }
+ }
+ );
+ (@build_conversions
+ $name:ident
+ [ $($maybe_a:tt)* ]
+ { $(#[$attr:meta])* $variant:ident( $($member:tt)* ), $($rest:tt)* }
+ ) => (
+ __ast_enum! {
+ @build_conversions
+ $name
+ [ $($maybe_a)* ]
+ { $variant(ast_types! { @extract_type $($member)* }), $($rest)* }
+ }
+ );
+
+ (@build_parse
+ { $name:ident [ $($maybe_a:tt)* ] $($member:ty)* }
+ { }
+ ) => (
+ impl<'a> $crate::Parse<'a> for $name<$($maybe_a)*> {
+ parser!(alt!(
+ $(nom::combinator::map(weedle!($member), From::from),)*
+ ));
+ }
+ );
+ (@build_parse
+ { $($prev:tt)* }
+ { $variant:ident($member:ty), $($rest:tt)* }
+ ) => (
+ __ast_enum! {
+ @build_parse
+ { $($prev)* $member }
+ { $($rest)* }
+ }
+ );
+ (@build_parse
+ { $($prev:tt)* }
+ { $(#[$attr:meta])* $variant:ident( $($member:tt)* ), $($rest:tt)* }
+ ) => (
+ __ast_enum! {
+ @build_parse
+ { $($prev)* ast_types! { @extract_type $($member)* } }
+ { $($rest)* }
+ }
+ );
+
+ (@launch_pad
+ $(#[$attr:meta])*
+ $name:ident
+ [ $($maybe_a:tt)* ]
+ { $($variants:tt)* }
+ ) => (
+ __ast_enum! {
+ @build_enum_decl
+ { $(#[$attr])* $name [ $($maybe_a)* ] }
+ { $($variants)* }
+ }
+
+ __ast_enum! {
+ @build_sub_types
+ { $($variants)* }
+ }
+
+ __ast_enum! {
+ @build_conversions
+ $name
+ [ $($maybe_a)* ]
+ { $($variants)* }
+ }
+
+ __ast_enum! {
+ @build_parse
+ { $name [ $($maybe_a)* ] }
+ { $($variants)* }
+ }
+ );
+}
+
+#[cfg(test)]
+macro_rules! test {
+ (@arg $parsed:ident) => {};
+ (@arg $parsed:ident $($lhs:tt).+ == $rhs:expr; $($rest:tt)*) => {
+ assert_eq!($parsed.$($lhs).+, $rhs);
+ test!(@arg $parsed $($rest)*);
+ };
+ (@arg $parsed:ident $($lhs:tt).+(); $($rest:tt)*) => {
+ assert!($parsed.$($lhs).+());
+ test!(@arg $parsed $($rest)*);
+ };
+ (@arg $parsed:ident $($lhs:tt).+() == $rhs:expr; $($rest:tt)*) => {
+ assert_eq!($parsed.$($lhs).+(), $rhs);
+ test!(@arg $parsed $($rest)*);
+ };
+ (err $name:ident { $raw:expr => $typ:ty }) => {
+ #[test]
+ fn $name() {
+ <$typ>::parse($raw).unwrap_err();
+ }
+ };
+ ($name:ident { $raw:expr => $rem:expr; $typ:ty => $val:expr }) => {
+ #[test]
+ fn $name() {
+ let (rem, parsed) = <$typ>::parse($raw).unwrap();
+ assert_eq!(rem, $rem);
+ assert_eq!(parsed, $val);
+ }
+ };
+ ($name:ident { $raw:expr => $rem:expr; $typ:ty; $($body:tt)* }) => {
+ #[test]
+ fn $name() {
+ let (_rem, _parsed) = <$typ>::parse($raw).unwrap();
+ assert_eq!(_rem, $rem);
+ test!(@arg _parsed $($body)*);
+ }
+ };
+}
+
+#[cfg(test)]
+macro_rules! test_variants {
+ ($struct_:ident { $( $variant:ident == $value:expr ),* $(,)* }) => {
+ #[allow(non_snake_case)]
+ mod $struct_ {
+ $(
+ mod $variant {
+ use $crate::types::*;
+ #[test]
+ fn should_parse() {
+ let (rem, parsed) = $struct_::parse($value).unwrap();
+ assert_eq!(rem, "");
+ match parsed {
+ $struct_::$variant(_) => {},
+ _ => { panic!("Failed to parse"); }
+ }
+ }
+ }
+ )*
+ }
+ };
+}
diff --git a/third_party/rust/weedle2/src/mixin.rs b/third_party/rust/weedle2/src/mixin.rs
new file mode 100644
index 0000000000..dcb40d50c5
--- /dev/null
+++ b/third_party/rust/weedle2/src/mixin.rs
@@ -0,0 +1,60 @@
+use crate::argument::ArgumentList;
+use crate::attribute::ExtendedAttributeList;
+use crate::common::{Identifier, Parenthesized};
+use crate::interface::{ConstMember, StringifierMember};
+use crate::types::{AttributedType, ReturnType};
+
+/// Parses the members declarations of a mixin
+pub type MixinMembers<'a> = Vec<MixinMember<'a>>;
+
+ast_types! {
+ /// Parses one of the variants of a mixin member
+ enum MixinMember<'a> {
+ Const(ConstMember<'a>),
+ /// Parses `[attributes]? stringifier? returntype identifier? (( args ));`
+ ///
+ /// (( )) means ( ) chars
+ Operation(struct OperationMixinMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ stringifier: Option<term!(stringifier)>,
+ return_type: ReturnType<'a>,
+ identifier: Option<Identifier<'a>>,
+ args: Parenthesized<ArgumentList<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attributes]? stringifier? readonly? attribute attributedtype identifier;`
+ Attribute(struct AttributeMixinMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ stringifier: Option<term!(stringifier)>,
+ readonly: Option<term!(readonly)>,
+ attribute: term!(attribute),
+ type_: AttributedType<'a>,
+ identifier: Identifier<'a>,
+ semi_colon: term!(;),
+ }),
+ Stringifier(StringifierMember<'a>),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::Parse;
+
+ test!(should_parse_attribute_mixin_member { "stringifier readonly attribute short name;" =>
+ "";
+ AttributeMixinMember;
+ attributes.is_none();
+ stringifier.is_some();
+ readonly.is_some();
+ identifier.0 == "name";
+ });
+
+ test!(should_parse_operation_mixin_member { "short fnName(long a);" =>
+ "";
+ OperationMixinMember;
+ attributes.is_none();
+ stringifier.is_none();
+ identifier.is_some();
+ });
+}
diff --git a/third_party/rust/weedle2/src/namespace.rs b/third_party/rust/weedle2/src/namespace.rs
new file mode 100644
index 0000000000..ed28573218
--- /dev/null
+++ b/third_party/rust/weedle2/src/namespace.rs
@@ -0,0 +1,52 @@
+use crate::argument::ArgumentList;
+use crate::attribute::ExtendedAttributeList;
+use crate::common::{Identifier, Parenthesized};
+use crate::types::{AttributedType, ReturnType};
+
+/// Parses namespace members declaration
+pub type NamespaceMembers<'a> = Vec<NamespaceMember<'a>>;
+
+ast_types! {
+ /// Parses namespace member declaration
+ enum NamespaceMember<'a> {
+ /// Parses `[attributes]? returntype identifier? (( args ));`
+ ///
+ /// (( )) means ( ) chars
+ Operation(struct OperationNamespaceMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ return_type: ReturnType<'a>,
+ identifier: Option<Identifier<'a>>,
+ args: Parenthesized<ArgumentList<'a>>,
+ semi_colon: term!(;),
+ }),
+ /// Parses `[attribute]? readonly attributetype type identifier;`
+ Attribute(struct AttributeNamespaceMember<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ readonly: term!(readonly),
+ attribute: term!(attribute),
+ type_: AttributedType<'a>,
+ identifier: Identifier<'a>,
+ semi_colon: term!(;),
+ }),
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::Parse;
+
+ test!(should_parse_attribute_namespace_member { "readonly attribute short name;" =>
+ "";
+ AttributeNamespaceMember;
+ attributes.is_none();
+ identifier.0 == "name";
+ });
+
+ test!(should_parse_operation_namespace_member { "short (long a, long b);" =>
+ "";
+ OperationNamespaceMember;
+ attributes.is_none();
+ identifier.is_none();
+ });
+}
diff --git a/third_party/rust/weedle2/src/term.rs b/third_party/rust/weedle2/src/term.rs
new file mode 100644
index 0000000000..d73de79847
--- /dev/null
+++ b/third_party/rust/weedle2/src/term.rs
@@ -0,0 +1,699 @@
+macro_rules! generate_terms {
+ ($( $(#[$attr:meta])* $typ:ident => $tok:expr ),*) => {
+ $(
+ $(#[$attr])*
+ #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ pub struct $typ;
+
+ impl<'a> $crate::Parse<'a> for $typ {
+ parser!(nom::combinator::value(
+ $typ,
+ crate::whitespace::ws(
+ nom::bytes::complete::tag($tok)
+ )
+ ));
+ }
+ )*
+ };
+}
+
+struct AlphaNumUnderscoreDash;
+
+impl nom::FindToken<char> for AlphaNumUnderscoreDash {
+ fn find_token(&self, token: char) -> bool {
+ crate::common::is_alphanum_underscore_dash(token)
+ }
+}
+
+pub(crate) fn ident_tag(tag: &'static str) -> impl FnMut(&str) -> nom::IResult<&str, &str> {
+ move |input| {
+ nom::sequence::terminated(
+ nom::bytes::complete::tag(tag),
+ nom::combinator::not(nom::combinator::map_parser(
+ nom::bytes::complete::take(1usize),
+ nom::bytes::complete::is_a(AlphaNumUnderscoreDash),
+ )),
+ )(input)
+ }
+}
+
+macro_rules! generate_terms_for_names {
+ ($( $(#[$attr:meta])* $typ:ident => $tok:expr,)*) => {
+ $(
+ $(#[$attr])*
+ #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ pub struct $typ;
+
+ impl<'a> $crate::Parse<'a> for $typ {
+ parser!(nom::combinator::value(
+ $typ,
+ $crate::whitespace::ws($crate::term::ident_tag($tok))
+ ));
+ }
+ )*
+ };
+}
+
+generate_terms! {
+ /// Represents the terminal symbol `(`
+ OpenParen => "(",
+
+ /// Represents the terminal symbol `)`
+ CloseParen => ")",
+
+ /// Represents the terminal symbol `[`
+ OpenBracket => "[",
+
+ /// Represents the terminal symbol `]`
+ CloseBracket => "]",
+
+ /// Represents the terminal symbol `{`
+ OpenBrace => "{",
+
+ /// Represents the terminal symbol `}`
+ CloseBrace => "}",
+
+ /// Represents the terminal symbol `,`
+ Comma => ",",
+
+ /// Represents the terminal symbol `-`
+ Minus => "-",
+
+ /// Represents the terminal symbol `.`
+ Dot => ".",
+
+ /// Represents the terminal symbol `...`
+ Ellipsis => "...",
+
+ /// Represents the terminal symbol `:`
+ Colon => ":",
+
+ /// Represents the terminal symbol `;`
+ SemiColon => ";",
+
+ /// Represents the terminal symbol `<`
+ LessThan => "<",
+
+ /// Represents the terminal symbol `=`
+ Assign => "=",
+
+ /// Represents the terminal symbol `>`
+ GreaterThan => ">",
+
+ /// Represents the terminal symbol `?`
+ QMark => "?"
+}
+
+generate_terms_for_names! {
+ /// Represents the terminal symbol `or`
+ Or => "or",
+
+ /// Represents the terminal symbol `optional`
+ Optional => "optional",
+
+ /// Represents the terminal symbol `async`
+ Async => "async",
+
+ /// Represents the terminal symbol `attribute`
+ Attribute => "attribute",
+
+ /// Represents the terminal symbol `callback`
+ Callback => "callback",
+
+ /// Represents the terminal symbol `const`
+ Const => "const",
+
+ /// Represents the terminal symbol `deleter`
+ Deleter => "deleter",
+
+ /// Represents the terminal symbol `dictionary`
+ Dictionary => "dictionary",
+
+ /// Represents the terminal symbol `enum`
+ Enum => "enum",
+
+ /// Represents the terminal symbol `getter`
+ Getter => "getter",
+
+ /// Represents the terminal symbol `includes`
+ Includes => "includes",
+
+ /// Represents the terminal symbol `inherit`
+ Inherit => "inherit",
+
+ /// Represents the terminal symbol `interface`
+ Interface => "interface",
+
+ /// Represents the terminal symbol `iterable`
+ Iterable => "iterable",
+
+ /// Represents the terminal symbol `maplike`
+ Maplike => "maplike",
+
+ /// Represents the terminal symbol `namespace`
+ Namespace => "namespace",
+
+ /// Represents the terminal symbol `partial`
+ Partial => "partial",
+
+ /// Represents the terminal symbol `required`
+ Required => "required",
+
+ /// Represents the terminal symbol `setlike`
+ Setlike => "setlike",
+
+ /// Represents the terminal symbol `setter`
+ Setter => "setter",
+
+ /// Represents the terminal symbol `static`
+ Static => "static",
+
+ /// Represents the terminal symbol `stringifier`
+ Stringifier => "stringifier",
+
+ /// Represents the terminal symbol `typedef`
+ Typedef => "typedef",
+
+ /// Represents the terminal symbol `unrestricted`
+ Unrestricted => "unrestricted",
+
+ /// Represents the terminal symbol `symbol`
+ Symbol => "symbol",
+
+ /// Represents the terminal symbol `Infinity`
+ NegInfinity => "-Infinity",
+
+ /// Represents the terminal symbol `ByteString`
+ ByteString => "ByteString",
+
+ /// Represents the terminal symbol `DOMString`
+ DOMString => "DOMString",
+
+ /// Represents the terminal symbol `FrozenArray`
+ FrozenArray => "FrozenArray",
+
+ /// Represents the terminal symbol `Infinity`
+ Infinity => "Infinity",
+
+ /// Represents the terminal symbol `NaN`
+ NaN => "NaN",
+
+ /// Represents the terminal symbol `USVString`
+ USVString => "USVString",
+
+ /// Represents the terminal symbol `any`
+ Any => "any",
+
+ /// Represents the terminal symbol `boolean`
+ Boolean => "boolean",
+
+ /// Represents the terminal symbol `byte`
+ Byte => "byte",
+
+ /// Represents the terminal symbol `double`
+ Double => "double",
+
+ /// Represents the terminal symbol `false`
+ False => "false",
+
+ /// Represents the terminal symbol `float`
+ Float => "float",
+
+ /// Represents the terminal symbol `long`
+ Long => "long",
+
+ /// Represents the terminal symbol `null`
+ Null => "null",
+
+ /// Represents the terminal symbol `object`
+ Object => "object",
+
+ /// Represents the terminal symbol `octet`
+ Octet => "octet",
+
+ /// Represents the terminal symbol `sequence`
+ Sequence => "sequence",
+
+ /// Represents the terminal symbol `short`
+ Short => "short",
+
+ /// Represents the terminal symbol `true`
+ True => "true",
+
+ /// Represents the terminal symbol `unsigned`
+ Unsigned => "unsigned",
+
+ /// Represents the terminal symbol `undefined`
+ Undefined => "undefined",
+
+ /// Represents the terminal symbol `record`
+ Record => "record",
+
+ /// Represents the terminal symbol `ArrayBuffer`
+ ArrayBuffer => "ArrayBuffer",
+
+ /// Represents the terminal symbol `DataView`
+ DataView => "DataView",
+
+ /// Represents the terminal symbol `Int8Array`
+ Int8Array => "Int8Array",
+
+ /// Represents the terminal symbol `Int16Array`
+ Int16Array => "Int16Array",
+
+ /// Represents the terminal symbol `Int32Array`
+ Int32Array => "Int32Array",
+
+ /// Represents the terminal symbol `Uint8Array`
+ Uint8Array => "Uint8Array",
+
+ /// Represents the terminal symbol `Uint16Array`
+ Uint16Array => "Uint16Array",
+
+ /// Represents the terminal symbol `Uint32Array`
+ Uint32Array => "Uint32Array",
+
+ /// Represents the terminal symbol `Uint8ClampedArray`
+ Uint8ClampedArray => "Uint8ClampedArray",
+
+ /// Represents the terminal symbol `Float32Array`
+ Float32Array => "Float32Array",
+
+ /// Represents the terminal symbol `Float64Array`
+ Float64Array => "Float64Array",
+
+ /// Represents the terminal symbol `ArrayBufferView`
+ ArrayBufferView => "ArrayBufferView",
+
+ /// Represents the terminal symbol `BufferSource
+ BufferSource => "BufferSource",
+
+ /// Represents the terminal symbol `Promise`
+ Promise => "Promise",
+
+ /// Represents the terminal symbol `Error`
+ Error => "Error",
+
+ /// Represents the terminal symbol `readonly`
+ ReadOnly => "readonly",
+
+ /// Represents the terminal symbol `mixin`
+ Mixin => "mixin",
+
+ /// Represents the terminal symbol `implements`
+ Implements => "implements",
+
+ /// Represents the terminal symbol `legacycaller`
+ LegacyCaller => "legacycaller",
+
+ /// Represents the terminal symbol `constructor`
+ Constructor => "constructor",
+}
+
+#[macro_export]
+macro_rules! term {
+ (OpenParen) => {
+ $crate::term::OpenParen
+ };
+ (CloseParen) => {
+ $crate::term::CloseParen
+ };
+ (OpenBracket) => {
+ $crate::term::OpenBracket
+ };
+ (CloseBracket) => {
+ $crate::term::CloseBracket
+ };
+ (OpenBrace) => {
+ $crate::term::OpenBrace
+ };
+ (CloseBrace) => {
+ $crate::term::CloseBrace
+ };
+ (,) => {
+ $crate::term::Comma
+ };
+ (-) => {
+ $crate::term::Minus
+ };
+ (.) => {
+ $crate::term::Dot
+ };
+ (...) => {
+ $crate::term::Ellipsis
+ };
+ (:) => {
+ $crate::term::Colon
+ };
+ (;) => {
+ $crate::term::SemiColon
+ };
+ (<) => {
+ $crate::term::LessThan
+ };
+ (=) => {
+ $crate::term::Assign
+ };
+ (>) => {
+ $crate::term::GreaterThan
+ };
+ (?) => {
+ $crate::term::QMark
+ };
+ (or) => {
+ $crate::term::Or
+ };
+ (optional) => {
+ $crate::term::Optional
+ };
+ (async) => {
+ $crate::term::Async
+ };
+ (attribute) => {
+ $crate::term::Attribute
+ };
+ (callback) => {
+ $crate::term::Callback
+ };
+ (const) => {
+ $crate::term::Const
+ };
+ (deleter) => {
+ $crate::term::Deleter
+ };
+ (dictionary) => {
+ $crate::term::Dictionary
+ };
+ (enum) => {
+ $crate::term::Enum
+ };
+ (getter) => {
+ $crate::term::Getter
+ };
+ (includes) => {
+ $crate::term::Includes
+ };
+ (inherit) => {
+ $crate::term::Inherit
+ };
+ (interface) => {
+ $crate::term::Interface
+ };
+ (iterable) => {
+ $crate::term::Iterable
+ };
+ (maplike) => {
+ $crate::term::Maplike
+ };
+ (namespace) => {
+ $crate::term::Namespace
+ };
+ (partial) => {
+ $crate::term::Partial
+ };
+ (required) => {
+ $crate::term::Required
+ };
+ (setlike) => {
+ $crate::term::Setlike
+ };
+ (setter) => {
+ $crate::term::Setter
+ };
+ (static) => {
+ $crate::term::Static
+ };
+ (stringifier) => {
+ $crate::term::Stringifier
+ };
+ (typedef) => {
+ $crate::term::Typedef
+ };
+ (unrestricted) => {
+ $crate::term::Unrestricted
+ };
+ (symbol) => {
+ $crate::term::Symbol
+ };
+ (- Infinity) => {
+ $crate::term::NegInfinity
+ };
+ (ByteString) => {
+ $crate::term::ByteString
+ };
+ (DOMString) => {
+ $crate::term::DOMString
+ };
+ (FrozenArray) => {
+ $crate::term::FrozenArray
+ };
+ (Infinity) => {
+ $crate::term::Infinity
+ };
+ (NaN) => {
+ $crate::term::NaN
+ };
+ (USVString) => {
+ $crate::term::USVString
+ };
+ (any) => {
+ $crate::term::Any
+ };
+ (boolean) => {
+ $crate::term::Boolean
+ };
+ (byte) => {
+ $crate::term::Byte
+ };
+ (double) => {
+ $crate::term::Double
+ };
+ (false) => {
+ $crate::term::False
+ };
+ (float) => {
+ $crate::term::Float
+ };
+ (long) => {
+ $crate::term::Long
+ };
+ (null) => {
+ $crate::term::Null
+ };
+ (object) => {
+ $crate::term::Object
+ };
+ (octet) => {
+ $crate::term::Octet
+ };
+ (sequence) => {
+ $crate::term::Sequence
+ };
+ (short) => {
+ $crate::term::Short
+ };
+ (true) => {
+ $crate::term::True
+ };
+ (unsigned) => {
+ $crate::term::Unsigned
+ };
+ (undefined) => {
+ $crate::term::Undefined
+ };
+ (record) => {
+ $crate::term::Record
+ };
+ (ArrayBuffer) => {
+ $crate::term::ArrayBuffer
+ };
+ (DataView) => {
+ $crate::term::DataView
+ };
+ (Int8Array) => {
+ $crate::term::Int8Array
+ };
+ (Int16Array) => {
+ $crate::term::Int16Array
+ };
+ (Int32Array) => {
+ $crate::term::Int32Array
+ };
+ (Uint8Array) => {
+ $crate::term::Uint8Array
+ };
+ (Uint16Array) => {
+ $crate::term::Uint16Array
+ };
+ (Uint32Array) => {
+ $crate::term::Uint32Array
+ };
+ (Uint8ClampedArray) => {
+ $crate::term::Uint8ClampedArray
+ };
+ (Float32Array) => {
+ $crate::term::Float32Array
+ };
+ (Float64Array) => {
+ $crate::term::Float64Array
+ };
+ (ArrayBufferView) => {
+ $crate::term::ArrayBufferView
+ };
+ (BufferSource) => {
+ $crate::term::BufferSource
+ };
+ (Promise) => {
+ $crate::term::Promise
+ };
+ (Error) => {
+ $crate::term::Error
+ };
+ (readonly) => {
+ $crate::term::ReadOnly
+ };
+ (mixin) => {
+ $crate::term::Mixin
+ };
+ (implements) => {
+ $crate::term::Implements
+ };
+ (legacycaller) => {
+ $crate::term::LegacyCaller
+ };
+ (constructor) => {
+ $crate::term::Constructor
+ };
+}
+
+#[cfg(test)]
+mod test {
+ macro_rules! generate_tests {
+ ($($m:ident, $typ:ident, $string:expr;)*) => {
+ $(
+ mod $m {
+ use super::super::$typ;
+ use crate::Parse;
+
+ #[test]
+ fn should_parse() {
+ let (rem, parsed) = $typ::parse(concat!($string)).unwrap();
+ assert_eq!(rem, "");
+ assert_eq!(parsed, $typ);
+ }
+
+ #[test]
+ fn should_parse_with_preceding_spaces() {
+ let (rem, parsed) = $typ::parse(concat!(" ", $string)).unwrap();
+ assert_eq!(rem, "");
+ assert_eq!(parsed, $typ);
+ }
+
+ #[test]
+ fn should_parse_with_succeeding_spaces() {
+ let (rem, parsed) = $typ::parse(concat!($string, " ")).unwrap();
+ assert_eq!(rem, "");
+ assert_eq!(parsed, $typ);
+ }
+
+ #[test]
+ fn should_parse_with_surrounding_spaces() {
+ let (rem, parsed) = $typ::parse(concat!(" ", $string, " ")).unwrap();
+ assert_eq!(rem, "");
+ assert_eq!(parsed, $typ);
+ }
+
+ #[test]
+ fn should_parse_if_anything_next() {
+ let (rem, parsed) = $typ::parse(concat!($string, " anything")).unwrap();
+ assert_eq!(rem, "anything");
+ assert_eq!(parsed, $typ);
+ }
+ }
+ )*
+ };
+ }
+
+ generate_tests![
+ openparen, OpenParen, "(";
+ closeparen, CloseParen, ")";
+ openbracket, OpenBracket, "[";
+ closebracket, CloseBracket, "]";
+ openbrace, OpenBrace, "{";
+ closebrace, CloseBrace, "}";
+ comma, Comma, ",";
+ minus, Minus, "-";
+ dot, Dot, ".";
+ ellipsis, Ellipsis, "...";
+ colon, Colon, ":";
+ semicolon, SemiColon, ";";
+ lessthan, LessThan, "<";
+ assign, Assign, "=";
+ greaterthan, GreaterThan, ">";
+ qmark, QMark, "?";
+ or, Or, "or";
+ optional, Optional, "optional";
+ async_, Async, "async";
+ attribute, Attribute, "attribute";
+ callback, Callback, "callback";
+ const_, Const, "const";
+ deleter, Deleter, "deleter";
+ dictionary, Dictionary, "dictionary";
+ enum_, Enum, "enum";
+ getter, Getter, "getter";
+ includes, Includes, "includes";
+ inherit, Inherit, "inherit";
+ interface, Interface, "interface";
+ iterable, Iterable, "iterable";
+ maplike, Maplike, "maplike";
+ namespace, Namespace, "namespace";
+ partial, Partial, "partial";
+ required, Required, "required";
+ setlike, Setlike, "setlike";
+ setter, Setter, "setter";
+ static_, Static, "static";
+ stringifier, Stringifier, "stringifier";
+ typedef, Typedef, "typedef";
+ unrestricted, Unrestricted, "unrestricted";
+ symbol, Symbol, "symbol";
+ neginfinity, NegInfinity, "-Infinity";
+ bytestring, ByteString, "ByteString";
+ domstring, DOMString, "DOMString";
+ frozenarray, FrozenArray, "FrozenArray";
+ infinity, Infinity, "Infinity";
+ nan, NaN, "NaN";
+ usvstring, USVString, "USVString";
+ any, Any, "any";
+ boolean, Boolean, "boolean";
+ byte, Byte, "byte";
+ double, Double, "double";
+ false_, False, "false";
+ float, Float, "float";
+ long, Long, "long";
+ null, Null, "null";
+ object, Object, "object";
+ octet, Octet, "octet";
+ sequence, Sequence, "sequence";
+ short, Short, "short";
+ true_, True, "true";
+ unsigned, Unsigned, "unsigned";
+ undefined, Undefined, "undefined";
+ record, Record, "record";
+ arraybuffer, ArrayBuffer, "ArrayBuffer";
+ dataview, DataView, "DataView";
+ int8array, Int8Array, "Int8Array";
+ int16array, Int16Array, "Int16Array";
+ int32array, Int32Array, "Int32Array";
+ uint8array, Uint8Array, "Uint8Array";
+ uint16array, Uint16Array, "Uint16Array";
+ uint32array, Uint32Array, "Uint32Array";
+ uint8clampedarray, Uint8ClampedArray, "Uint8ClampedArray";
+ float32array, Float32Array, "Float32Array";
+ float64array, Float64Array, "Float64Array";
+ promise, Promise, "Promise";
+ error, Error, "Error";
+ implements, Implements, "implements";
+ legacycaller, LegacyCaller, "legacycaller";
+ constructor, Constructor, "constructor";
+ ];
+}
diff --git a/third_party/rust/weedle2/src/types.rs b/third_party/rust/weedle2/src/types.rs
new file mode 100644
index 0000000000..913c307da9
--- /dev/null
+++ b/third_party/rust/weedle2/src/types.rs
@@ -0,0 +1,385 @@
+use crate::attribute::ExtendedAttributeList;
+use crate::common::{Generics, Identifier, Parenthesized, Punctuated};
+use crate::term;
+use crate::Parse;
+
+/// Parses a union of types
+pub type UnionType<'a> = Parenthesized<Punctuated<UnionMemberType<'a>, term!(or)>>;
+
+ast_types! {
+ /// Parses either single type or a union type
+ enum Type<'a> {
+ /// Parses one of the single types
+ Single(enum SingleType<'a> {
+ Any(term!(any)),
+ NonAny(NonAnyType<'a>),
+ }),
+ Union(MayBeNull<UnionType<'a>>),
+ }
+
+ // Parses any single non-any type
+ enum NonAnyType<'a> {
+ Promise(PromiseType<'a>),
+ Integer(MayBeNull<IntegerType>),
+ FloatingPoint(MayBeNull<FloatingPointType>),
+ Boolean(MayBeNull<term!(boolean)>),
+ Byte(MayBeNull<term!(byte)>),
+ Octet(MayBeNull<term!(octet)>),
+ ByteString(MayBeNull<term!(ByteString)>),
+ DOMString(MayBeNull<term!(DOMString)>),
+ USVString(MayBeNull<term!(USVString)>),
+ Sequence(MayBeNull<SequenceType<'a>>),
+ Object(MayBeNull<term!(object)>),
+ Symbol(MayBeNull<term!(symbol)>),
+ Error(MayBeNull<term!(Error)>),
+ ArrayBuffer(MayBeNull<term!(ArrayBuffer)>),
+ DataView(MayBeNull<term!(DataView)>),
+ Int8Array(MayBeNull<term!(Int8Array)>),
+ Int16Array(MayBeNull<term!(Int16Array)>),
+ Int32Array(MayBeNull<term!(Int32Array)>),
+ Uint8Array(MayBeNull<term!(Uint8Array)>),
+ Uint16Array(MayBeNull<term!(Uint16Array)>),
+ Uint32Array(MayBeNull<term!(Uint32Array)>),
+ Uint8ClampedArray(MayBeNull<term!(Uint8ClampedArray)>),
+ Float32Array(MayBeNull<term!(Float32Array)>),
+ Float64Array(MayBeNull<term!(Float64Array)>),
+ ArrayBufferView(MayBeNull<term!(ArrayBufferView)>),
+ BufferSource(MayBeNull<term!(BufferSource)>),
+ FrozenArrayType(MayBeNull<FrozenArrayType<'a>>),
+ RecordType(MayBeNull<RecordType<'a>>),
+ Identifier(MayBeNull<Identifier<'a>>),
+ }
+
+ /// Parses `sequence<Type>`
+ struct SequenceType<'a> {
+ sequence: term!(sequence),
+ generics: Generics<Box<Type<'a>>>,
+ }
+
+ /// Parses `FrozenArray<Type>`
+ struct FrozenArrayType<'a> {
+ frozen_array: term!(FrozenArray),
+ generics: Generics<Box<Type<'a>>>,
+ }
+
+ /// Parses a nullable type. Ex: `object | object??`
+ ///
+ /// `??` means an actual ? not an optional requirement
+ #[derive(Copy)]
+ struct MayBeNull<T> where [T: Parse<'a>] {
+ type_: T,
+ q_mark: Option<term::QMark>,
+ }
+
+ /// Parses a `Promise<Type|undefined>` type
+ struct PromiseType<'a> {
+ promise: term!(Promise),
+ generics: Generics<Box<ReturnType<'a>>>,
+ }
+
+ /// Parses `unsigned? short|long|(long long)`
+ #[derive(Copy)]
+ enum IntegerType {
+ /// Parses `unsigned? long long`
+ #[derive(Copy)]
+ LongLong(struct LongLongType {
+ unsigned: Option<term!(unsigned)>,
+ long_long: (term!(long), term!(long)),
+ }),
+ /// Parses `unsigned? long`
+ #[derive(Copy)]
+ Long(struct LongType {
+ unsigned: Option<term!(unsigned)>,
+ long: term!(long),
+ }),
+ /// Parses `unsigned? short`
+ #[derive(Copy)]
+ Short(struct ShortType {
+ unsigned: Option<term!(unsigned)>,
+ short: term!(short),
+ }),
+ }
+
+ /// Parses `unrestricted? float|double`
+ #[derive(Copy)]
+ enum FloatingPointType {
+ /// Parses `unrestricted? float`
+ #[derive(Copy)]
+ Float(struct FloatType {
+ unrestricted: Option<term!(unrestricted)>,
+ float: term!(float),
+ }),
+ /// Parses `unrestricted? double`
+ #[derive(Copy)]
+ Double(struct DoubleType {
+ unrestricted: Option<term!(unrestricted)>,
+ double: term!(double),
+ }),
+ }
+
+ /// Parses `record<StringType, Type>`
+ struct RecordType<'a> {
+ record: term!(record),
+ generics: Generics<(Box<RecordKeyType<'a>>, term!(,), Box<Type<'a>>)>,
+ }
+
+ /// Parses one of the string types `ByteString|DOMString|USVString` or any other type.
+ enum RecordKeyType<'a> {
+ Byte(term!(ByteString)),
+ DOM(term!(DOMString)),
+ USV(term!(USVString)),
+ NonAny(NonAnyType<'a>),
+ }
+
+ /// Parses one of the member of a union type
+ enum UnionMemberType<'a> {
+ Single(AttributedNonAnyType<'a>),
+ Union(MayBeNull<UnionType<'a>>),
+ }
+
+ /// Parses a const type
+ enum ConstType<'a> {
+ Integer(MayBeNull<IntegerType>),
+ FloatingPoint(MayBeNull<FloatingPointType>),
+ Boolean(MayBeNull<term!(boolean)>),
+ Byte(MayBeNull<term!(byte)>),
+ Octet(MayBeNull<term!(octet)>),
+ Identifier(MayBeNull<Identifier<'a>>),
+ }
+
+ /// Parses the return type which may be `undefined` or any given Type
+ enum ReturnType<'a> {
+ Undefined(term!(undefined)),
+ Type(Type<'a>),
+ }
+
+ /// Parses `[attributes]? type`
+ struct AttributedType<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ type_: Type<'a>,
+ }
+
+ /// Parses `[attributes]? type` where the type is a single non-any type
+ struct AttributedNonAnyType<'a> {
+ attributes: Option<ExtendedAttributeList<'a>>,
+ type_: NonAnyType<'a>,
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ test!(should_parse_may_be_null { "short" =>
+ "";
+ MayBeNull<crate::types::IntegerType>;
+ q_mark.is_none();
+ });
+
+ test!(should_parse_nullable { "short?" =>
+ "";
+ MayBeNull<crate::types::IntegerType>;
+ q_mark.is_some();
+ });
+
+ test_variants!(
+ ReturnType {
+ Undefined == "undefined",
+ Type == "any",
+ }
+ );
+
+ test_variants!(
+ ConstType {
+ Integer == "short",
+ FloatingPoint == "float",
+ Boolean == "boolean",
+ Byte == "byte",
+ Octet == "octet",
+ Identifier == "name",
+ }
+ );
+
+ test_variants!(
+ NonAnyType {
+ Promise == "Promise<long>",
+ Integer == "long",
+ FloatingPoint == "float",
+ Boolean == "boolean",
+ Byte == "byte",
+ Octet == "octet",
+ ByteString == "ByteString",
+ DOMString == "DOMString",
+ USVString == "USVString",
+ Sequence == "sequence<short>",
+ Object == "object",
+ Symbol == "symbol",
+ Error == "Error",
+ ArrayBuffer == "ArrayBuffer",
+ DataView == "DataView",
+ Int8Array == "Int8Array",
+ Int16Array == "Int16Array",
+ Int32Array == "Int32Array",
+ Uint8Array == "Uint8Array",
+ Uint16Array == "Uint16Array",
+ Uint32Array == "Uint32Array",
+ Uint8ClampedArray == "Uint8ClampedArray",
+ Float32Array == "Float32Array",
+ Float64Array == "Float64Array",
+ ArrayBufferView == "ArrayBufferView",
+ BufferSource == "BufferSource",
+ FrozenArrayType == "FrozenArray<short>",
+ RecordType == "record<DOMString, short>",
+ Identifier == "mango"
+ }
+ );
+
+ test_variants!(
+ UnionMemberType {
+ Single == "byte",
+ Union == "([Clamp] unsigned long or byte)"
+ }
+ );
+
+ test_variants!(
+ RecordKeyType {
+ DOM == "DOMString",
+ USV == "USVString",
+ Byte == "ByteString"
+ }
+ );
+
+ test!(should_parse_record_type { "record<DOMString, short>" =>
+ "";
+ RecordType;
+ });
+
+ test!(should_parse_record_type_alt_types { "record<u64, short>" =>
+ "";
+ RecordType;
+ });
+
+ test!(should_parse_double_type { "double" =>
+ "";
+ DoubleType;
+ });
+
+ test!(should_parse_float_type { "float" =>
+ "";
+ FloatType;
+ });
+
+ test_variants!(
+ FloatingPointType {
+ Float == "float",
+ Double == "double"
+ }
+ );
+
+ test!(should_parse_long_long_type { "long long" =>
+ "";
+ LongLongType;
+ });
+
+ test!(should_parse_long_type { "long" =>
+ "";
+ LongType;
+ });
+
+ test!(should_parse_short_type { "short" =>
+ "";
+ ShortType;
+ });
+
+ test_variants!(
+ IntegerType {
+ Short == "short",
+ Long == "long",
+ LongLong == "long long"
+ }
+ );
+
+ test!(should_parse_promise_type { "Promise<short>" =>
+ "";
+ PromiseType;
+ });
+
+ test!(should_parse_frozen_array_type { "FrozenArray<short>" =>
+ "";
+ FrozenArrayType;
+ });
+
+ test!(should_parse_sequence_type { "sequence<short>" =>
+ "";
+ SequenceType;
+ });
+
+ test_variants!(
+ SingleType {
+ Any == "any",
+ NonAny == "Promise<short>",
+ }
+ );
+
+ test_variants!(
+ Type {
+ Single == "short",
+ Union == "(short or float)"
+ }
+ );
+
+ test!(should_parse_attributed_type { "[Named] short" =>
+ "";
+ AttributedType;
+ attributes.is_some();
+ });
+
+ test!(should_parse_type_as_identifier { "DOMStringMap" =>
+ // if type is not parsed as identifier, it is parsed as `DOMString` and 'Map' is left
+ "";
+ crate::types::Type;
+ });
+
+ #[test]
+ fn should_parse_union_member_type_attributed_union() {
+ use crate::types::UnionMemberType;
+ let (rem, parsed) = UnionMemberType::parse("([Clamp] byte or [Named] byte)").unwrap();
+ assert_eq!(rem, "");
+ match parsed {
+ UnionMemberType::Union(MayBeNull {
+ type_:
+ Parenthesized {
+ body: Punctuated { list, .. },
+ ..
+ },
+ ..
+ }) => {
+ assert_eq!(list.len(), 2);
+
+ match list[0] {
+ UnionMemberType::Single(AttributedNonAnyType { ref attributes, .. }) => {
+ assert!(attributes.is_some());
+ }
+
+ _ => {
+ panic!("Failed to parse list[0] attributes");
+ }
+ };
+
+ match list[1] {
+ UnionMemberType::Single(AttributedNonAnyType { ref attributes, .. }) => {
+ assert!(attributes.is_some());
+ }
+
+ _ => {
+ panic!("Failed to parse list[1] attributes");
+ }
+ };
+ }
+
+ _ => {
+ panic!("Failed to parse");
+ }
+ }
+ }
+}
diff --git a/third_party/rust/weedle2/src/whitespace.rs b/third_party/rust/weedle2/src/whitespace.rs
new file mode 100644
index 0000000000..336e4784e1
--- /dev/null
+++ b/third_party/rust/weedle2/src/whitespace.rs
@@ -0,0 +1,34 @@
+use nom::{IResult, Parser};
+
+pub(crate) fn sp(input: &str) -> IResult<&str, &str> {
+ nom::combinator::recognize(nom::multi::many0(nom::branch::alt((
+ // ignores line comments
+ nom::combinator::value(
+ (),
+ nom::sequence::tuple((
+ nom::bytes::complete::tag("//"),
+ nom::bytes::complete::take_until("\n"),
+ nom::bytes::complete::tag("\n"),
+ )),
+ ),
+ // ignores whitespace
+ nom::combinator::value((), nom::character::complete::multispace1),
+ // ignores block comments
+ nom::combinator::value(
+ (),
+ nom::sequence::tuple((
+ nom::bytes::complete::tag("/*"),
+ nom::bytes::complete::take_until("*/"),
+ nom::bytes::complete::tag("*/"),
+ )),
+ ),
+ ))))(input)
+}
+
+/// ws also ignores line & block comments
+pub(crate) fn ws<'a, F>(inner: F) -> impl FnMut(&'a str) -> IResult<&str, &str>
+where
+ F: Parser<&'a str, &'a str, nom::error::Error<&'a str>>,
+{
+ nom::sequence::delimited(sp, inner, sp)
+}