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