1use std::collections::{BTreeSet, BTreeMap};
2use std::path::Path;
3use std::fs::File;
4use std::rc::Rc;
5use std::cell::RefCell;
6use std::io::prelude::*;
7use escape::escape;
8use inflector::cases::{classcase, pascalcase, snakecase};
9use pest::Parser;
10use pest::iterators::Pairs;
11use quote::__private::TokenStream;
12use quote::*;
13use crate::errors::*;
14use crate::slice::module::Module;
15use crate::slice::enumeration::Enum;
16use crate::slice::structure::Struct;
17use crate::slice::interface::Interface;
18use crate::slice::function::Function;
19use crate::slice::exception::Exception;
20use crate::slice::class::Class;
21use crate::slice::types::IceType;
22
23use super::{escape, function_argument::FunctionArgument, function_return::FunctionReturn, function_throws::FunctionThrows, struct_member::StructMember};
24
25
26#[derive(Parser)]
27#[grammar = "slice/ice.pest"]
28pub struct IceParser;
29
30pub trait ParsedObject {
31 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized;
32}
33
34pub trait ParsedModule {
35 fn parse(&mut self, rule: &mut Pairs<Rule>) -> Result<(), Box<dyn std::error::Error>> where Self: Sized;
36}
37
38
39impl ParsedModule for Module {
40 fn parse(&mut self, rule: &mut Pairs<Rule>) -> Result<(), Box<dyn std::error::Error>> where Self: Sized {
41 let it = rule.next().ok_or(
42 Box::new(ParsingError::new("No more items"))
43 )?;
44 if it.as_rule() != Rule::keyword_module {
45 return Err(Box::new(ParsingError::new(
46 &format!("Expected keyword module but found {:?}", it.as_rule())
47 )));
48 }
49 let it = rule.next().ok_or(
50 Box::new(ParsingError::new("No more items"))
51 )?;
52 if it.as_rule() != Rule::identifier {
53 return Err(Box::new(ParsingError::new(
54 &format!("Expected identifier but found {:?}", it.as_rule())
55 )));
56 }
57 let name = it.as_str();
58 let module = match self.sub_modules.iter_mut().find(|f| f.name == name) {
59 Some(module) => {
60 module
61 }
62 None => {
63 let mut new_module = Module::new(Rc::clone(&self.type_map));
64 new_module.name = String::from(name);
65 new_module.full_name = format!("{}::{}", self.full_name, new_module.name);
66 self.sub_modules.push(new_module);
67 self.sub_modules.last_mut().ok_or(
68 Box::new(ParsingError::new("Unexpected. No module found."))
69 )?
70 }
71 };
72
73 for child in rule {
74 match child.as_rule() {
75 Rule::block_open => {},
76 Rule::any_block => {
77 for block in child.into_inner() {
78 match block.as_rule() {
79 Rule::module_block => {
80 module.parse(&mut block.into_inner())?;
81 },
82 Rule::enum_block => {
83 let enumeration = Enum::parse(block.into_inner())?;
84 self.type_map.borrow_mut().insert(enumeration.id.to_string(), module.snake_name());
85 module.add_enum(enumeration);
86 },
87 Rule::struct_block => {
88 let structure = Struct::parse(block.into_inner())?;
89 self.type_map.borrow_mut().insert(structure.id.to_string(), module.snake_name());
90 module.add_struct(structure);
91 },
92 Rule::class_block => {
93 let class = Class::parse(block.into_inner())?;
94 self.type_map.borrow_mut().insert(class.id.to_string(), module.snake_name());
95 module.add_class(class);
96 },
97 Rule::interface_block => {
98 let interface = Interface::parse(block.into_inner())?;
99 module.add_interface(interface);
100 },
101 Rule::exception_block => {
102 let exception = Exception::parse(block.into_inner())?;
103 self.type_map.borrow_mut().insert(exception.id.to_string(), module.snake_name());
104 module.add_exception(exception);
105 }
106 _ => return Err(Box::new(ParsingError::new(
107 &format!("Unexpected rule {:?}", block.as_rule())
108 )))
109 }
110 }
111 },
112 Rule::typedef => {
113 let mut vartype = IceType::VoidType;
114 let mut id = "";
115 for item in child.into_inner() {
116 match item.as_rule() {
117 Rule::typename => { vartype = IceType::from(&escape::escape(item.as_str()))? },
118 Rule::identifier => { id = item.as_str(); },
119 Rule::typedef_end => {
120 self.type_map.borrow_mut().insert(String::from(id), module.snake_name());
121 module.add_typedef(id, vartype.clone());
122 },
123 _ => return Err(Box::new(ParsingError::new(
124 &format!("Unexpected rule {:?}", item.as_rule())
125 )))
126 }
127 }
128 }
129 Rule::block_close => {},
130 _ => return Err(Box::new(ParsingError::new(
131 &format!("Unexpected rule {:?}", child.as_rule())
132 )))
133 };
134 }
135 Ok(())
136 }
137}
138
139impl ParsedObject for Enum {
140 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
141 let mut enumeration = Enum::empty();
142 for child in rule {
143 match child.as_rule() {
144 Rule::keyword_enum => {},
145 Rule::identifier => {
146 enumeration.ice_id = String::from(child.as_str());
147 let id_str = format_ident!("{}", classcase::to_class_case(&enumeration.ice_id));
148 enumeration.id = quote! { #id_str };
149 },
150 Rule::block_open => {},
151 Rule::enum_lines => {
152 for line in child.into_inner() {
153 match line.as_rule() {
154 Rule::enum_line => {
156 let mut id = "";
157 let mut value: Option<i32> = None;
158 for item in line.into_inner() {
159 match item.as_rule() {
160 Rule::identifier => {
161 id = item.as_str();
162 },
163 Rule::numeric_value => {
164 value = Some(item.as_str().parse()?);
165 },
166 _ => return Err(Box::new(ParsingError::new(
167 &format!("Unexpected rule {:?}", item.as_rule())
168 )))
169 };
170 }
171 enumeration.add_variant(id, value);
172 },
173 _ => return Err(Box::new(ParsingError::new(
174 &format!("Unexpected rule {:?}", line.as_rule())
175 )))
176 }
177 }
178 },
179 Rule::block_close => {},
180 _ => return Err(Box::new(ParsingError::new(
181 &format!("Unexpected rule {:?}", child.as_rule())
182 )))
183 }
184 }
185
186 Ok(enumeration)
187 }
188}
189
190impl ParsedObject for StructMember {
191 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
192 let mut member = StructMember::empty();
193 let mut optional = false;
194 let mut optional_tag = 0;
195 for child in rule {
196 match child.as_rule() {
197 Rule::keyword_optional => {
198 optional = true;
199 for line in child.into_inner() {
200 match line.as_rule() {
201 Rule::optional_tag => {
202 optional_tag = line.as_str().parse()?;
203 }
204 _ => return Err(Box::new(ParsingError::new(
205 &format!("Unexpected rule {:?}", line.as_rule())
206 )))
207 }
208 }
209 },
210 Rule::typename => {
211 if optional {
212 member.r#type = IceType::Optional(Box::new(IceType::from(child.as_str())?), optional_tag);
213 } else {
214 member.r#type = IceType::from(child.as_str())?;
215 }
216 },
217 Rule::identifier => {
218 member.ice_id = String::from(child.as_str());
219 let id_str = format_ident!("{}", escape::escape(&snakecase::to_snake_case(&member.ice_id)));
220 member.id = quote! { #id_str };
221 },
222 Rule::struct_line_default | Rule::class_line_default => {
223 }
225 Rule::struct_line_end => {
226 },
227 Rule::class_line_end => {
228 },
229 _ => return Err(Box::new(ParsingError::new(
230 &format!("Unexpected rule {:?}", child.as_rule())
231 )))
232 }
233 }
234 Ok(member)
235 }
236}
237
238impl ParsedObject for Struct {
239 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
240 let mut structure = Struct::empty();
241 for child in rule {
242 match child.as_rule() {
243 Rule::keyword_struct => {},
244 Rule::identifier => {
245 structure.ice_id = String::from(child.as_str());
246 let id_str = format_ident!("{}", classcase::to_class_case(&structure.ice_id));
247 structure.id = quote! { #id_str };
248 },
249 Rule::block_open => {},
250
251 Rule::struct_line => {
252 let member = StructMember::parse(child.into_inner())?;
253 structure.add_member(member);
254 },
255 Rule::block_close => {},
256 _ => return Err(Box::new(ParsingError::new(
257 &format!("Unexpected rule {:?}", child.as_rule())
258 )))
259 }
260 }
261
262 Ok(structure)
263 }
264}
265
266impl ParsedObject for Class {
267 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
268 let mut class = Class::empty();
269 for child in rule {
270 match child.as_rule() {
271 Rule::keyword_class => {},
272 Rule::identifier => {
273 class.ice_id = String::from(child.as_str());
274 let id_str = format_ident!("{}", classcase::to_class_case(&class.ice_id));
275 class.id = quote! { #id_str };
276 },
277 Rule::extends => {
278 for line in child.into_inner() {
279 match line.as_rule() {
280 Rule::keyword_extends => { },
281 Rule::identifier => {
282 class.extends = Some(IceType::from(line.as_str())?);
283 },
284 _ => return Err(Box::new(ParsingError::new(
285 &format!("Unexpected rule {:?}", line.as_rule())
286 )))
287 }
288 }
289 }
290 Rule::block_open => {},
291 Rule::class_line => {
292 let member = StructMember::parse(child.into_inner())?;
293 class.add_member(member);
294 },
295 Rule::block_close => {},
296 _ => return Err(Box::new(ParsingError::new(
297 &format!("Unexpected rule {:?}", child.as_rule())
298 )))
299 }
300 }
301
302 Ok(class)
303 }
304}
305
306impl ParsedObject for Interface {
307 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
308 let mut interface = Interface::empty();
309 for child in rule {
310 match child.as_rule() {
311 Rule::keyword_interface => {},
312 Rule::identifier => {
313 interface.ice_id = String::from(child.as_str());
314 let id_str = format_ident!("{}", classcase::to_class_case(&interface.ice_id));
315 interface.id = quote! { #id_str };
316 },
317 Rule::block_open => {},
318 Rule::function => {
319 interface.add_function(Function::parse(child.into_inner())?);
320 },
321 Rule::block_close => {},
322 _ => return Err(Box::new(ParsingError::new(
323 &format!("Unexpected rule {:?}", child.as_rule())
324 )))
325 }
326 }
327 Ok(interface)
328 }
329}
330
331impl ParsedObject for Function {
332 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
333 let mut function = Function::empty();
334 for child in rule {
335 match child.as_rule() {
336 Rule::keyword_idempotent => {
337 function.set_idempotent();
338 }
339 Rule::fn_return_proxy => {
340 function.return_type.set_proxy();
341 }
342 Rule::fn_return => {
343 function.return_type = FunctionReturn::parse(child.into_inner())?;
344 },
345 Rule::fn_name => {
346 function.ice_id = String::from(child.as_str());
347 let id_str = format_ident!("{}", snakecase::to_snake_case(&function.ice_id));
348 function.id = quote! { #id_str };
349
350 },
351 Rule::fn_arg_open => {},
352 Rule::fn_arg_list => {
353 for arg in child.into_inner() {
354 match arg.as_rule() {
355 Rule::fn_arg | Rule::fn_arg_out => {
356 let arg = FunctionArgument::parse(arg.into_inner())?;
357 function.add_argument(arg);
358 }
359 _ => return Err(Box::new(ParsingError::new(
360 &format!("Unexpected rule {:?}", arg.as_rule())
361 )))
362 }
363 }
364 },
365 Rule::fn_arg_close => {},
366 Rule::fn_throws => {
367 function.throws = FunctionThrows::parse(child.into_inner())?;
368 }
369 _ => return Err(Box::new(ParsingError::new(
370 &format!("Unexpected rule {:?}", child.as_rule())
371 )))
372 }
373 }
374 Ok(function)
375 }
376}
377
378impl ParsedObject for FunctionThrows {
379 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
380 for child in rule {
381 match child.as_rule() {
382 Rule::keyword_throws => {}
383 Rule::identifier => {
384 return Ok(FunctionThrows::new(IceType::from(child.as_str())?));
385 }
386 _ => { }
387 }
388 }
389 return Err(Box::new(ParsingError::new(
390 &format!("Did not find throw identifier")
391 )))
392 }
393}
394
395impl ParsedObject for FunctionReturn {
396 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
397 let mut return_type = IceType::VoidType;
398 let mut optional = false;
399 let mut optional_tag = 0;
400 for child in rule {
401 match child.as_rule() {
402 Rule::keyword_optional => {
403 optional = true;
404 let tag = child.into_inner().next().ok_or(Box::new(ParsingError::new("No more items")))?;
405
406 if tag.as_rule() != Rule::optional_tag {
407 return Err(Box::new(ParsingError::new(
408 &format!("Expected keyword optional_tag but found {:?}", tag.as_rule())
409 )));
410 }
411 optional_tag = tag.as_str().parse()?;
412 }
413 Rule::identifier => {
414 if optional {
415 return_type = IceType::Optional(Box::new(IceType::from(child.as_str())?), optional_tag);
416 } else {
417 return_type = IceType::from(child.as_str())?;
418 }
419 }
420 _ => return Err(Box::new(ParsingError::new(
421 &format!("Unexpected rule {:?}", child.as_rule())
422 )))
423 }
424 }
425 Ok(FunctionReturn::new(return_type))
426 }
427}
428
429impl ParsedObject for FunctionArgument {
430 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
431 let mut id = TokenStream::new();
432 let mut optional = false;
433 let mut optional_tag = 0;
434 let mut typename = IceType::VoidType;
435 let mut out = false;
436
437 for child in rule {
438 match child.as_rule() {
439 Rule::typename => {
440 if optional {
441 typename = IceType::Optional(Box::new(IceType::from(child.as_str())?), optional_tag);
442 } else {
443 typename = IceType::from(child.as_str())?;
444 }
445 },
446 Rule::identifier => {
447 let id_str = format_ident!("{}", escape(&snakecase::to_snake_case(child.as_str())));
448 id = quote! { #id_str }
449 },
450 Rule::keyword_out => out = true,
451 Rule::keyword_optional => {
452 optional = true;
453 let tag = child.into_inner().next().ok_or(Box::new(ParsingError::new("No more items")))?;
454
455 if tag.as_rule() != Rule::optional_tag {
456 return Err(Box::new(ParsingError::new(
457 &format!("Expected keyword optional_tag but found {:?}", tag.as_rule())
458 )));
459 }
460 optional_tag = tag.as_str().parse()?;
461 }
462 _ => return Err(Box::new(ParsingError::new(
463 &format!("Unexpected rule {:?}", child.as_rule())
464 )))
465 }
466 }
467 Ok(FunctionArgument::new(id, typename, out))
468 }
469}
470
471impl ParsedObject for Exception {
472 fn parse(rule: Pairs<Rule>) -> Result<Self, Box<dyn std::error::Error>> where Self: Sized {
473 let mut exception = Exception::empty();
474 for child in rule {
475 match child.as_rule() {
476 Rule::keyword_exception => {},
477 Rule::identifier => {
478 exception.ice_id = String::from(child.as_str());
479 let id_str = format_ident!("{}", pascalcase::to_pascal_case(&exception.ice_id));
480 exception.id = quote! { #id_str };
481 },
482 Rule::block_open => {},
483 Rule::extends => {
484 for line in child.into_inner() {
485 match line.as_rule() {
486 Rule::keyword_extends => { },
487 Rule::identifier => {
488 exception.extends = Some(IceType::from(line.as_str())?);
489 },
490 _ => return Err(Box::new(ParsingError::new(
491 &format!("Unexpected rule {:?}", line.as_rule())
492 )))
493 }
494 }
495 }
496 Rule::struct_line => {
497 let member = StructMember::parse(child.into_inner())?;
498 exception.add_member(member);
499 },
500 Rule::block_close => {},
501 _ => return Err(Box::new(ParsingError::new(
502 &format!("Unexpected rule {:?}", child.as_rule())
503 )))
504 }
505 }
506
507 Ok(exception)
508 }
509}
510
511impl Module {
512 fn parse_file(&mut self, file: &mut File, include_dir: &Path, parsed_files: &mut BTreeSet<String>) -> Result<(), Box<dyn std::error::Error>> {
513 let mut content = String::new();
514 file.read_to_string(&mut content)?;
515
516 let pairs = IceParser::parse(Rule::ice, &content).unwrap();
517 for pair in pairs {
518 match pair.as_rule() {
519 Rule::ice => {
520 for child in pair.into_inner() {
521 match child.as_rule() {
522 Rule::file_include => {
523 for item in child.into_inner() {
524 match item.as_rule() {
525 Rule::keyword_include => {},
526 Rule::identifier => {
527 let include = include_dir.join(format!("{}.ice", item.as_str()));
528 let include_str = String::from(include_dir.join(format!("{}.ice", item.as_str())).to_str().unwrap());
529 println!(" parsing include {} ... ", include_str);
530 if parsed_files.contains(&include_str) {
531 println!(" skip file!");
532 } else {
533 parsed_files.insert(include_str);
534 let mut include_file = File::open(include)?;
535 self.parse_file(&mut include_file, include_dir, parsed_files)?;
536 println!(" finished include");
537 }
538 }
539 _ => return Err(Box::new(ParsingError::new(
540 &format!("Unexpected rule {:?}", item.as_rule())
541 )))
542 }
543 }
544 }
545 Rule::module_block => {
546 self.parse(&mut child.into_inner())?;
547 },
548 Rule::EOI => {
549 return Ok(())
550 },
551 _ => return Err(Box::new(ParsingError::new(
552 &format!("Unexpected rule {:?}", child.as_rule())
553 )))
554 }
555 }
556 },
557 _ => return Err(Box::new(ParsingError::new(
558 &format!("Unexpected rule {:?}", pair.as_rule())
559 )))
560 };
561 }
562
563 Err(Box::new(ParsingError::new("Unexpected error while parsing")))
564 }
565}
566
567pub fn parse_ice_files(ice_files: &Vec<String>, include_dir: &str) -> Result<Module, Box<dyn std::error::Error>> {
568 let mut parsed_files = BTreeSet::new();
569 let mut root = Module::new(Rc::new(RefCell::new(BTreeMap::new())));
570 for item in ice_files {
571 println!("parsing {} ... ", item);
572 if parsed_files.contains(item) {
573 println!("skip file!");
574 } else {
575 parsed_files.insert(item.clone());
576 let mut file = File::open(Path::new(&item))?;
577 root.parse_file(&mut file, Path::new(include_dir), &mut parsed_files)?;
578 println!("finished parsing!");
579 }
580 }
581
582 Ok(root)
583}
584
585
586#[cfg(test)]
587mod test {
588 use super::*;
589
590 #[test]
591 fn test_function() {
592 assert!(IceParser::parse(Rule::function, "void test();").is_ok());
593 assert!(IceParser::parse(Rule::function, "long test();").is_ok());
594 assert!(IceParser::parse(Rule::function, "long test(long width);").is_ok());
595 assert!(IceParser::parse(Rule::function, "long test(long width, long height);").is_ok());
596 assert!(IceParser::parse(Rule::function, "long test(long radius, out long area);").is_ok());
597 assert!(IceParser::parse(Rule::function, "long test(out long area);").is_ok());
598 assert!(IceParser::parse(Rule::function, "long test(out long area) throws exception;").is_ok());
599
600 assert!(IceParser::parse(Rule::function, "123abc test();").is_err());
601 assert!(IceParser::parse(Rule::function, "void 123abc();").is_err());
602 assert!(IceParser::parse(Rule::function, "void test(123abc width);").is_err());
603 assert!(IceParser::parse(Rule::function, "void test(long 123abc);").is_err());
604 assert!(IceParser::parse(Rule::function, "void test(long width height);").is_err());
605 assert!(IceParser::parse(Rule::function, "void test(out 123abc height);").is_err());
606 assert!(IceParser::parse(Rule::function, "void test(out long 123abc);").is_err());
607 assert!(IceParser::parse(Rule::function, "void test(out long result, long input);").is_err());
608 }
609
610 #[test]
611 fn test_module_block() {
612 assert!(IceParser::parse(Rule::ice, "#pragma once\nmodule Test { }").is_ok());
613
614 assert!(IceParser::parse(Rule::module_block, "module Test { }").is_ok());
615 assert!(IceParser::parse(Rule::module_block, "module Test { module Test2 {} }").is_ok());
616 assert!(IceParser::parse(Rule::module_block, "module Test { enum Test2 { First } }").is_ok());
617 assert!(IceParser::parse(Rule::module_block, "module Test { struct Test2 { long width; } }").is_ok());
618 assert!(IceParser::parse(Rule::module_block, "module Test { interface Test2 { void test(); } }").is_ok());
619
620 assert!(IceParser::parse(Rule::module_block, "module {}").is_err());
621 assert!(IceParser::parse(Rule::module_block, "struct Test {}").is_err());
622 assert!(IceParser::parse(Rule::module_block, "interface Test {}").is_err());
623 assert!(IceParser::parse(Rule::module_block, "enum Test {}").is_err());
624 assert!(IceParser::parse(Rule::module_block, "module 12Test {}").is_err());
625 }
626
627 #[test]
628 fn test_enum_block() {
629 assert!(IceParser::parse(Rule::enum_lines, "First = 0").is_ok());
630 assert!(IceParser::parse(Rule::enum_lines, "First = 0, Second = 1").is_ok());
631 assert!(IceParser::parse(Rule::enum_lines, "First").is_ok());
632 assert!(IceParser::parse(Rule::enum_lines, "First, Second").is_ok());
633
634 assert!(IceParser::parse(Rule::enum_block, "enum Test { First = 0 }").is_ok());
635 assert!(IceParser::parse(Rule::enum_block, "enum Test { First }").is_ok());
636 assert!(IceParser::parse(Rule::enum_block, "enum Test { First = 0, Second = 1 }").is_ok());
637 assert!(IceParser::parse(Rule::enum_block, "enum Test { First, Second }").is_ok());
638
639 assert!(IceParser::parse(Rule::enum_block, "struct Test {}").is_err());
640 assert!(IceParser::parse(Rule::enum_block, "interface Test {}").is_err());
641 assert!(IceParser::parse(Rule::enum_block, "module Test {}").is_err());
642 assert!(IceParser::parse(Rule::enum_block, "enum 12Test {}").is_err());
643 assert!(IceParser::parse(Rule::enum_block, "enum Test { 123abc }").is_err());
644 assert!(IceParser::parse(Rule::enum_block, "enum Test { 123abc = 1 }").is_err());
645 assert!(IceParser::parse(Rule::enum_block, "enum Test { First = X }").is_err());
646 }
647
648 #[test]
649 fn test_struct_block() {
650 assert!(IceParser::parse(Rule::struct_block, "struct Test { long width; }").is_ok());
651 assert!(IceParser::parse(Rule::struct_block, "struct Test { long width; long height; }").is_ok());
652
653 assert!(IceParser::parse(Rule::struct_block, "struct Test { long width }").is_err());
654 assert!(IceParser::parse(Rule::struct_block, "struct Test { }").is_err());
655 assert!(IceParser::parse(Rule::struct_block, "enum Test {}").is_err());
656 assert!(IceParser::parse(Rule::struct_block, "inteface Test {}").is_err());
657 assert!(IceParser::parse(Rule::struct_block, "module Test {}").is_err());
658 assert!(IceParser::parse(Rule::struct_block, "struct 12Test {}").is_err());
659 assert!(IceParser::parse(Rule::struct_block, "struct Test { 12long width; }").is_err());
660 assert!(IceParser::parse(Rule::struct_block, "struct Test { long 12width; }").is_err());
661 assert!(IceParser::parse(Rule::struct_block, "struct Test { struct Test2 { } }").is_err());
662 }
663
664 #[test]
665 fn test_interface_block() {
666 assert!(IceParser::parse(Rule::interface_block, "interface Test { void test(); }").is_ok());
667 assert!(IceParser::parse(Rule::interface_block, "interface Test { void test(long width); }").is_ok());
668 assert!(IceParser::parse(Rule::interface_block, "interface Test { void test(long width, long height); }").is_ok());
669
670 assert!(IceParser::parse(Rule::interface_block, "interface Test { void 12test(); }").is_err());
671 assert!(IceParser::parse(Rule::interface_block, "interface Test { test(); }").is_err());
672 assert!(IceParser::parse(Rule::interface_block, "interface Test { void test(long 12width); }").is_err());
673 assert!(IceParser::parse(Rule::interface_block, "enum Test {}").is_err());
674 assert!(IceParser::parse(Rule::interface_block, "struct Test {}").is_err());
675 assert!(IceParser::parse(Rule::interface_block, "module Test {}").is_err());
676 }
677}