Merge pull request #1223 from badboy/vendored-weedle2

Vendor complete weedle2 codebase into this repository
This commit is contained in:
Jan-Erik Rediger 2022-04-28 11:10:51 +02:00 коммит произвёл GitHub
Родитель 9a3c6509f1 87e99b8f89
Коммит 4006fcb041
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
26 изменённых файлов: 6822 добавлений и 1 удалений

Просмотреть файл

@ -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"

6
weedle2/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,6 @@
/target
**/*.rs.bk
Cargo.lock
.idea/
*.iml

6
weedle2/.travis.yml Normal file
Просмотреть файл

@ -0,0 +1,6 @@
language: rust
rust:
stable
cache: cargo
script:
- cargo test

17
weedle2/Cargo.toml Normal file
Просмотреть файл

@ -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"] }

15
weedle2/LICENSE.md Normal file
Просмотреть файл

@ -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.

46
weedle2/README.md Normal file
Просмотреть файл

@ -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);
}
```

76
weedle2/src/argument.rs Normal file
Просмотреть файл

@ -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"))),
});
});
}

99
weedle2/src/attribute.rs Normal file
Просмотреть файл

@ -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;
});
}

208
weedle2/src/common.rs Normal file
Просмотреть файл

@ -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";
});
}

33
weedle2/src/dictionary.rs Normal file
Просмотреть файл

@ -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();
});
}

249
weedle2/src/interface.rs Normal file
Просмотреть файл

@ -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";
});
}

425
weedle2/src/lib.rs Normal file
Просмотреть файл

@ -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;
});
}

281
weedle2/src/literal.rs Normal file
Просмотреть файл

@ -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)
});
}

614
weedle2/src/macros.rs Normal file
Просмотреть файл

@ -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"); }
}
}
}
)*
}
};
}

60
weedle2/src/mixin.rs Normal file
Просмотреть файл

@ -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();
});
}

52
weedle2/src/namespace.rs Normal file
Просмотреть файл

@ -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();
});
}

697
weedle2/src/term.rs Normal file
Просмотреть файл

@ -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";
];
}

385
weedle2/src/types.rs Normal file
Просмотреть файл

@ -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");
}
}
}
}

31
weedle2/src/whitespace.rs Normal file
Просмотреть файл

@ -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;
};

107
weedle2/tests/webidl.rs Normal file
Просмотреть файл

@ -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!(),
}
}