1use self::argument::ArgumentList;
25use self::attribute::ExtendedAttributeList;
26use self::common::{Braced, Identifier, Parenthesized, PunctuatedNonEmpty};
27use self::dictionary::DictionaryMembers;
28use self::interface::{Inheritance, InterfaceMembers};
29use self::literal::StringLit;
30use self::mixin::MixinMembers;
31use self::namespace::NamespaceMembers;
32use self::types::{AttributedType, ReturnType};
33pub use nom::{error::Error, Err, IResult};
34
35#[macro_use]
36mod macros;
37#[macro_use]
38mod whitespace;
39#[macro_use]
40pub mod term;
41pub mod argument;
42pub mod attribute;
43pub mod common;
44pub mod dictionary;
45pub mod interface;
46pub mod literal;
47pub mod mixin;
48pub mod namespace;
49pub mod types;
50
51pub fn parse(raw: &str) -> Result<Definitions<'_>, Err<Error<&str>>> {
67    let (remaining, parsed) = Definitions::parse(raw)?;
68
69    #[cfg(debug_assertions)]
70    assert!(
71        remaining.is_empty(),
72        "There is redundant raw data after parsing `{remaining}`"
73    );
74    #[cfg(not(debug_assertions))]
75    assert!(
76        remaining.is_empty(),
77        "There is redundant raw data after parsing"
78    );
79
80    Ok(parsed)
81}
82
83pub trait Parse<'a>: Sized {
84    fn parse(input: &'a str) -> IResult<&'a str, Self>;
85}
86
87pub type Definitions<'a> = Vec<Definition<'a>>;
104
105ast_types! {
106    enum Definition<'a> {
108        Callback(struct CallbackDefinition<'a> {
110            attributes: Option<ExtendedAttributeList<'a>>,
111            callback: term!(callback),
112            identifier: Identifier<'a>,
113            assign: term!(=),
114            return_type: ReturnType<'a>,
115            arguments: Parenthesized<ArgumentList<'a>>,
116            semi_colon: term!(;),
117        }),
118        CallbackInterface(struct CallbackInterfaceDefinition<'a> {
120            attributes: Option<ExtendedAttributeList<'a>>,
121            callback: term!(callback),
122            interface: term!(interface),
123            identifier: Identifier<'a>,
124            inheritance: Option<Inheritance<'a>>,
125            members: Braced<InterfaceMembers<'a>>,
126            semi_colon: term!(;),
127        }),
128        Interface(struct InterfaceDefinition<'a> {
130            attributes: Option<ExtendedAttributeList<'a>>,
131            interface: term!(interface),
132            identifier: Identifier<'a>,
133            inheritance: Option<Inheritance<'a>>,
134            members: Braced<InterfaceMembers<'a>>,
135            semi_colon: term!(;),
136        }),
137        InterfaceMixin(struct InterfaceMixinDefinition<'a> {
139            attributes: Option<ExtendedAttributeList<'a>>,
140            interface: term!(interface),
141            mixin: term!(mixin),
142            identifier: Identifier<'a>,
143            members: Braced<MixinMembers<'a>>,
144            semi_colon: term!(;),
145        }),
146        Namespace(struct NamespaceDefinition<'a> {
148            attributes: Option<ExtendedAttributeList<'a>>,
149            namespace: term!(namespace),
150            identifier: Identifier<'a>,
151            members: Braced<NamespaceMembers<'a>>,
152            semi_colon: term!(;),
153        }),
154        Dictionary(struct DictionaryDefinition<'a> {
156            attributes: Option<ExtendedAttributeList<'a>>,
157            dictionary: term!(dictionary),
158            identifier: Identifier<'a>,
159            inheritance: Option<Inheritance<'a>>,
160            members: Braced<DictionaryMembers<'a>>,
161            semi_colon: term!(;),
162        }),
163        PartialInterface(struct PartialInterfaceDefinition<'a> {
165            attributes: Option<ExtendedAttributeList<'a>>,
166            partial: term!(partial),
167            interface: term!(interface),
168            identifier: Identifier<'a>,
169            members: Braced<InterfaceMembers<'a>>,
170            semi_colon: term!(;),
171        }),
172        PartialInterfaceMixin(struct PartialInterfaceMixinDefinition<'a> {
174            attributes: Option<ExtendedAttributeList<'a>>,
175            partial: term!(partial),
176            interface: term!(interface),
177            mixin: term!(mixin),
178            identifier: Identifier<'a>,
179            members: Braced<MixinMembers<'a>>,
180            semi_colon: term!(;),
181        }),
182        PartialDictionary(struct PartialDictionaryDefinition<'a> {
184            attributes: Option<ExtendedAttributeList<'a>>,
185            partial: term!(partial),
186            dictionary: term!(dictionary),
187            identifier: Identifier<'a>,
188            members: Braced<DictionaryMembers<'a>>,
189            semi_colon: term!(;),
190        }),
191        PartialNamespace(struct PartialNamespaceDefinition<'a> {
193            attributes: Option<ExtendedAttributeList<'a>>,
194            partial: term!(partial),
195            namespace: term!(namespace),
196            identifier: Identifier<'a>,
197            members: Braced<NamespaceMembers<'a>>,
198            semi_colon: term!(;),
199        }),
200        Enum(struct EnumDefinition<'a> {
202            attributes: Option<ExtendedAttributeList<'a>>,
203            enum_: term!(enum),
204            identifier: Identifier<'a>,
205            values: Braced<EnumValueList<'a>>,
206            semi_colon: term!(;),
207        }),
208        Typedef(struct TypedefDefinition<'a> {
210            attributes: Option<ExtendedAttributeList<'a>>,
211            typedef: term!(typedef),
212            type_: AttributedType<'a>,
213            identifier: Identifier<'a>,
214            semi_colon: term!(;),
215        }),
216        IncludesStatement(struct IncludesStatementDefinition<'a> {
218            attributes: Option<ExtendedAttributeList<'a>>,
219            lhs_identifier: Identifier<'a>,
220            includes: term!(includes),
221            rhs_identifier: Identifier<'a>,
222            semi_colon: term!(;),
223        }),
224        Implements(struct ImplementsDefinition<'a> {
226            attributes: Option<ExtendedAttributeList<'a>>,
227            lhs_identifier: Identifier<'a>,
228            includes: term!(implements),
229            rhs_identifier: Identifier<'a>,
230            semi_colon: term!(;),
231        }),
232    }
233}
234
235pub type EnumValueList<'a> = PunctuatedNonEmpty<StringLit<'a>, term!(,)>;
237
238#[cfg(test)]
239mod test {
240    use super::*;
241
242    test!(should_parse_includes_statement { "first includes second;" =>
243        "";
244        IncludesStatementDefinition;
245        attributes.is_none();
246        lhs_identifier.0 == "first";
247        rhs_identifier.0 == "second";
248    });
249
250    test!(should_parse_typedef { "typedef short Short;" =>
251        "";
252        TypedefDefinition;
253        attributes.is_none();
254        identifier.0 == "Short";
255    });
256
257    test!(should_parse_enum { r#"enum name { "first", "second" }; "# =>
258        "";
259        EnumDefinition;
260        attributes.is_none();
261        identifier.0 == "name";
262        values.body.list.len() == 2;
263    });
264
265    test!(should_parse_dictionary { "dictionary A { long c; long g; };" =>
266        "";
267        DictionaryDefinition;
268        attributes.is_none();
269        identifier.0 == "A";
270        inheritance.is_none();
271        members.body.len() == 2;
272    });
273
274    test!(should_parse_dictionary_inherited { "dictionary C : B { long e; long f; };" =>
275        "";
276        DictionaryDefinition;
277        attributes.is_none();
278        identifier.0 == "C";
279        inheritance.is_some();
280        members.body.len() == 2;
281    });
282
283    test!(should_parse_partial_namespace { "
284        partial namespace VectorUtils {
285            readonly attribute Vector unit;
286            double dotProduct(Vector x, Vector y);
287            Vector crossProduct(Vector x, Vector y);
288        };
289    " =>
290        "";
291        PartialNamespaceDefinition;
292        attributes.is_none();
293        identifier.0 == "VectorUtils";
294        members.body.len() == 3;
295    });
296
297    test!(should_parse_partial_dictionary { "partial dictionary C { long e; long f; };" =>
298        "";
299        PartialDictionaryDefinition;
300        attributes.is_none();
301        identifier.0 == "C";
302        members.body.len() == 2;
303    });
304
305    test!(should_parse_partial_interface_mixin { "
306        partial interface mixin WindowSessionStorage {
307          readonly attribute Storage sessionStorage;
308        };
309    " =>
310        "";
311        PartialInterfaceMixinDefinition;
312        attributes.is_none();
313        identifier.0 == "WindowSessionStorage";
314        members.body.len() == 1;
315    });
316
317    test!(should_parse_partial_interface { "
318        partial interface Window {
319          readonly attribute Storage sessionStorage;
320        };
321    " =>
322        "";
323        PartialInterfaceDefinition;
324        attributes.is_none();
325        identifier.0 == "Window";
326        members.body.len() == 1;
327    });
328
329    test!(should_parse_namespace { "
330        namespace VectorUtils {
331          readonly attribute Vector unit;
332          double dotProduct(Vector x, Vector y);
333          Vector crossProduct(Vector x, Vector y);
334        };
335    " =>
336        "";
337        NamespaceDefinition;
338        attributes.is_none();
339        identifier.0 == "VectorUtils";
340        members.body.len() == 3;
341    });
342
343    test!(should_parse_interface_mixin { "
344        interface mixin WindowSessionStorage {
345          readonly attribute Storage sessionStorage;
346        };
347    " =>
348        "";
349        InterfaceMixinDefinition;
350        attributes.is_none();
351        identifier.0 == "WindowSessionStorage";
352        members.body.len() == 1;
353    });
354
355    test!(should_parse_interface { "
356        interface Window {
357          readonly attribute Storage sessionStorage;
358        };
359    " =>
360        "";
361        InterfaceDefinition;
362        attributes.is_none();
363        identifier.0 == "Window";
364        members.body.len() == 1;
365    });
366
367    test!(should_parse_callback_interface {"
368        callback interface Options {
369          attribute DOMString? option1;
370          attribute DOMString? option2;
371          attribute long? option3;
372        };
373    " =>
374        "";
375        CallbackInterfaceDefinition;
376        attributes.is_none();
377        identifier.0 == "Options";
378        members.body.len() == 3;
379    });
380
381    test!(should_parse_callback { "callback AsyncOperationCallback = undefined (DOMString status);" =>
382        "";
383        CallbackDefinition;
384        attributes.is_none();
385        identifier.0 == "AsyncOperationCallback";
386        arguments.body.list.len() == 1;
387    });
388
389    test!(should_parse_with_line_comments { "
390        // This is a comment
391        callback AsyncOperationCallback = undefined (DOMString status);
392    " =>
393        "";
394        CallbackDefinition;
395    });
396
397    test!(should_parse_with_block_comments { "
398        /* This is a comment */
399        callback AsyncOperationCallback = undefined (DOMString status);
400    " =>
401        "";
402        CallbackDefinition;
403    });
404
405    test!(should_parse_with_multiple_comments { "
406        // This is a comment
407        // This is a comment
408        // This is a comment
409
410        // This is a comment
411        callback AsyncOperationCallback = undefined (DOMString status);
412    " =>
413        "";
414        CallbackDefinition;
415    });
416}