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