зеркало из https://github.com/mozilla/uniffi-rs.git
Merge pull request #1223 from badboy/vendored-weedle2
Vendor complete weedle2 codebase into this repository
This commit is contained in:
Коммит
4006fcb041
|
@ -5,6 +5,7 @@ members = [
|
|||
"uniffi_macros",
|
||||
"uniffi_testing",
|
||||
"uniffi",
|
||||
"weedle2",
|
||||
"examples/arithmetic",
|
||||
"examples/callbacks",
|
||||
"examples/geometry",
|
||||
|
|
|
@ -16,7 +16,7 @@ path = "src/main.rs"
|
|||
|
||||
[dependencies]
|
||||
cargo_metadata = "0.13"
|
||||
weedle2 = "2.0.0"
|
||||
weedle2 = { version = "2.0.0", path = "../weedle2" }
|
||||
anyhow = "1"
|
||||
askama = { version = "0.11", default-features = false, features = ["config"] }
|
||||
heck = "0.4"
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
.idea/
|
||||
*.iml
|
|
@ -0,0 +1,6 @@
|
|||
language: rust
|
||||
rust:
|
||||
stable
|
||||
cache: cargo
|
||||
script:
|
||||
- cargo test
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "weedle2"
|
||||
version = "2.0.0"
|
||||
authors = ["Sharad Chand <sharad.d.chand@gmail.com>"]
|
||||
description = "A WebIDL Parser"
|
||||
license = "MIT"
|
||||
documentation = "https://docs.rs/weedle2"
|
||||
homepage = "https://github.com/badboy/weedle"
|
||||
repository = "https://github.com/badboy/weedle"
|
||||
readme = "./README.md"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "weedle"
|
||||
|
||||
[dependencies]
|
||||
nom = { version = "5.0.0", default-features = false, features = ["std"] }
|
|
@ -0,0 +1,15 @@
|
|||
Copyright 2018-Present Sharad Chand
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,46 @@
|
|||
<div align="center">
|
||||
|
||||
<h1>Weedle 2 - Electric Boogaloo</h1>
|
||||
|
||||
<strong>A Web IDL parser</strong>
|
||||
|
||||
<p>
|
||||
<a href="https://crates.io/crates/weedle2"><img src="https://img.shields.io/crates/v/weedle2.svg?style=flat-square" alt="Crates.io version" /></a>
|
||||
<a href="https://docs.rs/weedle2"><img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square" alt="Documentation" /></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/github/license/badboy/signify-rs?style=flat-square" alt="MIT License" /></a>
|
||||
</p>
|
||||
|
||||
<sub>
|
||||
Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a>.
|
||||
<br>
|
||||
Forked to extend the functionality beyond WebIDL needs.
|
||||
</sub>
|
||||
</div>
|
||||
|
||||
## About
|
||||
|
||||
Parses valid WebIDL definitions & produces a data structure starting from
|
||||
[`Definitions`](https://docs.rs/weedle/latest/weedle/type.Definitions.html).
|
||||
|
||||
## Usage
|
||||
|
||||
### `Cargo.toml`
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
weedle2 = "2.0.0-alpha0"
|
||||
```
|
||||
|
||||
### `src/main.rs`
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let parsed = weedle::parse("
|
||||
interface Window {
|
||||
readonly attribute Storage sessionStorage;
|
||||
};
|
||||
").unwrap();
|
||||
|
||||
println!("{:?}", parsed);
|
||||
}
|
||||
```
|
|
@ -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>> = map!(
|
||||
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"))),
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
use crate::literal::DefaultValue;
|
||||
use crate::term;
|
||||
use crate::Parse;
|
||||
|
||||
impl<'a, T: Parse<'a>> Parse<'a> for Option<T> {
|
||||
parser!(opt!(weedle!(T)));
|
||||
}
|
||||
|
||||
impl<'a, T: Parse<'a>> Parse<'a> for Box<T> {
|
||||
parser!(do_parse!(inner: weedle!(T) >> (Box::new(inner))));
|
||||
}
|
||||
|
||||
/// Parses `item1 item2 item3...`
|
||||
impl<'a, T: Parse<'a>> Parse<'a> for Vec<T> {
|
||||
parser!(many0!(weedle!(T)));
|
||||
}
|
||||
|
||||
impl<'a, T: Parse<'a>, U: Parse<'a>> Parse<'a> for (T, U) {
|
||||
parser!(do_parse!(t: weedle!(T) >> u: weedle!(U) >> ((t, u))));
|
||||
}
|
||||
|
||||
impl<'a, T: Parse<'a>, U: Parse<'a>, V: Parse<'a>> Parse<'a> for (T, U, V) {
|
||||
parser!(do_parse!(
|
||||
t: weedle!(T) >> u: weedle!(U) >> v: weedle!(V) >> ((t, u, v))
|
||||
));
|
||||
}
|
||||
|
||||
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> = separated_list!(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> = terminated!(
|
||||
separated_nonempty_list!(weedle!(S), weedle!(T)),
|
||||
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 = ws!(do_parse!(
|
||||
opt!(char!('_')) >>
|
||||
id: recognize!(do_parse!(
|
||||
take_while1!(|c: char| c.is_ascii_alphabetic()) >>
|
||||
take_while!(|c: char| c.is_ascii_alphanumeric() || c == '_' || c == '-') >>
|
||||
(())
|
||||
)) >>
|
||||
(id)
|
||||
)),
|
||||
)
|
||||
|
||||
/// 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_preceeding_others { "hello note" =>
|
||||
"note";
|
||||
Identifier;
|
||||
0 == "hello";
|
||||
});
|
||||
|
||||
test!(should_parse_identifier_attached_to_symbol { "hello=" =>
|
||||
"=";
|
||||
Identifier;
|
||||
0 == "hello";
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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";
|
||||
});
|
||||
}
|
|
@ -0,0 +1,425 @@
|
|||
//! 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.
|
||||
|
||||
// need a higher recusion limit for macros
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
#[macro_use(
|
||||
alt,
|
||||
cond,
|
||||
do_parse,
|
||||
map,
|
||||
many0,
|
||||
opt,
|
||||
recognize,
|
||||
separated_list,
|
||||
separated_nonempty_list,
|
||||
terminated
|
||||
)]
|
||||
extern crate nom;
|
||||
|
||||
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::ErrorKind, 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<(&str, ErrorKind)>> {
|
||||
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;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
ast_types! {
|
||||
/// Represents an integer value
|
||||
#[derive(Copy)]
|
||||
enum IntegerLit<'a> {
|
||||
/// Parses `-?[1-9][0-9]*`
|
||||
#[derive(Copy)]
|
||||
Dec(struct DecLit<'a>(
|
||||
&'a str = ws!(recognize!(do_parse!(
|
||||
opt!(char!('-')) >>
|
||||
one_of!("123456789") >>
|
||||
take_while!(|c: char| c.is_ascii_digit()) >>
|
||||
(())
|
||||
))),
|
||||
)),
|
||||
/// Parses `-?0[Xx][0-9A-Fa-f]+)`
|
||||
#[derive(Copy)]
|
||||
Hex(struct HexLit<'a>(
|
||||
&'a str = ws!(recognize!(do_parse!(
|
||||
opt!(char!('-')) >>
|
||||
char!('0') >>
|
||||
alt!(char!('x') | char!('X')) >>
|
||||
take_while!(|c: char| c.is_ascii_hexdigit()) >>
|
||||
(())
|
||||
))),
|
||||
)),
|
||||
/// Parses `-?0[0-7]*`
|
||||
#[derive(Copy)]
|
||||
Oct(struct OctLit<'a>(
|
||||
&'a str = ws!(recognize!(do_parse!(
|
||||
opt!(char!('-')) >>
|
||||
char!('0') >>
|
||||
take_while!(|c| ('0'..='7').contains(&c)) >>
|
||||
(())
|
||||
))),
|
||||
)),
|
||||
}
|
||||
|
||||
/// Represents a string value
|
||||
///
|
||||
/// Follow `/"[^"]*"/`
|
||||
#[derive(Copy)]
|
||||
struct StringLit<'a>(
|
||||
&'a str = ws!(do_parse!(
|
||||
char!('"') >>
|
||||
s: take_while!(|c| c != '"') >>
|
||||
char!('"') >>
|
||||
(s)
|
||||
)),
|
||||
)
|
||||
|
||||
/// 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 = alt!(
|
||||
weedle!(term!(true)) => {|_| true} |
|
||||
weedle!(term!(false)) => {|_| 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 = ws!(recognize!(do_parse!(
|
||||
opt!(char!('-')) >>
|
||||
alt!(
|
||||
do_parse!(
|
||||
// (?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)
|
||||
alt!(
|
||||
do_parse!(
|
||||
take_while1!(|c: char| c.is_ascii_digit()) >>
|
||||
char!('.') >>
|
||||
take_while!(|c: char| c.is_ascii_digit()) >>
|
||||
(())
|
||||
)
|
||||
|
|
||||
do_parse!(
|
||||
take_while!(|c: char| c.is_ascii_digit()) >>
|
||||
char!('.') >>
|
||||
take_while1!(|c: char| c.is_ascii_digit()) >>
|
||||
(())
|
||||
)
|
||||
) >>
|
||||
// (?:[Ee][+-]?[0-9]+)?
|
||||
opt!(do_parse!(
|
||||
alt!(char!('e') | char!('E')) >>
|
||||
opt!(alt!(char!('+') | char!('-'))) >>
|
||||
take_while1!(|c: char| c.is_ascii_digit()) >>
|
||||
(())
|
||||
)) >>
|
||||
(())
|
||||
)
|
||||
|
|
||||
// [0-9]+[Ee][+-]?[0-9]+
|
||||
do_parse!(
|
||||
take_while1!(|c: char| c.is_ascii_digit()) >>
|
||||
alt!(char!('e') | char!('E')) >>
|
||||
opt!(alt!(char!('+') | char!('-'))) >>
|
||||
take_while1!(|c: char| c.is_ascii_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_preceeding_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_preceeding_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 { "5.3434e23" =>
|
||||
"";
|
||||
FloatLit => FloatLit::Value(FloatValueLit("5.3434e23"))
|
||||
});
|
||||
|
||||
test!(should_parse_float_exp_with_decimal { "3e23" =>
|
||||
"";
|
||||
FloatLit => FloatLit::Value(FloatValueLit("3e23"))
|
||||
});
|
||||
|
||||
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)
|
||||
});
|
||||
}
|
|
@ -0,0 +1,614 @@
|
|||
macro_rules! tag {
|
||||
($i:expr, $tag: expr) => {
|
||||
nom::bytes::complete::tag($tag)($i)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! take_while {
|
||||
($input:expr, $submac:ident!( $($args:tt)* )) => {
|
||||
$crate::macros::take_while!($input, (|c| $submac!(c, $($args)*)))
|
||||
};
|
||||
($input:expr, $f:expr) => {
|
||||
nom::bytes::complete::take_while($f)($input)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! take_while1 {
|
||||
($input:expr, $submac:ident!( $($args:tt)* )) => {
|
||||
$crate::macros::take_while1!($input, (|c| $submac!(c, $($args)*)))
|
||||
};
|
||||
($input:expr, $f:expr) => {
|
||||
nom::bytes::complete::take_while1($f)($input)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! take_until {
|
||||
($i:expr, $substr:expr) => {
|
||||
nom::bytes::complete::take_until($substr)($i)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! one_of {
|
||||
($i:expr, $inp: expr) => {
|
||||
nom::character::complete::one_of($inp)($i)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! char {
|
||||
($i:expr, $c: expr) => {
|
||||
nom::character::complete::char($c)($i)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! parser {
|
||||
($submac:ident!( $($args:tt)* )) => {
|
||||
fn parse(input: &'a str) -> $crate::IResult<&'a str, Self> {
|
||||
$submac!(input, $($args)*)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! weedle {
|
||||
($i:expr, $t:ty) => {
|
||||
<$t as $crate::Parse<'a>>::parse($i)
|
||||
};
|
||||
}
|
||||
|
||||
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 = $submac:ident!( $($args:tt)* ), )
|
||||
) => (
|
||||
$(#[$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 $crate::nom::lib::std::result::Result::*;
|
||||
|
||||
match $submac!(input, $($args)*) {
|
||||
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 = $submac:ident!( $($args:tt)* ), $($rest:tt)* }
|
||||
) => (
|
||||
__ast_struct! {
|
||||
@build_struct_decl
|
||||
{ $($prev)* $field : $type }
|
||||
{ $($rest)* }
|
||||
}
|
||||
);
|
||||
(@build_struct_decl
|
||||
{ $($prev:tt)* }
|
||||
{ $field:ident : $type:ty = marker, $($rest:tt)* }
|
||||
) => (
|
||||
__ast_struct! {
|
||||
@build_struct_decl
|
||||
{ $($prev)* $field : $type }
|
||||
{ $($rest)* }
|
||||
}
|
||||
);
|
||||
|
||||
(@build_parser
|
||||
{ $i:expr, $($field:ident)* }
|
||||
{ }
|
||||
) => ({
|
||||
use $crate::nom::lib::std::result::Result::Ok;
|
||||
Ok(($i, Self { $($field,)* }))
|
||||
});
|
||||
(@build_parser
|
||||
{ $i:expr, $($prev:tt)* }
|
||||
{ $field:ident : $type:ty = $submac:ident!( $($args:tt)* ), $($rest:tt)* }
|
||||
) => ({
|
||||
use $crate::nom::lib::std::result::Result::*;
|
||||
|
||||
match $submac!($i, $($args)*) {
|
||||
Err(e) => Err(e),
|
||||
Ok((i, $field)) => {
|
||||
__ast_struct! {
|
||||
@build_parser
|
||||
{ i, $($prev)* $field }
|
||||
{ $($rest)* }
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
(@build_parser
|
||||
{ $($prev:tt)* }
|
||||
{ $field:ident : $type:ty = marker, $($rest:tt)* }
|
||||
) => ({
|
||||
let $field = ::std::default::Default::default();
|
||||
__ast_struct! {
|
||||
@build_parser
|
||||
{ $($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!(
|
||||
$(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"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,697 @@
|
|||
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!(do_parse!(
|
||||
ws!(tag!($tok)) >>
|
||||
($typ)
|
||||
));
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! ident_tag (
|
||||
($i:expr, $tok:expr) => (
|
||||
{
|
||||
match tag!($i, $tok) {
|
||||
Err(e) => Err(e),
|
||||
Ok((i, o)) => {
|
||||
use nom::{character::is_alphanumeric, Err as NomErr, error::ErrorKind};
|
||||
let mut res = Ok((i, o));
|
||||
if let Some(&c) = i.as_bytes().first() {
|
||||
if is_alphanumeric(c) || c == b'_' || c == b'-' {
|
||||
res = Err(NomErr::Error(($i, ErrorKind::Tag)));
|
||||
}
|
||||
}
|
||||
res
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
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!(do_parse!(
|
||||
ws!(ident_tag!($tok)) >>
|
||||
($typ)
|
||||
));
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
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";
|
||||
];
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
use crate::IResult;
|
||||
|
||||
pub(crate) fn sp(input: &str) -> IResult<&str, &str> {
|
||||
recognize!(
|
||||
input,
|
||||
many0!(alt!(
|
||||
// ignores line comments
|
||||
do_parse!(tag!("//") >> take_until!("\n") >> char!('\n') >> (()))
|
||||
|
|
||||
// ignores whitespace
|
||||
map!(take_while1!(|c| c == '\t' || c == '\n' || c == '\r' || c == ' '), |_| ())
|
||||
|
|
||||
// ignores block comments
|
||||
do_parse!(tag!("/*") >> take_until!("*/") >> tag!("*/") >> (()))
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
/// ws! also ignores line & block comments
|
||||
macro_rules! ws (
|
||||
($i:expr, $($args:tt)*) => ({
|
||||
use $crate::whitespace::sp;
|
||||
|
||||
do_parse!($i,
|
||||
sp >>
|
||||
s: $($args)* >>
|
||||
sp >>
|
||||
(s)
|
||||
)
|
||||
});
|
||||
);
|
|
@ -0,0 +1,549 @@
|
|||
[Constructor(DOMString type, optional EventInit eventInitDict),
|
||||
Exposed=(Window,Worker,AudioWorklet)]
|
||||
interface Event {
|
||||
readonly attribute DOMString type;
|
||||
readonly attribute EventTarget? target;
|
||||
readonly attribute EventTarget? srcElement; // historical
|
||||
readonly attribute EventTarget? currentTarget;
|
||||
sequence<EventTarget> composedPath();
|
||||
|
||||
const unsigned short NONE = 0;
|
||||
const unsigned short CAPTURING_PHASE = 1;
|
||||
const unsigned short AT_TARGET = 2;
|
||||
const unsigned short BUBBLING_PHASE = 3;
|
||||
readonly attribute unsigned short eventPhase;
|
||||
|
||||
undefined stopPropagation();
|
||||
attribute boolean cancelBubble; // historical alias of .stopPropagation
|
||||
undefined stopImmediatePropagation();
|
||||
|
||||
readonly attribute boolean bubbles;
|
||||
readonly attribute boolean cancelable;
|
||||
attribute boolean returnValue; // historical
|
||||
undefined preventDefault();
|
||||
readonly attribute boolean defaultPrevented;
|
||||
readonly attribute boolean composed;
|
||||
|
||||
[Unforgeable] readonly attribute boolean isTrusted;
|
||||
readonly attribute DOMHighResTimeStamp timeStamp;
|
||||
|
||||
undefined initEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false); // historical
|
||||
};
|
||||
|
||||
dictionary EventInit {
|
||||
boolean bubbles = false;
|
||||
boolean cancelable = false;
|
||||
boolean composed = false;
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional CustomEventInit eventInitDict),
|
||||
Exposed=(Window,Worker)]
|
||||
interface CustomEvent : Event {
|
||||
readonly attribute any detail;
|
||||
|
||||
undefined initCustomEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional any detail = null);
|
||||
};
|
||||
|
||||
dictionary CustomEventInit : EventInit {
|
||||
any detail = null;
|
||||
};
|
||||
|
||||
[Constructor,
|
||||
Exposed=(Window,Worker,AudioWorklet)]
|
||||
interface EventTarget {
|
||||
undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options);
|
||||
undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
|
||||
boolean dispatchEvent(Event event);
|
||||
};
|
||||
|
||||
callback interface EventListener {
|
||||
undefined handleEvent(Event event);
|
||||
};
|
||||
|
||||
dictionary EventListenerOptions {
|
||||
boolean capture = false;
|
||||
};
|
||||
|
||||
dictionary AddEventListenerOptions : EventListenerOptions {
|
||||
boolean passive = false;
|
||||
boolean once = false;
|
||||
};
|
||||
|
||||
[Constructor,
|
||||
Exposed=(Window,Worker)]
|
||||
interface AbortController {
|
||||
[SameObject] readonly attribute AbortSignal signal;
|
||||
|
||||
undefined abort();
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface AbortSignal : EventTarget {
|
||||
readonly attribute boolean aborted;
|
||||
|
||||
attribute EventHandler onabort;
|
||||
};
|
||||
|
||||
interface mixin NonElementParentNode {
|
||||
Element? getElementById(DOMString elementId);
|
||||
};
|
||||
Document includes NonElementParentNode;
|
||||
DocumentFragment includes NonElementParentNode;
|
||||
|
||||
interface mixin DocumentOrShadowRoot {
|
||||
};
|
||||
Document includes DocumentOrShadowRoot;
|
||||
ShadowRoot includes DocumentOrShadowRoot;
|
||||
|
||||
interface mixin ParentNode {
|
||||
[SameObject] readonly attribute HTMLCollection children;
|
||||
readonly attribute Element? firstElementChild;
|
||||
readonly attribute Element? lastElementChild;
|
||||
readonly attribute unsigned long childElementCount;
|
||||
|
||||
[CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes);
|
||||
[CEReactions, Unscopable] undefined append((Node or DOMString)... nodes);
|
||||
|
||||
Element? querySelector(DOMString selectors);
|
||||
[NewObject] NodeList querySelectorAll(DOMString selectors);
|
||||
};
|
||||
Document includes ParentNode;
|
||||
DocumentFragment includes ParentNode;
|
||||
Element includes ParentNode;
|
||||
|
||||
interface mixin NonDocumentTypeChildNode {
|
||||
readonly attribute Element? previousElementSibling;
|
||||
readonly attribute Element? nextElementSibling;
|
||||
};
|
||||
Element includes NonDocumentTypeChildNode;
|
||||
CharacterData includes NonDocumentTypeChildNode;
|
||||
|
||||
interface mixin ChildNode {
|
||||
[CEReactions, Unscopable] undefined before((Node or DOMString)... nodes);
|
||||
[CEReactions, Unscopable] undefined after((Node or DOMString)... nodes);
|
||||
[CEReactions, Unscopable] undefined replaceWith((Node or DOMString)... nodes);
|
||||
[CEReactions, Unscopable] undefined remove();
|
||||
};
|
||||
DocumentType includes ChildNode;
|
||||
Element includes ChildNode;
|
||||
CharacterData includes ChildNode;
|
||||
|
||||
interface mixin Slotable {
|
||||
readonly attribute HTMLSlotElement? assignedSlot;
|
||||
};
|
||||
Element includes Slotable;
|
||||
Text includes Slotable;
|
||||
|
||||
[Exposed=Window]
|
||||
interface NodeList {
|
||||
getter Node? item(unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
iterable<Node>;
|
||||
};
|
||||
|
||||
[Exposed=Window, LegacyUnenumerableNamedProperties]
|
||||
interface HTMLCollection {
|
||||
readonly attribute unsigned long length;
|
||||
getter Element? item(unsigned long index);
|
||||
getter Element? namedItem(DOMString name);
|
||||
};
|
||||
|
||||
[Constructor(MutationCallback callback),
|
||||
Exposed=Window]
|
||||
interface MutationObserver {
|
||||
undefined observe(Node target, optional MutationObserverInit options);
|
||||
undefined disconnect();
|
||||
sequence<MutationRecord> takeRecords();
|
||||
};
|
||||
|
||||
callback MutationCallback = undefined (sequence<MutationRecord> mutations, MutationObserver observer);
|
||||
|
||||
dictionary MutationObserverInit {
|
||||
boolean childList = false;
|
||||
boolean attributes;
|
||||
boolean characterData;
|
||||
boolean subtree = false;
|
||||
boolean attributeOldValue;
|
||||
boolean characterDataOldValue;
|
||||
sequence<DOMString> attributeFilter;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface MutationRecord {
|
||||
readonly attribute DOMString type;
|
||||
[SameObject] readonly attribute Node target;
|
||||
[SameObject] readonly attribute NodeList addedNodes;
|
||||
[SameObject] readonly attribute NodeList removedNodes;
|
||||
readonly attribute Node? previousSibling;
|
||||
readonly attribute Node? nextSibling;
|
||||
readonly attribute DOMString? attributeName;
|
||||
readonly attribute DOMString? attributeNamespace;
|
||||
readonly attribute DOMString? oldValue;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface Node : EventTarget {
|
||||
const unsigned short ELEMENT_NODE = 1;
|
||||
const unsigned short ATTRIBUTE_NODE = 2;
|
||||
const unsigned short TEXT_NODE = 3;
|
||||
const unsigned short CDATA_SECTION_NODE = 4;
|
||||
const unsigned short ENTITY_REFERENCE_NODE = 5; // historical
|
||||
const unsigned short ENTITY_NODE = 6; // historical
|
||||
const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
|
||||
const unsigned short COMMENT_NODE = 8;
|
||||
const unsigned short DOCUMENT_NODE = 9;
|
||||
const unsigned short DOCUMENT_TYPE_NODE = 10;
|
||||
const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
|
||||
const unsigned short NOTATION_NODE = 12; // historical
|
||||
readonly attribute unsigned short nodeType;
|
||||
readonly attribute DOMString nodeName;
|
||||
|
||||
readonly attribute USVString baseURI;
|
||||
|
||||
readonly attribute boolean isConnected;
|
||||
readonly attribute Document? ownerDocument;
|
||||
Node getRootNode(optional GetRootNodeOptions options);
|
||||
readonly attribute Node? parentNode;
|
||||
readonly attribute Element? parentElement;
|
||||
boolean hasChildNodes();
|
||||
[SameObject] readonly attribute NodeList childNodes;
|
||||
readonly attribute Node? firstChild;
|
||||
readonly attribute Node? lastChild;
|
||||
readonly attribute Node? previousSibling;
|
||||
readonly attribute Node? nextSibling;
|
||||
|
||||
[CEReactions] attribute DOMString? nodeValue;
|
||||
[CEReactions] attribute DOMString? textContent;
|
||||
[CEReactions] undefined normalize();
|
||||
|
||||
[CEReactions, NewObject] Node cloneNode(optional boolean deep = false);
|
||||
boolean isEqualNode(Node? otherNode);
|
||||
boolean isSameNode(Node? otherNode); // historical alias of ===
|
||||
|
||||
const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
|
||||
const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02;
|
||||
const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04;
|
||||
const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08;
|
||||
const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
|
||||
const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
|
||||
unsigned short compareDocumentPosition(Node other);
|
||||
boolean contains(Node? other);
|
||||
|
||||
DOMString? lookupPrefix(DOMString? namespace);
|
||||
DOMString? lookupNamespaceURI(DOMString? prefix);
|
||||
boolean isDefaultNamespace(DOMString? namespace);
|
||||
|
||||
[CEReactions] Node insertBefore(Node node, Node? child);
|
||||
[CEReactions] Node appendChild(Node node);
|
||||
[CEReactions] Node replaceChild(Node node, Node child);
|
||||
[CEReactions] Node removeChild(Node child);
|
||||
};
|
||||
|
||||
dictionary GetRootNodeOptions {
|
||||
boolean composed = false;
|
||||
};
|
||||
|
||||
[Constructor,
|
||||
Exposed=Window]
|
||||
interface Document : Node {
|
||||
[SameObject] readonly attribute DOMImplementation implementation;
|
||||
readonly attribute USVString URL;
|
||||
readonly attribute USVString documentURI;
|
||||
readonly attribute USVString origin;
|
||||
readonly attribute DOMString compatMode;
|
||||
readonly attribute DOMString characterSet;
|
||||
readonly attribute DOMString charset; // historical alias of .characterSet
|
||||
readonly attribute DOMString inputEncoding; // historical alias of .characterSet
|
||||
readonly attribute DOMString contentType;
|
||||
|
||||
readonly attribute DocumentType? doctype;
|
||||
readonly attribute Element? documentElement;
|
||||
HTMLCollection getElementsByTagName(DOMString qualifiedName);
|
||||
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
|
||||
HTMLCollection getElementsByClassName(DOMString classNames);
|
||||
|
||||
[CEReactions, NewObject] Element createElement(DOMString localName, optional (DOMString or ElementCreationOptions) options);
|
||||
[CEReactions, NewObject] Element createElementNS(DOMString? namespace, DOMString qualifiedName, optional (DOMString or ElementCreationOptions) options);
|
||||
[NewObject] DocumentFragment createDocumentFragment();
|
||||
[NewObject] Text createTextNode(DOMString data);
|
||||
[NewObject] CDATASection createCDATASection(DOMString data);
|
||||
[NewObject] Comment createComment(DOMString data);
|
||||
[NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
|
||||
|
||||
[CEReactions, NewObject] Node importNode(Node node, optional boolean deep = false);
|
||||
[CEReactions] Node adoptNode(Node node);
|
||||
|
||||
[NewObject] Attr createAttribute(DOMString localName);
|
||||
[NewObject] Attr createAttributeNS(DOMString? namespace, DOMString qualifiedName);
|
||||
|
||||
[NewObject] Event createEvent(DOMString interface);
|
||||
|
||||
[NewObject] Range createRange();
|
||||
|
||||
// NodeFilter.SHOW_ALL = 0xFFFFFFFF
|
||||
[NewObject] NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
|
||||
[NewObject] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface XMLDocument : Document {};
|
||||
|
||||
dictionary ElementCreationOptions {
|
||||
DOMString is;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface DOMImplementation {
|
||||
[NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId);
|
||||
[NewObject] XMLDocument createDocument(DOMString? namespace, [TreatNullAs=EmptyString] DOMString qualifiedName, optional DocumentType? doctype = null);
|
||||
[NewObject] Document createHTMLDocument(optional DOMString title);
|
||||
|
||||
boolean hasFeature(); // useless; always returns true
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface DocumentType : Node {
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString publicId;
|
||||
readonly attribute DOMString systemId;
|
||||
};
|
||||
|
||||
[Constructor,
|
||||
Exposed=Window]
|
||||
interface DocumentFragment : Node {
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface ShadowRoot : DocumentFragment {
|
||||
readonly attribute ShadowRootMode mode;
|
||||
readonly attribute Element host;
|
||||
};
|
||||
|
||||
enum ShadowRootMode { "open", "closed" };
|
||||
|
||||
[Exposed=Window]
|
||||
interface Element : Node {
|
||||
readonly attribute DOMString? namespaceURI;
|
||||
readonly attribute DOMString? prefix;
|
||||
readonly attribute DOMString localName;
|
||||
readonly attribute DOMString tagName;
|
||||
|
||||
[CEReactions] attribute DOMString id;
|
||||
[CEReactions] attribute DOMString className;
|
||||
[SameObject, PutForwards=value] readonly attribute DOMTokenList classList;
|
||||
[CEReactions, Unscopable] attribute DOMString slot;
|
||||
|
||||
boolean hasAttributes();
|
||||
[SameObject] readonly attribute NamedNodeMap attributes;
|
||||
sequence<DOMString> getAttributeNames();
|
||||
DOMString? getAttribute(DOMString qualifiedName);
|
||||
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
|
||||
[CEReactions] undefined setAttribute(DOMString qualifiedName, DOMString value);
|
||||
[CEReactions] undefined setAttributeNS(DOMString? namespace, DOMString qualifiedName, DOMString value);
|
||||
[CEReactions] undefined removeAttribute(DOMString qualifiedName);
|
||||
[CEReactions] undefined removeAttributeNS(DOMString? namespace, DOMString localName);
|
||||
boolean hasAttribute(DOMString qualifiedName);
|
||||
boolean hasAttributeNS(DOMString? namespace, DOMString localName);
|
||||
|
||||
Attr? getAttributeNode(DOMString qualifiedName);
|
||||
Attr? getAttributeNodeNS(DOMString? namespace, DOMString localName);
|
||||
[CEReactions] Attr? setAttributeNode(Attr attr);
|
||||
[CEReactions] Attr? setAttributeNodeNS(Attr attr);
|
||||
[CEReactions] Attr removeAttributeNode(Attr attr);
|
||||
|
||||
ShadowRoot attachShadow(ShadowRootInit init);
|
||||
readonly attribute ShadowRoot? shadowRoot;
|
||||
|
||||
Element? closest(DOMString selectors);
|
||||
boolean matches(DOMString selectors);
|
||||
boolean webkitMatchesSelector(DOMString selectors); // historical alias of .matches
|
||||
|
||||
HTMLCollection getElementsByTagName(DOMString qualifiedName);
|
||||
HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
|
||||
HTMLCollection getElementsByClassName(DOMString classNames);
|
||||
|
||||
[CEReactions] Element? insertAdjacentElement(DOMString where, Element element); // historical
|
||||
undefined insertAdjacentText(DOMString where, DOMString data); // historical
|
||||
};
|
||||
|
||||
dictionary ShadowRootInit {
|
||||
required ShadowRootMode mode;
|
||||
};
|
||||
|
||||
[Exposed=Window,
|
||||
LegacyUnenumerableNamedProperties]
|
||||
interface NamedNodeMap {
|
||||
readonly attribute unsigned long length;
|
||||
getter Attr? item(unsigned long index);
|
||||
getter Attr? getNamedItem(DOMString qualifiedName);
|
||||
Attr? getNamedItemNS(DOMString? namespace, DOMString localName);
|
||||
[CEReactions] Attr? setNamedItem(Attr attr);
|
||||
[CEReactions] Attr? setNamedItemNS(Attr attr);
|
||||
[CEReactions] Attr removeNamedItem(DOMString qualifiedName);
|
||||
[CEReactions] Attr removeNamedItemNS(DOMString? namespace, DOMString localName);
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface Attr : Node {
|
||||
readonly attribute DOMString? namespaceURI;
|
||||
readonly attribute DOMString? prefix;
|
||||
readonly attribute DOMString localName;
|
||||
readonly attribute DOMString name;
|
||||
[CEReactions] attribute DOMString value;
|
||||
|
||||
readonly attribute Element? ownerElement;
|
||||
|
||||
readonly attribute boolean specified; // useless; always returns true
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface CharacterData : Node {
|
||||
attribute [TreatNullAs=EmptyString] DOMString data;
|
||||
readonly attribute unsigned long length;
|
||||
DOMString substringData(unsigned long offset, unsigned long count);
|
||||
undefined appendData(DOMString data);
|
||||
undefined insertData(unsigned long offset, DOMString data);
|
||||
undefined deleteData(unsigned long offset, unsigned long count);
|
||||
undefined replaceData(unsigned long offset, unsigned long count, DOMString data);
|
||||
};
|
||||
|
||||
[Constructor(optional DOMString data = ""),
|
||||
Exposed=Window]
|
||||
interface Text : CharacterData {
|
||||
[NewObject] Text splitText(unsigned long offset);
|
||||
readonly attribute DOMString wholeText;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface CDATASection : Text {
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface ProcessingInstruction : CharacterData {
|
||||
readonly attribute DOMString target;
|
||||
};
|
||||
|
||||
[Constructor(optional DOMString data = ""),
|
||||
Exposed=Window]
|
||||
interface Comment : CharacterData {
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface AbstractRange {
|
||||
readonly attribute Node startContainer;
|
||||
readonly attribute unsigned long startOffset;
|
||||
readonly attribute Node endContainer;
|
||||
readonly attribute unsigned long endOffset;
|
||||
readonly attribute boolean collapsed;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface StaticRange : AbstractRange {
|
||||
};
|
||||
|
||||
[Constructor,
|
||||
Exposed=Window]
|
||||
interface Range : AbstractRange {
|
||||
readonly attribute Node commonAncestorContainer;
|
||||
|
||||
undefined setStart(Node node, unsigned long offset);
|
||||
undefined setEnd(Node node, unsigned long offset);
|
||||
undefined setStartBefore(Node node);
|
||||
undefined setStartAfter(Node node);
|
||||
undefined setEndBefore(Node node);
|
||||
undefined setEndAfter(Node node);
|
||||
undefined collapse(optional boolean toStart = false);
|
||||
undefined selectNode(Node node);
|
||||
undefined selectNodeContents(Node node);
|
||||
|
||||
const unsigned short START_TO_START = 0;
|
||||
const unsigned short START_TO_END = 1;
|
||||
const unsigned short END_TO_END = 2;
|
||||
const unsigned short END_TO_START = 3;
|
||||
short compareBoundaryPoints(unsigned short how, Range sourceRange);
|
||||
|
||||
[CEReactions] undefined deleteContents();
|
||||
[CEReactions, NewObject] DocumentFragment extractContents();
|
||||
[CEReactions, NewObject] DocumentFragment cloneContents();
|
||||
[CEReactions] undefined insertNode(Node node);
|
||||
[CEReactions] undefined surroundContents(Node newParent);
|
||||
|
||||
[NewObject] Range cloneRange();
|
||||
undefined detach();
|
||||
|
||||
boolean isPointInRange(Node node, unsigned long offset);
|
||||
short comparePoint(Node node, unsigned long offset);
|
||||
|
||||
boolean intersectsNode(Node node);
|
||||
|
||||
stringifier;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface NodeIterator {
|
||||
[SameObject] readonly attribute Node root;
|
||||
readonly attribute Node referenceNode;
|
||||
readonly attribute boolean pointerBeforeReferenceNode;
|
||||
readonly attribute unsigned long whatToShow;
|
||||
readonly attribute NodeFilter? filter;
|
||||
|
||||
Node? nextNode();
|
||||
Node? previousNode();
|
||||
|
||||
undefined detach();
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface TreeWalker {
|
||||
[SameObject] readonly attribute Node root;
|
||||
readonly attribute unsigned long whatToShow;
|
||||
readonly attribute NodeFilter? filter;
|
||||
attribute Node currentNode;
|
||||
|
||||
Node? parentNode();
|
||||
Node? firstChild();
|
||||
Node? lastChild();
|
||||
Node? previousSibling();
|
||||
Node? nextSibling();
|
||||
Node? previousNode();
|
||||
Node? nextNode();
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
callback interface NodeFilter {
|
||||
// Constants for acceptNode()
|
||||
const unsigned short FILTER_ACCEPT = 1;
|
||||
const unsigned short FILTER_REJECT = 2;
|
||||
const unsigned short FILTER_SKIP = 3;
|
||||
|
||||
// Constants for whatToShow
|
||||
const unsigned long SHOW_ALL = 0xFFFFFFFF;
|
||||
const unsigned long SHOW_ELEMENT = 0x1;
|
||||
const unsigned long SHOW_ATTRIBUTE = 0x2;
|
||||
const unsigned long SHOW_TEXT = 0x4;
|
||||
const unsigned long SHOW_CDATA_SECTION = 0x8;
|
||||
const unsigned long SHOW_ENTITY_REFERENCE = 0x10; // historical
|
||||
const unsigned long SHOW_ENTITY = 0x20; // historical
|
||||
const unsigned long SHOW_PROCESSING_INSTRUCTION = 0x40;
|
||||
const unsigned long SHOW_COMMENT = 0x80;
|
||||
const unsigned long SHOW_DOCUMENT = 0x100;
|
||||
const unsigned long SHOW_DOCUMENT_TYPE = 0x200;
|
||||
const unsigned long SHOW_DOCUMENT_FRAGMENT = 0x400;
|
||||
const unsigned long SHOW_NOTATION = 0x800; // historical
|
||||
|
||||
unsigned short acceptNode(Node node);
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface DOMTokenList {
|
||||
readonly attribute unsigned long length;
|
||||
getter DOMString? item(unsigned long index);
|
||||
boolean contains(DOMString token);
|
||||
[CEReactions] undefined add(DOMString... tokens);
|
||||
[CEReactions] undefined remove(DOMString... tokens);
|
||||
[CEReactions] boolean toggle(DOMString token, optional boolean force);
|
||||
[CEReactions] boolean replace(DOMString token, DOMString newToken);
|
||||
boolean supports(DOMString token);
|
||||
[CEReactions] stringifier attribute DOMString value;
|
||||
iterable<DOMString>;
|
||||
};
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,4 @@
|
|||
interface InterfaceWithConstructor {
|
||||
[Throws]
|
||||
constructor(long a);
|
||||
};
|
|
@ -0,0 +1,246 @@
|
|||
[Exposed=Window,
|
||||
Constructor,
|
||||
Constructor(MediaStream stream),
|
||||
Constructor(sequence<MediaStreamTrack> tracks)]
|
||||
interface MediaStream : EventTarget {
|
||||
readonly attribute DOMString id;
|
||||
sequence<MediaStreamTrack> getAudioTracks();
|
||||
sequence<MediaStreamTrack> getVideoTracks();
|
||||
sequence<MediaStreamTrack> getTracks();
|
||||
MediaStreamTrack? getTrackById(DOMString trackId);
|
||||
undefined addTrack(MediaStreamTrack track);
|
||||
undefined removeTrack(MediaStreamTrack track);
|
||||
MediaStream clone();
|
||||
readonly attribute boolean active;
|
||||
attribute EventHandler onaddtrack;
|
||||
attribute EventHandler onremovetrack;
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface MediaStreamTrack : EventTarget {
|
||||
readonly attribute DOMString kind;
|
||||
readonly attribute DOMString id;
|
||||
readonly attribute DOMString label;
|
||||
attribute boolean enabled;
|
||||
readonly attribute boolean muted;
|
||||
attribute EventHandler onmute;
|
||||
attribute EventHandler onunmute;
|
||||
readonly attribute MediaStreamTrackState readyState;
|
||||
attribute EventHandler onended;
|
||||
MediaStreamTrack clone();
|
||||
undefined stop();
|
||||
MediaTrackCapabilities getCapabilities();
|
||||
MediaTrackConstraints getConstraints();
|
||||
MediaTrackSettings getSettings();
|
||||
Promise<undefined> applyConstraints(optional MediaTrackConstraints constraints = {});
|
||||
};
|
||||
|
||||
enum MediaStreamTrackState {
|
||||
"live",
|
||||
"ended"
|
||||
};
|
||||
|
||||
dictionary MediaTrackSupportedConstraints {
|
||||
boolean width = true;
|
||||
boolean height = true;
|
||||
boolean aspectRatio = true;
|
||||
boolean frameRate = true;
|
||||
boolean facingMode = true;
|
||||
boolean resizeMode = true;
|
||||
boolean volume = true;
|
||||
boolean sampleRate = true;
|
||||
boolean sampleSize = true;
|
||||
boolean echoCancellation = true;
|
||||
boolean autoGainControl = true;
|
||||
boolean noiseSuppression = true;
|
||||
boolean latency = true;
|
||||
boolean channelCount = true;
|
||||
boolean deviceId = true;
|
||||
boolean groupId = true;
|
||||
};
|
||||
|
||||
dictionary MediaTrackCapabilities {
|
||||
ULongRange width;
|
||||
ULongRange height;
|
||||
DoubleRange aspectRatio;
|
||||
DoubleRange frameRate;
|
||||
sequence<DOMString> facingMode;
|
||||
sequence<DOMString> resizeMode;
|
||||
DoubleRange volume;
|
||||
ULongRange sampleRate;
|
||||
ULongRange sampleSize;
|
||||
sequence<boolean> echoCancellation;
|
||||
sequence<boolean> autoGainControl;
|
||||
sequence<boolean> noiseSuppression;
|
||||
DoubleRange latency;
|
||||
ULongRange channelCount;
|
||||
DOMString deviceId;
|
||||
DOMString groupId;
|
||||
};
|
||||
|
||||
dictionary MediaTrackConstraints : MediaTrackConstraintSet {
|
||||
sequence<MediaTrackConstraintSet> advanced;
|
||||
};
|
||||
|
||||
dictionary MediaTrackConstraintSet {
|
||||
ConstrainULong width;
|
||||
ConstrainULong height;
|
||||
ConstrainDouble aspectRatio;
|
||||
ConstrainDouble frameRate;
|
||||
ConstrainDOMString facingMode;
|
||||
ConstrainDOMString resizeMode;
|
||||
ConstrainDouble volume;
|
||||
ConstrainULong sampleRate;
|
||||
ConstrainULong sampleSize;
|
||||
ConstrainBoolean echoCancellation;
|
||||
ConstrainBoolean autoGainControl;
|
||||
ConstrainBoolean noiseSuppression;
|
||||
ConstrainDouble latency;
|
||||
ConstrainULong channelCount;
|
||||
ConstrainDOMString deviceId;
|
||||
ConstrainDOMString groupId;
|
||||
};
|
||||
|
||||
dictionary MediaTrackSettings {
|
||||
long width;
|
||||
long height;
|
||||
double aspectRatio;
|
||||
double frameRate;
|
||||
DOMString facingMode;
|
||||
DOMString resizeMode;
|
||||
double volume;
|
||||
long sampleRate;
|
||||
long sampleSize;
|
||||
boolean echoCancellation;
|
||||
boolean autoGainControl;
|
||||
boolean noiseSuppression;
|
||||
double latency;
|
||||
long channelCount;
|
||||
DOMString deviceId;
|
||||
DOMString groupId;
|
||||
};
|
||||
|
||||
enum VideoFacingModeEnum {
|
||||
"user",
|
||||
"environment",
|
||||
"left",
|
||||
"right"
|
||||
};
|
||||
|
||||
enum VideoResizeModeEnum {
|
||||
"none",
|
||||
"crop-and-scale"
|
||||
};
|
||||
|
||||
[Exposed=Window,
|
||||
Constructor(DOMString type, MediaStreamTrackEventInit eventInitDict)]
|
||||
interface MediaStreamTrackEvent : Event {
|
||||
[SameObject]
|
||||
readonly attribute MediaStreamTrack track;
|
||||
};
|
||||
|
||||
dictionary MediaStreamTrackEventInit : EventInit {
|
||||
required MediaStreamTrack track;
|
||||
};
|
||||
|
||||
partial interface Navigator {
|
||||
[SameObject, SecureContext]
|
||||
readonly attribute MediaDevices mediaDevices;
|
||||
};
|
||||
|
||||
[Exposed=Window, SecureContext]
|
||||
interface MediaDevices : EventTarget {
|
||||
attribute EventHandler ondevicechange;
|
||||
Promise<sequence<MediaDeviceInfo>> enumerateDevices();
|
||||
};
|
||||
|
||||
[Exposed=Window, SecureContext]
|
||||
interface MediaDeviceInfo {
|
||||
readonly attribute DOMString deviceId;
|
||||
readonly attribute MediaDeviceKind kind;
|
||||
readonly attribute DOMString label;
|
||||
readonly attribute DOMString groupId;
|
||||
[Default] object toJSON();
|
||||
};
|
||||
|
||||
enum MediaDeviceKind {
|
||||
"audioinput",
|
||||
"audiooutput",
|
||||
"videoinput"
|
||||
};
|
||||
|
||||
[Exposed=Window] interface InputDeviceInfo : MediaDeviceInfo {
|
||||
MediaTrackCapabilities getCapabilities();
|
||||
};
|
||||
|
||||
partial interface Navigator {
|
||||
[SecureContext]
|
||||
undefined getUserMedia(MediaStreamConstraints constraints, NavigatorUserMediaSuccessCallback successCallback, NavigatorUserMediaErrorCallback errorCallback);
|
||||
};
|
||||
|
||||
partial interface MediaDevices {
|
||||
MediaTrackSupportedConstraints getSupportedConstraints();
|
||||
Promise<MediaStream> getUserMedia(optional MediaStreamConstraints constraints = {});
|
||||
};
|
||||
|
||||
dictionary MediaStreamConstraints {
|
||||
(boolean or MediaTrackConstraints) video = false;
|
||||
(boolean or MediaTrackConstraints) audio = false;
|
||||
};
|
||||
|
||||
callback NavigatorUserMediaSuccessCallback = undefined (MediaStream stream);
|
||||
|
||||
callback NavigatorUserMediaErrorCallback = undefined (MediaStreamError error);
|
||||
|
||||
typedef object MediaStreamError;
|
||||
|
||||
dictionary DoubleRange {
|
||||
double max;
|
||||
double min;
|
||||
};
|
||||
|
||||
dictionary ConstrainDoubleRange : DoubleRange {
|
||||
double exact;
|
||||
double ideal;
|
||||
};
|
||||
|
||||
dictionary ULongRange {
|
||||
[Clamp] unsigned long max;
|
||||
[Clamp] unsigned long min;
|
||||
};
|
||||
|
||||
dictionary ConstrainULongRange : ULongRange {
|
||||
[Clamp] unsigned long exact;
|
||||
[Clamp] unsigned long ideal;
|
||||
};
|
||||
|
||||
dictionary ConstrainBooleanParameters {
|
||||
boolean exact;
|
||||
boolean ideal;
|
||||
};
|
||||
|
||||
dictionary ConstrainDOMStringParameters {
|
||||
(DOMString or sequence<DOMString>) exact;
|
||||
(DOMString or sequence<DOMString>) ideal;
|
||||
};
|
||||
|
||||
typedef ([Clamp] unsigned long or ConstrainULongRange) ConstrainULong;
|
||||
|
||||
typedef (double or ConstrainDoubleRange) ConstrainDouble;
|
||||
|
||||
typedef (boolean or ConstrainBooleanParameters) ConstrainBoolean;
|
||||
|
||||
typedef (DOMString or sequence<DOMString> or ConstrainDOMStringParameters) ConstrainDOMString;
|
||||
|
||||
dictionary Capabilities {
|
||||
};
|
||||
|
||||
dictionary Settings {
|
||||
};
|
||||
|
||||
dictionary ConstraintSet {
|
||||
};
|
||||
|
||||
dictionary Constraints : ConstraintSet {
|
||||
sequence<ConstraintSet> advanced;
|
||||
};
|
|
@ -0,0 +1,204 @@
|
|||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface ReadableStream {
|
||||
constructor(optional object underlyingSource, optional QueuingStrategy strategy = {});
|
||||
|
||||
readonly attribute boolean locked;
|
||||
|
||||
Promise<undefined> cancel(optional any reason);
|
||||
ReadableStreamReader getReader(optional ReadableStreamGetReaderOptions options = {});
|
||||
ReadableStream pipeThrough(ReadableWritablePair transform, optional StreamPipeOptions options = {});
|
||||
Promise<undefined> pipeTo(WritableStream destination, optional StreamPipeOptions options = {});
|
||||
sequence<ReadableStream> tee();
|
||||
|
||||
async iterable<any>(optional ReadableStreamIteratorOptions options = {});
|
||||
};
|
||||
|
||||
typedef (ReadableStreamDefaultReader or ReadableStreamBYOBReader) ReadableStreamReader;
|
||||
|
||||
enum ReadableStreamReaderMode { "byob" };
|
||||
|
||||
dictionary ReadableStreamGetReaderOptions {
|
||||
ReadableStreamReaderMode mode;
|
||||
};
|
||||
|
||||
dictionary ReadableStreamIteratorOptions {
|
||||
boolean preventCancel = false;
|
||||
};
|
||||
|
||||
dictionary ReadableWritablePair {
|
||||
required ReadableStream readable;
|
||||
required WritableStream writable;
|
||||
};
|
||||
|
||||
dictionary StreamPipeOptions {
|
||||
boolean preventClose = false;
|
||||
boolean preventAbort = false;
|
||||
boolean preventCancel = false;
|
||||
AbortSignal signal;
|
||||
};
|
||||
|
||||
dictionary UnderlyingSource {
|
||||
UnderlyingSourceStartCallback start;
|
||||
UnderlyingSourcePullCallback pull;
|
||||
UnderlyingSourceCancelCallback cancel;
|
||||
ReadableStreamType type;
|
||||
[EnforceRange] unsigned long long autoAllocateChunkSize;
|
||||
};
|
||||
|
||||
typedef (ReadableStreamDefaultController or ReadableByteStreamController) ReadableStreamController;
|
||||
|
||||
callback UnderlyingSourceStartCallback = any (ReadableStreamController controller);
|
||||
callback UnderlyingSourcePullCallback = Promise<undefined> (ReadableStreamController controller);
|
||||
callback UnderlyingSourceCancelCallback = Promise<undefined> (optional any reason);
|
||||
|
||||
enum ReadableStreamType { "bytes" };
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface ReadableStreamDefaultReader {
|
||||
constructor(ReadableStream stream);
|
||||
|
||||
readonly attribute Promise<undefined> closed;
|
||||
|
||||
Promise<undefined> cancel(optional any reason);
|
||||
Promise<any> read();
|
||||
undefined releaseLock();
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface ReadableStreamBYOBReader {
|
||||
constructor(ReadableStream stream);
|
||||
|
||||
readonly attribute Promise<undefined> closed;
|
||||
|
||||
Promise<undefined> cancel(optional any reason);
|
||||
Promise<any> read(ArrayBufferView view);
|
||||
undefined releaseLock();
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface ReadableStreamDefaultController {
|
||||
readonly attribute unrestricted double? desiredSize;
|
||||
|
||||
undefined close();
|
||||
undefined enqueue(optional any chunk);
|
||||
undefined error(optional any e);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface ReadableByteStreamController {
|
||||
readonly attribute ReadableStreamBYOBRequest? byobRequest;
|
||||
readonly attribute unrestricted double? desiredSize;
|
||||
|
||||
undefined close();
|
||||
undefined enqueue(ArrayBufferView chunk);
|
||||
undefined error(optional any e);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface ReadableStreamBYOBRequest {
|
||||
readonly attribute ArrayBufferView? view;
|
||||
|
||||
undefined respond([EnforceRange] unsigned long long bytesWritten);
|
||||
undefined respondWithNewView(ArrayBufferView view);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface WritableStream {
|
||||
constructor(optional object underlyingSink, optional QueuingStrategy strategy = {});
|
||||
|
||||
readonly attribute boolean locked;
|
||||
|
||||
Promise<undefined> abort(optional any reason);
|
||||
Promise<undefined> close();
|
||||
WritableStreamDefaultWriter getWriter();
|
||||
};
|
||||
|
||||
dictionary UnderlyingSink {
|
||||
UnderlyingSinkStartCallback start;
|
||||
UnderlyingSinkWriteCallback write;
|
||||
UnderlyingSinkCloseCallback close;
|
||||
UnderlyingSinkAbortCallback abort;
|
||||
any type;
|
||||
};
|
||||
|
||||
callback UnderlyingSinkStartCallback = any (WritableStreamDefaultController controller);
|
||||
callback UnderlyingSinkWriteCallback = Promise<undefined> (WritableStreamDefaultController controller, optional any chunk);
|
||||
callback UnderlyingSinkCloseCallback = Promise<undefined> ();
|
||||
callback UnderlyingSinkAbortCallback = Promise<undefined> (optional any reason);
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface WritableStreamDefaultWriter {
|
||||
constructor(WritableStream stream);
|
||||
|
||||
readonly attribute Promise<undefined> closed;
|
||||
readonly attribute unrestricted double? desiredSize;
|
||||
readonly attribute Promise<undefined> ready;
|
||||
|
||||
Promise<undefined> abort(optional any reason);
|
||||
Promise<undefined> close();
|
||||
undefined releaseLock();
|
||||
Promise<undefined> write(optional any chunk);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface WritableStreamDefaultController {
|
||||
undefined error(optional any e);
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface TransformStream {
|
||||
constructor(optional object transformer,
|
||||
optional QueuingStrategy writableStrategy = {},
|
||||
optional QueuingStrategy readableStrategy = {});
|
||||
|
||||
readonly attribute ReadableStream readable;
|
||||
readonly attribute WritableStream writable;
|
||||
};
|
||||
|
||||
dictionary Transformer {
|
||||
TransformerStartCallback start;
|
||||
TransformerTransformCallback transform;
|
||||
TransformerFlushCallback flush;
|
||||
any readableType;
|
||||
any writableType;
|
||||
};
|
||||
|
||||
callback TransformerStartCallback = any (TransformStreamDefaultController controller);
|
||||
callback TransformerFlushCallback = Promise<undefined> (TransformStreamDefaultController controller);
|
||||
callback TransformerTransformCallback = Promise<undefined> (TransformStreamDefaultController controller, optional any chunk);
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface TransformStreamDefaultController {
|
||||
readonly attribute unrestricted double? desiredSize;
|
||||
|
||||
undefined enqueue(optional any chunk);
|
||||
undefined error(optional any reason);
|
||||
undefined terminate();
|
||||
};
|
||||
|
||||
dictionary QueuingStrategy {
|
||||
unrestricted double highWaterMark;
|
||||
QueuingStrategySize size;
|
||||
};
|
||||
|
||||
callback QueuingStrategySize = unrestricted double (optional any chunk);
|
||||
|
||||
dictionary QueuingStrategyInit {
|
||||
required unrestricted double highWaterMark;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface ByteLengthQueuingStrategy {
|
||||
constructor(QueuingStrategyInit init);
|
||||
|
||||
readonly attribute unrestricted double highWaterMark;
|
||||
readonly attribute Function size;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,Worklet)]
|
||||
interface CountQueuingStrategy {
|
||||
constructor(QueuingStrategyInit init);
|
||||
|
||||
readonly attribute unrestricted double highWaterMark;
|
||||
readonly attribute Function size;
|
||||
};
|
|
@ -0,0 +1,107 @@
|
|||
extern crate weedle;
|
||||
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
|
||||
use weedle::*;
|
||||
|
||||
fn read_file(path: &str) -> String {
|
||||
let mut file = fs::File::open(path).unwrap();
|
||||
let mut file_content = String::new();
|
||||
file.read_to_string(&mut file_content).unwrap();
|
||||
file_content
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn should_parse_dom_webidl() {
|
||||
let content = read_file("./tests/defs/dom.webidl");
|
||||
let parsed = weedle::parse(&content).unwrap();
|
||||
|
||||
assert_eq!(parsed.len(), 62);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_html_webidl() {
|
||||
let content = read_file("./tests/defs/html.webidl");
|
||||
let parsed = weedle::parse(&content).unwrap();
|
||||
|
||||
assert_eq!(parsed.len(), 325);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_mediacapture_streams_webidl() {
|
||||
let content = read_file("./tests/defs/mediacapture-streams.webidl");
|
||||
let parsed = weedle::parse(&content).unwrap();
|
||||
|
||||
assert_eq!(parsed.len(), 37);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_streams_webidl() {
|
||||
let content = read_file("./tests/defs/streams.webidl");
|
||||
let parsed = weedle::parse(&content).unwrap();
|
||||
|
||||
assert_eq!(parsed.len(), 37);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interface_constructor() {
|
||||
let content = read_file("./tests/defs/interface-constructor.webidl");
|
||||
let mut parsed = weedle::parse(&content).unwrap();
|
||||
|
||||
assert_eq!(parsed.len(), 1);
|
||||
|
||||
let definition = parsed.pop().unwrap();
|
||||
|
||||
match definition {
|
||||
Definition::Interface(mut interface) => {
|
||||
assert!(interface.attributes.is_none());
|
||||
assert_eq!(interface.interface, term!(interface));
|
||||
assert_eq!(interface.identifier.0, "InterfaceWithConstructor");
|
||||
assert_eq!(interface.inheritance, None);
|
||||
|
||||
assert_eq!(interface.members.body.len(), 1);
|
||||
|
||||
let body = interface.members.body.pop().unwrap();
|
||||
|
||||
match body {
|
||||
interface::InterfaceMember::Constructor(constructor) => {
|
||||
let mut attributes = constructor.attributes.unwrap().body.list;
|
||||
assert_eq!(attributes.len(), 1);
|
||||
let attribute = attributes.pop().unwrap();
|
||||
|
||||
match attribute {
|
||||
attribute::ExtendedAttribute::NoArgs(attribute) => {
|
||||
assert_eq!((attribute.0).0, "Throws");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let mut args = constructor.args.body.list;
|
||||
assert_eq!(args.len(), 1);
|
||||
let arg = args.pop().unwrap();
|
||||
|
||||
match arg {
|
||||
argument::Argument::Single(arg) => {
|
||||
assert!(arg.attributes.is_none());
|
||||
assert!(arg.optional.is_none());
|
||||
assert!(arg.type_.attributes.is_none());
|
||||
|
||||
match arg.type_.type_ {
|
||||
types::Type::Single(types::SingleType::NonAny(
|
||||
types::NonAnyType::Integer(_),
|
||||
)) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
assert_eq!(constructor.constructor, term::Constructor);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче