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}