diff options
Diffstat (limited to 'third_party/rust/weedle2/src/lib.rs')
-rw-r--r-- | third_party/rust/weedle2/src/lib.rs | 408 |
1 files changed, 408 insertions, 0 deletions
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; + }); +} |