1use crate::ast::types::*;
2use anyhow::{anyhow, Result};
3
4#[cfg(test)]
5use pretty_assertions::assert_eq;
6
7use hexf_parse::parse_hexf64;
8
9use nom::{
10 self, branch::alt, bytes::complete::*, character::complete::*, combinator::*, multi::*,
11 sequence::*, IResult,
12};
13
14use std::{iter::FromIterator, path::Path, str::FromStr};
15
16#[cfg(test)]
17macro_rules! assert_failed_parse {
18 ($left:expr, $rest:expr, $error_kind:ident) => {
19 $crate::ast::parser::assert_eq!(
20 $left,
21 Err(nom::Err::Error(($rest, nom::error::ErrorKind::$error_kind)))
22 )
23 };
24}
25
26#[cfg(test)]
27macro_rules! assert_successful_parse {
28 ($left:expr, $right:expr) => {
29 assert_successful_parse!($left, "", $right)
32 };
33 ($left:expr, $remaining:expr, $right:expr) => {
34 $crate::ast::parser::assert_eq!($left, Ok(($remaining, $right)))
37 };
38}
39
40pub fn plus_or_minus(input: &str) -> IResult<&str, char> {
41 one_of("-+")(input)
42}
43
44#[cfg(test)]
45mod plus_or_minus_tests {
46 use super::plus_or_minus;
47
48 #[test]
49 fn test_plus_or_minus() {
50 assert_successful_parse!(plus_or_minus("+"), '+');
51 assert_successful_parse!(plus_or_minus("-"), '-');
52 }
53
54 #[test]
55 fn test_invalid_plus_or_minus() {
56 assert_failed_parse!(plus_or_minus("/"), "/", OneOf);
57 }
58}
59
60pub fn double_quote(input: &str) -> IResult<&str, char> {
61 char('\"')(input)
62}
63
64pub fn backslash(input: &str) -> IResult<&str, char> {
65 char('\\')(input)
66}
67
68pub fn left_paren(input: &str) -> IResult<&str, char> {
69 char('(')(input)
70}
71
72pub fn right_paren(input: &str) -> IResult<&str, char> {
73 char(')')(input)
74}
75
76pub fn left_brace(input: &str) -> IResult<&str, char> {
77 char('{')(input)
78}
79
80pub fn right_brace(input: &str) -> IResult<&str, char> {
81 char('}')(input)
82}
83
84pub fn colon(input: &str) -> IResult<&str, char> {
85 char(':')(input)
86}
87
88pub fn comma(input: &str) -> IResult<&str, char> {
89 char(',')(input)
90}
91
92pub fn semicolon(input: &str) -> IResult<&str, char> {
93 char(';')(input)
94}
95
96pub fn equals(input: &str) -> IResult<&str, char> {
97 char('=')(input)
98}
99
100pub fn period(input: &str) -> IResult<&str, char> {
101 char('.')(input)
102}
103
104pub fn zero(input: &str) -> IResult<&str, char> {
105 char('0')(input)
106}
107
108pub fn left_square_bracket(input: &str) -> IResult<&str, char> {
109 char('[')(input)
110}
111
112pub fn right_square_bracket(input: &str) -> IResult<&str, char> {
113 char(']')(input)
114}
115
116pub fn ident(input: &str) -> IResult<&str, Ident<'_>> {
117 map(
118 recognize(preceded(
119 take_while_m_n(1, 1, |c: char| c.is_alphabetic() || c == '_'),
120 take_while(|c: char| c.is_alphanumeric() || c == '_'),
121 )),
122 Ident::from,
123 )(input)
124}
125
126#[cfg(test)]
127mod ident_tests {
128 use super::{ident, Ident};
129
130 #[test]
131 fn test_simple_ident() {
132 assert_successful_parse!(ident("foo"), Ident::from("foo"));
133 }
134
135 #[test]
136 fn test_underscore_prefix() {
137 assert_successful_parse!(ident("_foo"), Ident::from("_foo"));
138 }
139
140 #[test]
141 fn test_just_underscore() {
142 assert_successful_parse!(ident("_"), Ident::from("_"));
143 }
144
145 #[test]
146 fn test_id_with_number() {
147 assert_successful_parse!(ident("foo1"), Ident::from("foo1"));
148 }
149
150 #[test]
151 fn test_invalid_ident_contains_valid() {
152 assert_failed_parse!(ident("1foo"), "1foo", TakeWhileMN);
153 }
154
155 #[test]
156 fn test_number_is_invalid() {
157 let result = ident("1");
158 assert_failed_parse!(result, "1", TakeWhileMN)
159 }
160
161 #[test]
162 fn test_empty_ident_is_invalid() {
163 let result = ident("");
164 assert_failed_parse!(result, "", TakeWhileMN)
165 }
166}
167
168pub fn string_constant(input: &str) -> IResult<&str, &str> {
169 map(
170 delimited(
171 double_quote,
172 opt(escaped(
173 none_of("\\\""),
174 '\\',
175 alt((backslash, double_quote)),
176 )),
177 double_quote,
178 ),
179 |string| string.unwrap_or(""),
180 )(input)
181}
182
183#[cfg(test)]
184mod string_constant_tests {
185 use super::string_constant;
186
187 #[test]
188 fn test_string_constant() {
189 let result = string_constant("\"a b c D \\\"z1\"");
190 assert_successful_parse!(result, "a b c D \\\"z1");
191 }
192
193 #[test]
194 fn test_empty_string_constant() {
195 let result = string_constant("\"\"");
196 assert_successful_parse!(result, "");
197 }
198}
199
200pub fn element(input: &str) -> IResult<&str, Element<'_>> {
201 alt((
202 map(namespace_decl, Element::from),
203 map(table_decl, Element::from),
204 map(struct_decl, Element::from),
205 map(enum_decl, Element::from),
206 map(union_decl, Element::from),
207 map(root_decl, Element::from),
208 map(file_extension_decl, Element::from),
209 map(file_identifier_decl, Element::from),
210 map(attribute_decl, Element::from),
211 map(rpc_decl, Element::from),
212 map(object, Element::from),
213 ))(input)
214}
215
216#[cfg(test)]
217mod element_tests {
218 use super::element;
219 use crate::{element as elem, meta, method, rpc};
220
221 #[test]
222 fn test_element_schema() {
223 let input = "\
224rpc_service Greeter {
225 SayHello(HelloRequest):HelloReply;
226 SayManyHellos(ManyHellosRequest):HelloReply (streaming: \"server\");
227}";
228 let result = element(input);
229 let expected = elem!(rpc!(
230 Greeter,
231 [
232 method!(fn SayHello(HelloRequest) -> HelloReply),
233 method!(fn SayManyHellos(ManyHellosRequest) -> HelloReply, [meta!(streaming, "server")])
234 ]
235 ));
236 assert_successful_parse!(result, expected);
237 }
238}
239
240pub fn comment(input: &str) -> IResult<&str, ()> {
242 value((), tuple((tag("//"), not(tag("/")), not_line_ending)))(input)
244}
245
246pub fn comment_or_space(input: &str) -> IResult<&str, ()> {
247 alt((complete(comment), value((), complete(multispace1))))(input)
248}
249
250pub fn comment_or_space0(input: &str) -> IResult<&str, ()> {
251 value((), many0(comment_or_space))(input)
252}
253
254pub fn comment_or_space1(input: &str) -> IResult<&str, ()> {
255 value((), many1(comment_or_space))(input)
256}
257
258pub fn schema_decl(input: &str) -> IResult<&str, Schema<'_>> {
260 map(
261 tuple((
262 many0(delimited(
263 comment_or_space0,
264 include_decl,
265 comment_or_space0,
266 )),
267 many0(delimited(comment_or_space0, element, comment_or_space0)),
268 )),
269 Schema::from,
270 )(input)
271}
272
273#[cfg(test)]
274mod schema_tests {
275 use super::{comment_or_space0, delimited, include_decl, many0, schema_decl, Include, Path};
276 use crate::{field, meta, method, namespace, rpc, schema, table};
277
278 #[test]
279 fn test_simple_include_with_comments() {
280 let input = "//baz\ninclude \"a\"; // bar\n";
281 let parser = many0(delimited(
282 comment_or_space0,
283 include_decl,
284 comment_or_space0,
285 ));
286 let result = parser(input);
287 let expected = vec![Include::builder().path(Path::new("a")).stem("a").build()];
288 assert_successful_parse!(result, expected);
289 }
290
291 #[test]
292 fn test_includes_only_schema() {
293 let input = r#"include "a"; // bar
294 // foo
295include "b";
296
297
298include "foo/bar/baz.fbs";
299
300 "#;
301 let result = schema_decl(input);
302 let expected = schema! {
303 include {
304 "a",
305 "b",
306 "foo/bar/baz.fbs"
307 }
308 };
309 assert_successful_parse!(result, expected);
310 }
311
312 #[test]
313 fn test_elements_only_schema() {
314 let input = "\
315table MyMessage {
316 message: string;
317 foo: float64 = 2.0;
318}";
319 let result = schema_decl(input);
320 let expected = schema! {
321 table!(
322 MyMessage,
323 [field!(message, String), field!(foo, Float64 = 2.0)]
324 )
325 };
326 assert_successful_parse!(result, expected);
327 }
328
329 #[test]
330 fn test_full_schema() {
331 let input = r#"
332
333include "foo/bar/baz.fbs";
334
335table HelloReply {
336 message:string;
337} // bar
338
339// foo!
340
341table HelloRequest {
342 name:string;
343}
344
345table ManyHellosRequest {
346 name:string;
347 num_greetings:int;
348}
349
350namespace foo.bar;
351
352rpc_service Greeter {
353 SayHello(HelloRequest):HelloReply;
354 SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server");
355}
356
357"#;
358 let result = schema_decl(input);
359 let expected = schema! {
360 include {
361 "foo/bar/baz.fbs"
362 },
363 table!(HelloReply, [field!(message, String)]),
364 table!(HelloRequest, [field!(name, String)]),
365 table!(
366 ManyHellosRequest,
367 [field!(name, String), field!(num_greetings, Int)]
368 ),
369 namespace!(foo::bar),
370 rpc!(
371 Greeter,
372 [
373 method!(fn SayHello(HelloRequest) -> HelloReply),
374 method!(
375 fn SayManyHellos(ManyHellosRequest) -> HelloReply,
376 [meta!(streaming, "server")]
377 )
378 ]
379 )
380 };
381 assert_successful_parse!(result, expected);
382 }
383
384 #[test]
385 fn test_schema_with_namespaces() {
386 let input = r#"
387namespace a.b;
388
389table A {
390 message: string;
391}
392
393namespace c;
394
395table C {
396 field1: a.b.A;
397}
398"#;
399 let result = schema_decl(input);
400 let expected = schema! {
401 namespace!(a::b),
402 table!(A, [field!(message, String)]),
403 namespace!(c),
404 table!(C, [field!(field1, a::b::A)])
405 };
406 assert_successful_parse!(result, expected);
407 }
408
409 #[test]
410 fn test_schema_with_namespace() {
411 let input = r#"
412
413namespace baz;
414
415table Hello{
416 message:string;
417 count:uint64; } // bar
418"#;
419 let result = schema_decl(input);
420 let expected = schema! {
421 namespace!(baz),
422 table!(Hello, [field!(message, String), field!(count, UInt64)])
423 };
424 assert_successful_parse!(result, expected);
425 }
426}
427
428pub fn include_decl(input: &str) -> IResult<&str, Include<'_>> {
429 map_res(
430 tuple((
431 doc_comment,
432 delimited(
433 tag("include"),
434 delimited(
435 comment_or_space1,
436 map(string_constant, Path::new),
437 comment_or_space0,
438 ),
439 semicolon,
440 ),
441 )),
442 |(comment, path)| -> Result<Include<'_>> {
443 let stem = path
444 .file_stem()
445 .ok_or_else(|| anyhow!("path has no file stem: {:?}", path))?
446 .to_str()
447 .ok_or_else(|| anyhow!("cannot convert OsStr to str {:?}", path))?;
448 Ok(Include::builder()
449 .doc(comment)
450 .path(path)
451 .stem(stem)
452 .build())
453 },
454 )(input)
455}
456
457#[cfg(test)]
458mod include_tests {
459 use super::{include_decl, Include, Path};
460
461 #[test]
462 fn test_include_decl_with_comments() {
463 let result = include_decl(
464 "include //fizz
465 //buzz\n\t\"foo\"//bzz\n;",
466 );
467 let expected = Include::builder()
468 .path(Path::new("foo"))
469 .stem("foo")
470 .build();
471 assert_successful_parse!(result, expected);
472 }
473
474 #[test]
475 fn test_include_decl() {
476 let result = include_decl("include \"foo\";");
477 let expected = Include::builder()
478 .path(Path::new("foo"))
479 .stem("foo")
480 .build();
481 assert_successful_parse!(result, expected);
482 }
483
484 #[test]
485 fn test_include_decl_prefix_whitespace() {
486 let result = include_decl("include \"foo\";");
487 let expected = Include::builder()
488 .path(Path::new("foo"))
489 .stem("foo")
490 .build();
491 assert_successful_parse!(result, expected);
492 }
493
494 #[test]
495 fn test_include_decl_no_prefix_whitespace() {
496 let result = include_decl("include\"foo\";");
497 assert_failed_parse!(result, "\"foo\";", MultiSpace);
498 }
499
500 #[test]
501 fn test_include_decl_trailing_whitespace() {
502 let result = include_decl("include \"foo\" ;");
503 let expected = Include::builder()
504 .path(Path::new("foo"))
505 .stem("foo")
506 .build();
507 assert_successful_parse!(result, expected);
508 }
509}
510
511pub fn qualified_ident(input: &str) -> IResult<&str, QualifiedIdent<'_>> {
512 map(
513 separated_nonempty_list(
514 delimited(comment_or_space0, tag("."), comment_or_space0),
515 ident,
516 ),
517 QualifiedIdent::from,
518 )(input)
519}
520
521pub fn namespace_decl(input: &str) -> IResult<&str, Namespace<'_>> {
522 map(
523 tuple((
524 doc_comment,
525 delimited(
526 tag("namespace"),
527 delimited(comment_or_space1, qualified_ident, comment_or_space0),
528 semicolon,
529 ),
530 )),
531 |(comment, path)| Namespace::from((path, comment)),
532 )(input)
533}
534
535#[cfg(test)]
536mod namespace_tests {
537 use super::namespace_decl;
538 use crate::namespace;
539
540 #[test]
541 fn test_namespace_decl_with_comments() {
542 let result =
543 namespace_decl("namespace // a namespace comment \na// Yet another one\t\n\n\n;");
544 let expected = namespace!(a);
545 assert_successful_parse!(result, expected);
546 }
547
548 #[test]
549 fn test_namespace_decl_with_doc_comment() {
550 let input = "\
551/// foo
552namespace foo;";
553 let result = namespace_decl(input);
554 let expected = namespace!(foo, [" foo"]);
555 assert_successful_parse!(result, expected);
556 }
557
558 #[test]
559 fn test_namespace_decl_with_doc_and_non_doc_comment() {
560 let input = "\
561/// foo
562// Bar
563namespace foo;";
564 let result = namespace_decl(input);
565 let expected = namespace!(foo, [" foo"]);
566 assert_successful_parse!(result, expected);
567 }
568
569 #[test]
570 fn test_namespace_decl_with_doc_space_and_non_doc_comment() {
571 let input = "\
572/// foo
573//
574// Bar
575
576namespace foo;";
577 let result = namespace_decl(input);
578 let expected = namespace!(foo, [" foo"]);
579 assert_successful_parse!(result, expected);
580 }
581
582 #[test]
583 fn test_one_level_namespace_decl() {
584 let result = namespace_decl("namespace a;");
585 let expected = namespace!(a);
586 assert_successful_parse!(result, expected);
587 }
588
589 #[test]
590 fn test_two_level_namespace_decl() {
591 let result = namespace_decl("namespace a.b;");
592 let expected = namespace!(a::b);
593 assert_successful_parse!(result, expected);
594 }
595
596 #[test]
597 fn test_three_level_namespace_decl() {
598 let result = namespace_decl("namespace a.b.c;");
599 let expected = namespace!(a::b::c);
600 assert_successful_parse!(result, expected);
601 }
602
603 #[test]
604 fn test_three_level_namespace_decl_ws() {
605 let result = namespace_decl("namespace \r\na .b.c\n\t;");
606 let expected = namespace!(a::b::c);
607 assert_successful_parse!(result, expected);
608 }
609}
610
611pub fn attribute_decl(input: &str) -> IResult<&str, Attribute<'_>> {
612 map(
613 tuple((
614 doc_comment,
615 delimited(
616 tag("attribute"),
617 delimited(
618 comment_or_space1,
619 alt((ident, map(string_constant, Ident::from))),
620 comment_or_space0,
621 ),
622 semicolon,
623 ),
624 )),
625 |(_, attr)| Attribute::builder().attr(attr).build(),
626 )(input)
627}
628
629#[cfg(test)]
630mod attribute_tests {
631 use super::attribute_decl;
632 use crate::attr;
633
634 #[test]
635 fn test_simple_attribute_decl_with_comments() {
636 let result = attribute_decl(
637 "attribute// gah, an attr!
638 a;",
639 );
640 let expected = attr!(a);
641 assert_successful_parse!(result, expected);
642 }
643
644 #[test]
645 fn test_attribute_decl_with_doc_comments() {
646 let input = "\
647/// An
648/// Attribute
649// implementation notes
650/// Further comments
651attribute a;";
652 let result = attribute_decl(input);
653 let expected = attr!(a);
656 assert_successful_parse!(result, expected);
657 }
658
659 #[test]
660 fn test_simple_attribute_decl() {
661 let result = attribute_decl("attribute a;");
662 let expected = attr!(a);
663 assert_successful_parse!(result, expected);
664 }
665
666 #[test]
667 fn test_quoted_attribute_decl() {
668 let result = attribute_decl("attribute \"a\";");
669 let expected = attr!(a);
670 assert_successful_parse!(result, expected);
671 }
672
673 #[test]
674 fn test_attribute_decl_ws() {
675 let result = attribute_decl("attribute\t\n\t my_attr\n\n\r\n;");
676 let expected = attr!(my_attr);
677 assert_successful_parse!(result, expected);
678 }
679}
680
681pub fn enum_body(input: &str) -> IResult<&str, Vec<EnumVariant<'_>>> {
682 delimited(
683 delimited(comment_or_space0, left_brace, comment_or_space0),
684 terminated(
685 separated_nonempty_list(
686 delimited(comment_or_space0, comma, comment_or_space0),
687 enumval_decl,
688 ),
689 opt(tuple((comment_or_space0, comma, comment_or_space0))),
690 ),
691 preceded(comment_or_space0, right_brace),
692 )(input)
693}
694
695pub fn enum_decl(input: &str) -> IResult<&str, Enum<'_>> {
696 let parser = tuple((
697 doc_comment,
698 preceded(
699 tag("enum"),
700 delimited(comment_or_space1, ident, comment_or_space0),
701 ),
702 preceded(colon, preceded(comment_or_space0, type_)),
703 metadata,
704 enum_body,
705 ));
706 map(parser, |(comment, name, base_type, metadata, variants)| {
707 Enum::builder()
708 .doc(comment)
709 .id(name)
710 .base_type(base_type)
711 .variants(variants)
712 .metadata(metadata)
713 .build()
714 })(input)
715}
716
717#[cfg(test)]
718mod enum_tests {
719 use super::enum_decl;
720 use crate::{e_item, enum_};
721
722 #[test]
723 fn test_simple_enum_with_comments() {
724 let input = "enum // thing
725 MyEnum //other thing!
726 // jazz?
727: int32 // fiz!
728 { foo // bar
729 = 1, bar //ugh!
730 }";
731 let result = enum_decl(input);
732 let expected = enum_!(MyEnum, Int32, [e_item!(foo = 1), e_item!(bar)]);
733 assert_successful_parse!(result, expected);
734 }
735
736 #[test]
737 fn test_enum_with_doc_comments() {
738 let input = "\
739/// The enum!
740enum MyEnum : int32 {
741 // Not a doc commment
742 /// Maybe it's a foo
743 foo = 1,
744 // Hm,
745 /// Could be a bar though
746 bar,
747
748 // Nope, it's a baz
749 baz = 9,
750}";
751 let result = enum_decl(input);
752 let expected = enum_!(
753 MyEnum,
754 Int32,
755 [
756 e_item!(foo = 1, [" Maybe it's a foo"]),
757 e_item!(bar, [" Could be a bar though"]),
758 e_item!(baz = 9)
759 ],
760 [" The enum!"]
761 );
762 assert_successful_parse!(result, expected);
763 }
764
765 #[test]
766 fn test_simple_enum() {
767 let input = "enum MyEnum : int32 { foo = 1, bar }";
768 let result = enum_decl(input);
769 let expected = enum_!(MyEnum, Int32, [e_item!(foo = 1), e_item!(bar)]);
770 assert_successful_parse!(result, expected);
771 }
772
773 #[test]
775 fn test_simple_enum_with_trailing_comma() {
776 let input = "enum MyEnum : int32 { foo = 1, bar, }";
777 let result = enum_decl(input);
778 let expected = enum_!(MyEnum, Int32, [e_item!(foo = 1), e_item!(bar)]);
779 assert_successful_parse!(result, expected);
780 }
781}
782
783pub fn union_decl(input: &str) -> IResult<&str, Union<'_>> {
784 let parser = tuple((
785 doc_comment,
786 preceded(
787 tag("union"),
788 delimited(comment_or_space1, ident, comment_or_space0),
789 ),
790 metadata,
791 enum_body,
792 ));
793 map(parser, |(comment, name, metadata, variants)| {
794 Union::builder()
795 .doc(comment)
796 .id(name)
797 .variants(variants)
798 .metadata(metadata)
799 .build()
800 })(input)
801}
802
803#[cfg(test)]
804mod union_tests {
805 use super::union_decl;
806 use crate::{e_item, union};
807
808 #[test]
809 fn test_simple_union_with_comments() {
810 let input = "union //foo!\nMyUnion // comment
811 //comment\n// thing\n{ // comm
812 foo // foo!
813 = 1//bar
814 ,\t\tbar, //baz! field\nBaz= 234 \n\n // ha!\n}";
815 let result = union_decl(input);
816 let expected = union!(
817 MyUnion,
818 [e_item!(foo = 1), e_item!(bar), e_item!(Baz = 234)]
819 );
820 assert_successful_parse!(result, expected);
821 }
822
823 #[test]
824 fn test_union_with_doc_comments() {
825 let input = "\
826/// Unionize!
827union MyUnion {
828 // Not a doc commment
829 /// Maybe it's a foo
830 foo = 1,
831 // Hm,
832 /// Could be a bar though
833 bar,
834
835 // Nope, it's a baz
836 baz = 9,
837}";
838 let result = union_decl(input);
839 let expected = union!(
840 MyUnion,
841 [
842 e_item!(foo = 1, [" Maybe it's a foo"]),
843 e_item!(bar, [" Could be a bar though"]),
844 e_item!(baz = 9)
845 ],
846 [" Unionize!"]
847 );
848 assert_successful_parse!(result, expected);
849 }
850
851 #[test]
852 fn test_simple_union() {
853 let input = "union MyUnion { foo = 1, bar, Baz = 234 }";
854 let result = union_decl(input);
855 let expected = union!(
856 MyUnion,
857 [e_item!(foo = 1), e_item!(bar), e_item!(Baz = 234)]
858 );
859 assert_successful_parse!(result, expected);
860 }
861}
862
863pub fn root_decl(input: &str) -> IResult<&str, Root<'_>> {
864 map(
865 tuple((
866 doc_comment,
867 delimited(
868 tag("root_type"),
869 delimited(comment_or_space1, ident, comment_or_space0),
870 semicolon,
871 ),
872 )),
873 |(_, typename)| Root::builder().typename(typename).build(),
874 )(input)
875}
876
877#[cfg(test)]
878mod root_tests {
879 use super::root_decl;
880 use crate::root_type;
881
882 #[test]
883 fn test_root_decl() {
884 let result = root_decl("root_type Foo;");
885 let expected = root_type!(Foo);
886 assert_successful_parse!(result, expected);
887 }
888
889 #[test]
890 fn test_root_decl_with_doc_comments() {
891 let input = "\
892/// I am Foo.
893// Not a doc
894
895root_type Foo;";
896 let result = root_decl(input);
897 let expected = root_type!(Foo);
900 assert_successful_parse!(result, expected);
901 }
902}
903
904pub fn field_decl(input: &str) -> IResult<&str, Field<'_>> {
905 map(
906 terminated(
907 tuple((
908 doc_comment,
909 terminated(ident, tuple((comment_or_space0, colon, comment_or_space0))),
910 type_,
911 opt(preceded(
912 tuple((comment_or_space0, equals, comment_or_space0)),
913 default_value,
914 )),
915 preceded(comment_or_space0, metadata),
916 )),
917 tuple((comment_or_space0, semicolon)),
918 ),
919 |(comment, name, ty, default_value, metadata)| {
920 Field::builder()
921 .doc(comment)
922 .id(name)
923 .ty(ty)
924 .default_value(default_value)
925 .metadata(metadata)
926 .build()
927 },
928 )(input)
929}
930
931#[cfg(test)]
932mod field_tests {
933 use super::{field_decl, Field, Ident, QualifiedIdent, Type};
934 use crate::{default_value, field, meta};
935
936 #[test]
937 fn test_field_decl_with_metadata() {
938 let input = "message: string (required);";
939 let result = field_decl(input);
940 let expected = field!(message, String, [meta!(required)]);
941 assert_successful_parse!(result, expected);
942 }
943
944 #[test]
945 fn test_field_decl_with_comments() {
946 let input = "\
948foo // bar
949// baz
950 :
951\tfloat64 // fizz
952= // buuzzzz
953\t\t\t2.0
954
955
956;";
957 let result = field_decl(input);
958 let expected = field!(foo, Float64 = 2.0);
959 assert_successful_parse!(result, expected);
960 }
961
962 #[test]
963 fn test_field_decl_with_doc_comment() {
964 let input = "\
965/// A really great field
966great: int64;";
967
968 let expected = field!(great, Int64, [" A really great field"]);
969 let result = field_decl(input);
970 assert_successful_parse!(result, expected);
971 }
972
973 #[test]
974 fn test_field_decl_with_doc_and_non_doc_comment() {
975 let input = "\
976/// A really great field
977// Not part of the doc
978
979great: int64;";
980
981 let expected = field!(great, Int64, [" A really great field"]);
982 let result = field_decl(input);
983 assert_successful_parse!(result, expected);
984 }
985
986 #[test]
987 fn test_field_decl_with_spaced_doc_comment() {
988 let input = "\
989/// A really great field
990
991great: int64;";
992
993 let expected = field!(great, Int64, [" A really great field"]);
994 let result = field_decl(input);
995 assert_successful_parse!(result, expected);
996 }
997
998 #[test]
999 fn test_field_decl_with_space_doc_and_non_doc_comment() {
1000 let input = "\
1001/// A really great field
1002// comment
1003
1004
1005// Thing!
1006great: int64;";
1007
1008 let expected = field!(great, Int64, [" A really great field"]);
1009 let result = field_decl(input);
1010 assert_successful_parse!(result, expected);
1011 }
1012
1013 #[test]
1014 fn test_field_decl() {
1015 let input = "foo: float64 = 2.0;";
1016 let result = field_decl(input);
1017 let expected = field!(foo, Float64 = 2.0);
1018 assert_successful_parse!(result, expected);
1019 }
1020
1021 #[test]
1022 fn test_field_decl_uint() {
1023 let input = "foo :uint=3;";
1024 let result = field_decl(input);
1025 let expected = field!(foo, UInt = 3);
1026 assert_successful_parse!(result, expected);
1027 }
1028
1029 #[test]
1030 fn test_field_decl_no_scalar() {
1031 let input = "foo:float64 //faz\n;";
1032 let result = field_decl(input);
1033 let expected = field!(foo, Float64);
1034 assert_successful_parse!(result, expected);
1035 }
1036
1037 #[test]
1038 fn test_field_decl_enum_default_value() {
1039 let input = "foo : MyEnum = Foo;";
1040 let result = field_decl(input);
1041 let expected = Field::builder()
1042 .id("foo".into())
1043 .ty(Type::Ident(QualifiedIdent::from(vec![Ident::from(
1044 "MyEnum",
1045 )])))
1046 .default_value(Some(default_value!("Foo")))
1047 .build();
1048 assert_successful_parse!(result, expected);
1049 }
1050
1051 #[test]
1052 fn test_field_decl_boolean_default_value_explicit_false() {
1053 let input = "foo : bool = false;";
1054 let result = field_decl(input);
1055 let expected = Field::builder()
1056 .id("foo".into())
1057 .ty(Type::Bool)
1058 .default_value(Some(default_value!(false)))
1059 .build();
1060 assert_successful_parse!(result, expected);
1061 }
1062
1063 #[test]
1064 fn test_field_decl_boolean_default_value_true() {
1065 let input = "foo : bool = true;";
1066 let result = field_decl(input);
1067 let expected = Field::builder()
1068 .id("foo".into())
1069 .ty(Type::Bool)
1070 .default_value(Some(default_value!(true)))
1071 .build();
1072 assert_successful_parse!(result, expected);
1073 }
1074}
1075
1076pub fn rpc_decl(input: &str) -> IResult<&str, Rpc<'_>> {
1077 map(
1078 tuple((
1079 doc_comment,
1080 preceded(
1081 terminated(tag("rpc_service"), comment_or_space1),
1082 terminated(ident, comment_or_space0),
1083 ),
1084 delimited(
1085 left_brace,
1086 many1(delimited(comment_or_space0, rpc_method, comment_or_space0)),
1087 right_brace,
1088 ),
1089 )),
1090 |(comment, name, methods)| {
1091 Rpc::builder()
1092 .doc(comment)
1093 .id(name)
1094 .methods(methods)
1095 .build()
1096 },
1097 )(input)
1098}
1099
1100#[cfg(test)]
1101mod rpc_tests {
1102 use super::rpc_decl;
1103 use crate::{meta, method, rpc};
1104
1105 #[test]
1106 fn test_rpc_decl_single_method_with_comments() {
1107 let input = "\
1108rpc_service Greeter { // foo
1109 //b baz
1110 SayHello(// foo
1111 HelloRequest):HelloReply; // zaz
1112// zu
1113}";
1114 let result = rpc_decl(input);
1115 let expected = rpc!(Greeter, [method!(fn SayHello(HelloRequest) -> HelloReply)]);
1116 assert_successful_parse!(result, expected);
1117 }
1118
1119 #[test]
1120 fn test_rpc_decl_single_method() {
1121 let input = "\
1122rpc_service Greeter {
1123 SayHello(HelloRequest):HelloReply;
1124}";
1125 let result = rpc_decl(input);
1126 let expected = rpc!(Greeter, [method!(fn SayHello(HelloRequest) -> HelloReply)]);
1127 assert_successful_parse!(result, expected);
1128 }
1129
1130 #[test]
1131 fn test_rpc_decl_multiple_methods() {
1132 let input = "\
1133rpc_service Greeter {
1134 SayHello (HelloRequest ):HelloReply;
1135 SayManyHellos(ManyHellosRequest):HelloReply (streaming: \"server\" ) ;
1136
1137}";
1138 let result = rpc_decl(input);
1139 let expected = rpc!(
1140 Greeter,
1141 [
1142 method!(fn SayHello(HelloRequest) -> HelloReply),
1143 method!(fn SayManyHellos(ManyHellosRequest) -> HelloReply, [
1144 meta!(streaming, "server")
1145 ])
1146 ]
1147 );
1148 assert_successful_parse!(result, expected);
1149 }
1150
1151 #[test]
1152 fn test_rpc_decl_doc_comment() {
1153 let input = "\
1154/// A greeter service!
1155// impl
1156/// User facing
1157rpc_service Greeter {
1158 /// Hi there!
1159 SayHello (HelloRequest ):HelloReply;
1160 /// Multiple hi theres!
1161 SayManyHellos(ManyHellosRequest):HelloReply (streaming: \"server\" ) ;
1162
1163}";
1164 let result = rpc_decl(input);
1165 let expected = rpc!(
1166 Greeter,
1167 [
1168 method!(fn SayHello(HelloRequest) -> HelloReply, None, [ " Hi there!" ]),
1169 method!(fn SayManyHellos(ManyHellosRequest) -> HelloReply, [
1170 meta!(streaming, "server")
1171 ], [ " Multiple hi theres!" ])
1172 ],
1173 [" A greeter service!", " User facing"]
1174 );
1175 assert_successful_parse!(result, expected);
1176 }
1177}
1178
1179#[cfg(test)]
1180mod qualified_ident_tests {
1181 use super::{qualified_ident, Ident, QualifiedIdent};
1182
1183 #[test]
1184 fn test_simple_qualified_ident() {
1185 let result = qualified_ident("a.b");
1186 let expected = QualifiedIdent::from(vec![Ident::from("a"), Ident::from("b")]);
1187 assert_successful_parse!(result, expected);
1188 }
1189}
1190
1191pub fn rpc_method(input: &str) -> IResult<&str, RpcMethod<'_>> {
1192 map(
1193 tuple((
1194 doc_comment,
1195 terminated(ident, comment_or_space0),
1196 delimited(
1197 left_paren,
1198 delimited(comment_or_space0, qualified_ident, comment_or_space0),
1199 right_paren,
1200 ),
1201 preceded(
1202 delimited(comment_or_space0, colon, comment_or_space0),
1203 terminated(
1204 tuple((qualified_ident, preceded(comment_or_space0, metadata))),
1205 terminated(comment_or_space0, semicolon),
1206 ),
1207 ),
1208 )),
1209 |(comment, name, request_type, (response_type, metadata))| {
1210 RpcMethod::builder()
1211 .id(name)
1212 .request_type(request_type)
1213 .response_type(response_type)
1214 .metadata(metadata)
1215 .doc(comment)
1216 .build()
1217 },
1218 )(input)
1219}
1220
1221#[cfg(test)]
1222mod rpc_method_tests {
1223 use super::rpc_method;
1224 use crate::{meta, method};
1225
1226 #[test]
1227 fn test_rpc_method_with_comments() {
1228 let input = "\
1229SayHello // foo
1230(// bar
1231 HelloRequest
1232 // fiizz
1233 )
1234//buzz
1235// baz
1236:
1237 HelloReply // saz
1238// fzz
1239;";
1240 let result = rpc_method(input);
1241 let expected = method!(fn SayHello(HelloRequest) -> HelloReply);
1242 assert_successful_parse!(result, expected);
1243 }
1244
1245 #[test]
1246 fn test_rpc_method() {
1247 let input = "SayHello(HelloRequest):HelloReply;";
1248 let result = rpc_method(input);
1249 let expected = method!(fn SayHello(HelloRequest) -> HelloReply);
1250 assert_successful_parse!(result, expected);
1251 }
1252
1253 #[test]
1254 fn test_rpc_method_with_metadata() {
1255 let input =
1256 r#"SayHello(HelloRequest):HelloReply (streaming: "server", streaming: "server");"#;
1257 let result = rpc_method(input);
1258 let expected =
1259 method!(fn SayHello(HelloRequest) -> HelloReply, [meta!(streaming, "server")]);
1260 assert_successful_parse!(result, expected);
1261 }
1262
1263 #[test]
1264 fn test_rpc_method_with_metadata_and_comments() {
1265 let input = r#"SayHello(HelloRequest):HelloReply (streaming:
1266 // fuzz
1267 "server", streaming: "server");"#;
1268 let result = rpc_method(input);
1269 let expected =
1270 method!(fn SayHello(HelloRequest) -> HelloReply, [meta!(streaming, "server")]);
1271 assert_successful_parse!(result, expected);
1272 }
1273}
1274
1275pub fn type_(input: &str) -> IResult<&str, Type<'_>> {
1276 alt((
1277 alt((
1278 value(Type::Bool, tag("bool")),
1279 value(Type::Byte, tag("byte")),
1280 value(Type::UByte, tag("ubyte")),
1281 value(Type::Short, tag("short")),
1282 value(Type::UShort, tag("ushort")),
1283 value(Type::Long, tag("long")),
1284 value(Type::ULong, tag("ulong")),
1285 value(Type::Double, tag("double")),
1286 value(Type::Int8, tag("int8")),
1287 value(Type::UInt8, tag("uint8")),
1288 value(Type::Int16, tag("int16")),
1289 value(Type::UInt16, tag("uint16")),
1290 value(Type::Int32, tag("int32")),
1291 value(Type::UInt32, tag("uint32")),
1292 value(Type::Int64, tag("int64")),
1293 value(Type::UInt64, tag("uint64")),
1294 value(Type::Float32, tag("float32")),
1295 value(Type::Float64, tag("float64")),
1296 value(Type::Int, tag("int")),
1297 value(Type::UInt, tag("uint")),
1298 value(Type::Float, tag("float")),
1299 )),
1300 value(Type::String, tag("string")),
1301 map(
1302 delimited(left_square_bracket, type_, right_square_bracket),
1303 |t| Type::from([t]),
1304 ),
1305 map(qualified_ident, Type::Ident),
1306 ))(input)
1307}
1308
1309pub fn enumval_decl(input: &str) -> IResult<&str, EnumVariant<'_>> {
1311 let parser = tuple((
1312 doc_comment,
1313 ident,
1314 opt(preceded(
1315 comment_or_space0,
1316 preceded(equals, preceded(comment_or_space0, integer_constant)),
1317 )),
1318 ));
1319 map(parser, |(comment, id, value)| {
1320 EnumVariant::builder()
1321 .id(id)
1322 .value(value)
1323 .doc(comment)
1324 .build()
1325 })(input)
1326}
1327
1328pub fn raw_metadata(input: &str) -> IResult<&str, Metadata<'_>> {
1330 map(
1331 delimited(
1332 terminated(left_paren, comment_or_space0),
1333 separated_list(
1334 delimited(comment_or_space0, comma, comment_or_space0),
1335 tuple((
1336 ident,
1337 opt(preceded(
1338 comment_or_space0,
1339 preceded(colon, preceded(comment_or_space0, single)),
1340 )),
1341 )),
1342 ),
1343 preceded(comment_or_space0, right_paren),
1344 ),
1345 Metadata::from,
1346 )(input)
1347}
1348
1349pub fn metadata(input: &str) -> IResult<&str, Option<Metadata<'_>>> {
1351 opt(raw_metadata)(input)
1352}
1353
1354#[cfg(test)]
1355mod metadata_tests {
1356 use super::{metadata, Metadata};
1357 use crate::meta;
1358
1359 #[test]
1360 fn test_simple_metadata_with_comments() {
1361 let input = "\
1362(
1363 // fuzzy
1364 a // wuzzy
1365 : // wuz
1366 \"b\"
1367// a bear
1368\t)";
1369 let result = metadata(input);
1370 let expected = Some(Metadata::from(vec![meta!(a, "b")]));
1371 assert_successful_parse!(result, expected);
1372 }
1373
1374 #[test]
1375 fn test_simple_metadata() {
1376 let input = "(a: \"b\")";
1377 let result = metadata(input);
1378 let expected = Some(Metadata::from(vec![meta!(a, "b")]));
1379 assert_successful_parse!(result, expected);
1380 }
1381
1382 #[test]
1383 fn test_single_metadata() {
1384 let input = "(required)";
1385 let result = metadata(input);
1386 let expected = Some(Metadata::from(vec![meta!(required)]));
1387 assert_successful_parse!(result, expected);
1388 }
1389
1390 #[test]
1391 fn test_empty_metadata() {
1392 let input = "()";
1393 let result = metadata(input);
1394 let expected = Some(Metadata::builder().build());
1395 assert_successful_parse!(result, expected);
1396 }
1397
1398 #[test]
1399 fn test_keys_only_metadata() {
1400 let input = "(a, b, c, def)";
1401 let result = metadata(input);
1402 let expected = Some(Metadata::from(vec![
1403 meta!(a),
1404 meta!(b),
1405 meta!(c),
1406 meta!(def),
1407 ]));
1408 assert_successful_parse!(result, expected);
1409 }
1410
1411 #[test]
1412 fn test_multiple_field_metadata() {
1413 let input = "(x, a: \"news\", b: 42,c: 42.42, d, e)";
1414 let result = metadata(input);
1415 let expected = Some(Metadata::from(vec![
1416 meta!(x),
1417 meta!(a, "news"),
1418 meta!(b, 42),
1419 meta!(c, 42.42),
1420 meta!(d),
1421 meta!(e),
1422 ]));
1423 assert_successful_parse!(result, expected);
1424 }
1425}
1426
1427pub fn scalar(input: &str) -> IResult<&str, Scalar> {
1429 alt((
1430 map(float_constant, Scalar::from),
1431 map(integer_constant, Scalar::from),
1432 map(boolean_constant, Scalar::from),
1433 ))(input)
1434}
1435
1436pub fn object(input: &str) -> IResult<&str, Object<'_>> {
1438 map(
1439 tuple((
1440 doc_comment,
1441 delimited(
1442 terminated(left_brace, comment_or_space0),
1443 separated_list(
1444 delimited(comment_or_space0, comma, comment_or_space0),
1445 separated_pair(
1446 ident,
1447 delimited(comment_or_space0, colon, comment_or_space0),
1448 value_,
1449 ),
1450 ),
1451 preceded(comment_or_space0, right_brace),
1452 ),
1453 )),
1454 |(comment, key_value_pairs)| {
1455 Object::builder()
1456 .doc(comment)
1457 .values(std::collections::HashMap::from_iter(key_value_pairs))
1458 .build()
1459 },
1460 )(input)
1461}
1462
1463#[cfg(test)]
1464mod object_tests {
1465 use super::object;
1466 use crate::object as obj;
1467
1468 #[test]
1469 fn test_object() {
1470 let input = r#"{a: ["b", 1.0, 2, [3]]}"#;
1471 let result = object(input);
1472 let expected = obj!({
1473 a => ["b", 1.0, 2, [3]]
1474 });
1475 assert_successful_parse!(result, expected);
1476 }
1477
1478 #[test]
1479 fn test_empty_object() {
1480 let input = "{}";
1481 let result = object(input);
1482 let expected = obj!({});
1483 assert_successful_parse!(result, expected);
1484 }
1485
1486 #[test]
1487 fn test_object_with_doc_comments() {
1488 let input = "\
1489/// A doc
1490//
1491/// Comment
1492
1493{}";
1494 let result = object(input);
1495 let expected = obj!({}, [" A doc", " Comment"]);
1496 assert_successful_parse!(result, expected);
1497 }
1498
1499 #[test]
1500 fn test_object_with_comments() {
1501 let input = r#"{
1502 // baz
1503
1504 a //buzz
1505 : // fizz
1506 [// baz
1507"b" // foo
1508, // fizz
1509 1.0, 2, [//foo
1510 3//bar
1511 ]
1512 //baz
1513 ]
1514 // foo
1515}"#;
1516 let result = object(input);
1517 let expected = obj!({
1518 a => ["b", 1.0, 2, [3]]
1519 });
1520 assert_successful_parse!(result, expected);
1521 }
1522}
1523
1524pub fn single(input: &str) -> IResult<&str, Single<'_>> {
1526 alt((
1527 map(scalar, Single::from),
1528 map(string_constant, Single::from),
1529 ))(input)
1530}
1531
1532pub fn value_list(input: &str) -> IResult<&str, Vec<Value<'_>>> {
1534 delimited(
1535 terminated(left_square_bracket, comment_or_space0),
1536 separated_list(
1537 delimited(comment_or_space0, comma, comment_or_space0),
1538 value_,
1539 ),
1540 preceded(comment_or_space0, right_square_bracket),
1541 )(input)
1542}
1543
1544#[cfg(test)]
1545mod value_list_tests {
1546 use super::value_list;
1547 use crate::value as val;
1548
1549 #[test]
1550 fn test_value_list() {
1551 let input = r#"["a",1, 2]"#;
1552 let result = value_list(input);
1553 assert_successful_parse!(result, vec![val!("a"), val!(1), val!(2)]);
1554 }
1555
1556 #[test]
1557 fn test_value_list_with_comments() {
1558 let input = r#"[//thing
1559 "a",1
1560 // comment
1561 ,
1562 // a huge comment
1563 // on
1564 // mul-
1565 // tiple lines, some space too!
1566
1567 2// fiz
1568 ]"#;
1569 let result = value_list(input);
1570 assert_successful_parse!(result, vec![val!("a"), val!(1), val!(2)]);
1571 }
1572}
1573
1574pub fn value_(input: &str) -> IResult<&str, Value<'_>> {
1576 alt((
1577 map(single, Value::from),
1578 map(object, Value::from),
1579 map(value_list, Value::from),
1580 ))(input)
1581}
1582
1583#[cfg(test)]
1584mod value_tests {
1585 use super::{value_, Scalar, Single, Value};
1586 use crate::value as val;
1587
1588 #[test]
1589 fn test_value_single_value() {
1590 let result = value_("1");
1591 assert_successful_parse!(
1592 result,
1593 Value::Single(Single::Scalar(Scalar::Integer(1.into())))
1594 );
1595
1596 let result = value_("2.3");
1597 assert_successful_parse!(result, val!(2.3));
1598
1599 let result = value_("\"abc d\"");
1600 assert_successful_parse!(result, val!("abc d"));
1601
1602 let result = value_("true");
1603 assert_successful_parse!(result, val!(true));
1604
1605 let result = value_("false");
1606 assert_successful_parse!(result, val!(false));
1607 }
1608
1609 #[test]
1610 fn test_value_object() {
1611 let result = value_("{a: 1}");
1612 assert_successful_parse!(result, val!({ a => 1 }));
1613
1614 let result = value_("{b: 2.42}");
1615 assert_successful_parse!(result, val!({ b => 2.42 }));
1616
1617 let result = value_(r#"{c: ["a"]}"#);
1618 assert_successful_parse!(result, val!({ c => ["a"] }));
1619
1620 let result = value_(r#"{d: ["a", {b: [1, ["z"]]}]}"#);
1622 assert_successful_parse!(
1623 result,
1624 val!({
1625 d => [
1626 "a",
1627 {
1628 b => [1, ["z"]]
1629 }
1630 ]
1631 })
1632 );
1633 }
1634
1635 #[test]
1636 fn test_value_value_list() {
1637 let result = value_(r#"["a", 1]"#);
1638 let expected = val!(["a", 1]);
1639 assert_successful_parse!(result, expected);
1640 }
1641}
1642
1643pub fn default_value(input: &str) -> IResult<&str, DefaultValue<'_>> {
1646 alt((
1647 map(scalar, DefaultValue::from),
1648 map(ident, DefaultValue::from),
1649 ))(input)
1650}
1651
1652#[cfg(test)]
1653mod default_value_tests {
1654 use super::default_value;
1655 use crate::default_value as defval;
1656
1657 #[test]
1658 fn test_default_value() {
1659 let result = default_value("1");
1660 assert_successful_parse!(result, defval!(1));
1661
1662 let result = default_value("Foo");
1663 assert_successful_parse!(result, defval!("Foo"));
1664
1665 let result = default_value("false");
1666 assert_successful_parse!(result, defval!(false));
1667
1668 let result = default_value("true");
1669 assert_successful_parse!(result, defval!(true));
1670 }
1671}
1672
1673type ProductTypeTriple<'a> = (Ident<'a>, Option<Metadata<'a>>, Vec<Field<'a>>);
1675
1676pub fn product_type_body(input: &str) -> IResult<&str, ProductTypeTriple<'_>> {
1678 tuple((
1679 delimited(comment_or_space1, ident, comment_or_space0),
1680 terminated(metadata, comment_or_space0),
1681 delimited(
1682 preceded(left_brace, comment_or_space0),
1683 many0(delimited(comment_or_space0, field_decl, comment_or_space0)),
1684 terminated(comment_or_space0, right_brace),
1685 ),
1686 ))(input)
1687}
1688
1689pub fn struct_decl(input: &str) -> IResult<&str, Struct<'_>> {
1691 map(
1692 tuple((doc_comment, preceded(tag("struct"), product_type_body))),
1693 |(comment, (name, metadata, fields))| {
1694 Struct::builder()
1695 .doc(comment)
1696 .id(name)
1697 .metadata(metadata)
1698 .fields(fields)
1699 .build()
1700 },
1701 )(input)
1702}
1703
1704pub fn table_decl(input: &str) -> IResult<&str, Table<'_>> {
1706 map(
1707 tuple((doc_comment, preceded(tag("table"), product_type_body))),
1708 |(comment, (name, metadata, fields))| {
1709 Table::builder()
1710 .doc(comment)
1711 .id(name)
1712 .metadata(metadata)
1713 .fields(fields)
1714 .build()
1715 },
1716 )(input)
1717}
1718
1719#[cfg(test)]
1720mod table_tests {
1721 use super::{table_decl, Field, Ident, QualifiedIdent, Table, Type};
1722 use crate::{default_value, field, meta, table};
1723
1724 #[test]
1725 fn test_empty_table_no_spaces() {
1726 let input = "table HelloReply {}";
1727 let result = table_decl(input);
1728 let expected = table!(HelloReply, []);
1729 assert_successful_parse!(result, expected);
1730 }
1731
1732 #[test]
1733 fn test_empty_table() {
1734 let input = "\
1735table HelloReply {
1736}";
1737 let result = table_decl(input);
1738 let expected = table!(HelloReply, []);
1739 assert_successful_parse!(result, expected);
1740 }
1741
1742 #[test]
1743 fn test_table_with_doc_commented_fields() {
1744 let input = "\
1745/// A response with a required field
1746table HelloReply {
1747
1748 /// Sweet, sweet message
1749 message: string;
1750 // Not a doc comment
1751 /// A doc comment
1752 foo: [string];
1753 // Aha!
1754
1755 bar: [float64];
1756
1757}";
1758 let result = table_decl(input);
1759 let expected = table!(
1760 HelloReply,
1761 [
1762 field!(message, String, [" Sweet, sweet message"]),
1763 field!(foo, [String], [" A doc comment"]),
1764 field!(bar, [Float64])
1765 ],
1766 [" A response with a required field"]
1767 );
1768 assert_successful_parse!(result, expected);
1769 }
1770
1771 #[test]
1772 fn test_table_with_required_field() {
1773 let input = "\
1774/// A response with a required field
1775table HelloReply {
1776 message: string (required);
1777}";
1778 let result = table_decl(input);
1779 let expected = table!(
1780 HelloReply,
1781 [field!(message, String, [meta!(required)])],
1782 [" A response with a required field"]
1783 );
1784 assert_successful_parse!(result, expected);
1785 }
1786
1787 #[test]
1788 fn test_table_with_comments() {
1789 let input = "\
1791/// My awesome table!
1792table HelloReply // baz
1793// foo
1794{ // buz
1795 message: string; // fizz
1796 // buzzz
1797 // a
1798foo :uint=3;//baz
1799// fizzy
1800 bar // fuzzy
1801 : [int8];
1802}";
1803 let result = table_decl(input);
1804 let expected = table!(
1805 HelloReply,
1806 [
1807 field!(message, String),
1808 field!(foo, UInt = 3),
1809 field!(bar, [Int8])
1810 ],
1811 [" My awesome table!"]
1812 );
1813 assert_successful_parse!(result, expected);
1814 }
1815
1816 #[test]
1817 fn test_table_multiple_fields() {
1818 let input = "\
1819/// My awesome table!
1820table HelloReply
1821{
1822 message: string;
1823 foo :uint=3;
1824
1825 bar : [int8];
1826}";
1827 let result = table_decl(input);
1828 let expected = table!(
1829 HelloReply,
1830 [
1831 field!(message, String),
1832 field!(foo, UInt = 3),
1833 field!(bar, [Int8])
1834 ],
1835 [" My awesome table!"]
1836 );
1837 assert_successful_parse!(result, expected);
1838 }
1839
1840 #[test]
1841 fn test_table() {
1842 let input = "\
1843table HelloReply {
1844 message: string;
1845}";
1846 let result = table_decl(input);
1847 let expected = table!(HelloReply, [field!(message, String)]);
1848 assert_successful_parse!(result, expected);
1849 }
1850
1851 #[test]
1852 fn test_table_with_default_enum_value() {
1853 let input = "\
1854table HelloReply {
1855 message_type: MessageType = UNKNOWN;
1856}";
1857 let result = table_decl(input);
1858 let expected = Table::builder()
1859 .id(Ident::from("HelloReply"))
1860 .fields(vec![Field::builder()
1861 .id("message_type".into())
1862 .ty(Type::Ident(QualifiedIdent::from(vec![Ident::from(
1863 "MessageType",
1864 )])))
1865 .default_value(Some(default_value!("UNKNOWN")))
1866 .build()])
1867 .build();
1868
1869 assert_successful_parse!(result, expected);
1870 }
1871}
1872
1873pub fn dec_integer_constant(input: &str) -> IResult<&str, IntegerConstant> {
1875 map_res(
1876 recognize(preceded(opt(plus_or_minus), digit1)),
1877 IntegerConstant::from_str,
1878 )(input)
1879}
1880
1881#[cfg(test)]
1882mod dec_integer_constant_tests {
1883 use super::{dec_integer_constant, IntegerConstant};
1884 use anyhow::Result;
1885 use std::convert::TryFrom;
1886
1887 #[test]
1888 fn test_u64() -> Result<()> {
1889 let u64_max = std::u64::MAX;
1890 let u64_max_string = u64_max.to_string();
1891 let result = dec_integer_constant(&u64_max_string);
1892 let expected = IntegerConstant::try_from(u64_max)?;
1893 assert_successful_parse!(result, expected);
1894 Ok(())
1895 }
1896
1897 #[test]
1898 fn test_i64_max() -> Result<()> {
1899 let i64_max = std::i64::MAX;
1900 let i64_max_string = i64_max.to_string();
1901 let result = dec_integer_constant(&i64_max_string);
1902 let expected = IntegerConstant::try_from(i64_max)?;
1903 assert_successful_parse!(result, expected);
1904 Ok(())
1905 }
1906
1907 #[test]
1908 fn test_i64_min() -> Result<()> {
1909 let i64_min = std::i64::MIN;
1910 let i64_min_string = i64_min.to_string();
1911 let result = dec_integer_constant(&i64_min_string);
1912 let expected = IntegerConstant::try_from(i64_min)?;
1913 assert_successful_parse!(result, expected);
1914 Ok(())
1915 }
1916
1917 #[test]
1918 fn test_dec_integer_constant() {
1919 let result = dec_integer_constant("1234");
1920 assert_successful_parse!(result, 1234.into());
1921
1922 let result = dec_integer_constant("-1234");
1923 assert_successful_parse!(result, (-1234).into());
1924 }
1925}
1926
1927pub fn hex_integer_constant(input: &str) -> IResult<&str, IntegerConstant> {
1928 map_res(
1929 tuple((
1930 opt(plus_or_minus),
1931 preceded(zero, preceded(one_of("xX"), hex_digit1)),
1932 )),
1933 |(sign, value)| -> Result<IntegerConstant> {
1934 let int_const = IntegerConstant::from_str_radix(value, 16)?;
1935 if let Some('-') = sign {
1936 int_const
1937 .checked_neg()
1938 .ok_or_else(|| anyhow!("invalid value for negation {}", int_const))
1939 } else {
1940 Ok(int_const)
1941 }
1942 },
1943 )(input)
1944}
1945
1946#[cfg(test)]
1947mod hex_integer_constant_tests {
1948 use super::hex_integer_constant;
1949
1950 #[test]
1951 fn test_hex_integer_constant() {
1952 let result = hex_integer_constant("0x1234ABCDEFabcdef");
1953 assert_successful_parse!(result, 0x1234_ABCD_EFAB_CDEF_i64.into());
1954
1955 let result = hex_integer_constant("-0x1234ABCDEFabcdef");
1956 assert_successful_parse!(result, (-0x1234_ABCD_EFAB_CDEF_i64).into());
1957 }
1958
1959 #[test]
1960 fn test_invalid_hex_integer_constant() {
1961 let result = hex_integer_constant("ABCDEFabcdef");
1962 assert_failed_parse!(result, "ABCDEFabcdef", Char);
1963 }
1964}
1965
1966pub fn true_(input: &str) -> IResult<&str, BooleanConstant> {
1967 value(true, |input: &str| {
1968 nom::re_match!(input, r"\btrue\b")?;
1969 tag("true")(input)
1970 })(input)
1971}
1972
1973pub fn false_(input: &str) -> IResult<&str, BooleanConstant> {
1974 value(false, |input: &str| {
1975 nom::re_match!(input, r"\bfalse\b")?;
1976 tag("false")(input)
1977 })(input)
1978}
1979
1980#[cfg(test)]
1981mod true_false_tests {
1982 use super::{false_, true_};
1983
1984 #[test]
1985 fn test_true() {
1986 let result = true_("true");
1987 assert_successful_parse!(result, true);
1988 }
1989
1990 #[test]
1991 fn test_true_semicolon() {
1992 let result = true_("true;");
1993 assert_successful_parse!(result, ";", true);
1994 }
1995
1996 #[test]
1997 fn test_invalid_true() {
1998 let result = true_("truez");
1999 assert_failed_parse!(result, "truez", RegexpMatch);
2000 }
2001
2002 #[test]
2003 fn test_false() {
2004 let result = false_("false");
2005 assert_successful_parse!(result, false);
2006 }
2007
2008 #[test]
2009 fn test_false_semicolon() {
2010 let result = false_("false;");
2011 assert_successful_parse!(result, ";", false);
2012 }
2013
2014 #[test]
2015 fn test_invalid_false() {
2016 let result = false_("falsez");
2017 assert_failed_parse!(result, "falsez", RegexpMatch);
2018 }
2019}
2020
2021pub fn boolean_constant(input: &str) -> IResult<&str, bool> {
2024 alt((true_, false_))(input)
2025}
2026
2027#[cfg(test)]
2028mod boolean_constant_tests {
2029 use super::boolean_constant;
2030
2031 #[test]
2032 fn test_boolean_constant() {
2033 let result = boolean_constant("true");
2034 assert_successful_parse!(result, true);
2035
2036 let result = boolean_constant("false");
2037 assert_successful_parse!(result, false);
2038 }
2039
2040 #[test]
2041 fn test_invalid_boolean_constant() {
2042 let result = boolean_constant("waltz");
2043 assert_failed_parse!(result, "waltz", RegexpMatch);
2044 }
2045}
2046
2047pub fn dec_float_exponent(input: &str) -> IResult<&str, &str> {
2048 recognize(tuple((one_of("eE"), opt(plus_or_minus), digit1)))(input)
2049}
2050
2051pub fn dec_float_constant(input: &str) -> IResult<&str, FloatingConstant> {
2053 let parser = recognize(preceded(
2054 opt(plus_or_minus),
2055 alt((
2056 terminated(
2057 alt((
2058 terminated(digit1, terminated(period, digit0)),
2059 preceded(period, digit1),
2060 )),
2061 opt(dec_float_exponent),
2062 ),
2063 terminated(digit1, dec_float_exponent),
2064 )),
2065 ));
2066 map_res(parser, FloatingConstant::from_str)(input)
2067}
2068
2069#[cfg(test)]
2070mod dec_float_constant_tests {
2071 use super::dec_float_constant;
2072
2073 #[test]
2074 fn test_dec_float_constant() {
2075 let result = dec_float_constant("-2.1");
2076 assert_successful_parse!(result, -2.1);
2077 }
2078}
2079
2080pub fn float_constant(input: &str) -> IResult<&str, FloatingConstant> {
2083 alt((
2084 special_float_constant,
2085 hex_float_constant,
2086 dec_float_constant,
2087 ))(input)
2088}
2089
2090#[cfg(test)]
2091mod float_constant_tests {
2092 use super::{assert_eq, float_constant};
2093
2094 #[test]
2095 fn test_float_constant_nan() {
2096 let result = float_constant("nan");
2097 assert_eq!(
2098 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_positive())),
2099 Ok(("", true, true))
2100 );
2101
2102 let result = float_constant("+nan");
2103 assert_eq!(
2104 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_positive())),
2105 Ok(("", true, true))
2106 );
2107
2108 let result = float_constant("-nan");
2109 assert_eq!(
2110 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_negative())),
2111 Ok(("", true, true))
2112 );
2113 }
2114
2115 #[test]
2116 fn test_float_constant_inf() {
2117 let result = float_constant("inf");
2118 assert_successful_parse!(result, std::f64::INFINITY);
2119
2120 let result = float_constant("+inf");
2121 assert_successful_parse!(result, std::f64::INFINITY);
2122
2123 let result = float_constant("-inf");
2124 assert_successful_parse!(result, std::f64::NEG_INFINITY);
2125 }
2126
2127 #[test]
2128 fn test_float_constant_infinity() {
2129 let result = float_constant("infinity");
2130 assert_successful_parse!(result, std::f64::INFINITY);
2131
2132 let result = float_constant("+infinity");
2133 assert_successful_parse!(result, std::f64::INFINITY);
2134
2135 let result = float_constant("-infinity");
2136 assert_successful_parse!(result, std::f64::NEG_INFINITY);
2137 }
2138}
2139
2140pub fn hex_float_exponent(input: &str) -> IResult<&str, &str> {
2142 recognize(terminated(
2143 one_of("pP"),
2144 terminated(opt(plus_or_minus), digit1),
2145 ))(input)
2146}
2147
2148pub fn hex_float_constant(input: &str) -> IResult<&str, FloatingConstant> {
2149 let parser = tuple((
2150 terminated(opt(plus_or_minus), terminated(zero, one_of("xX"))),
2151 map_res(
2154 recognize(alt((
2155 terminated(
2156 alt((
2157 terminated(terminated(hex_digit1, period), hex_digit0),
2158 preceded(period, hex_digit1),
2159 )),
2160 opt(hex_float_exponent),
2161 ),
2162 terminated(hex_digit1, hex_float_exponent),
2163 ))),
2164 |value| parse_hexf64(value, false),
2165 ),
2166 ));
2167 map(
2168 parser,
2169 |(sign, value)| {
2170 if let Some('-') = sign {
2171 -value
2172 } else {
2173 value
2174 }
2175 },
2176 )(input)
2177}
2178
2179pub fn nan(input: &str) -> IResult<&str, FloatingConstant> {
2181 map(
2182 terminated(opt(plus_or_minus), |input| {
2183 nom::re_match!(input, r"\bnan\b")
2184 }),
2185 |sign| {
2186 if let Some('-') = sign {
2187 -std::f64::NAN
2188 } else {
2189 std::f64::NAN
2190 }
2191 },
2192 )(input)
2193}
2194
2195#[cfg(test)]
2196mod nan_tests {
2197 use super::{assert_eq, nan};
2198
2199 #[test]
2200 fn test_nan() {
2201 let result = nan("nan");
2202 assert_eq!(
2203 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_positive())),
2204 Ok(("", true, true))
2205 );
2206
2207 let result = nan("+nan");
2208 assert_eq!(
2209 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_positive())),
2210 Ok(("", true, true))
2211 );
2212
2213 let result = nan("-nan");
2214 assert_eq!(
2215 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_negative())),
2216 Ok(("", true, true))
2217 );
2218 }
2219
2220 #[test]
2221 fn test_invalid_nan() {
2222 let result = nan("nanz");
2223 assert_failed_parse!(result, "nanz", RegexpMatch);
2224 }
2225}
2226
2227pub fn inf_or_infinity(input: &str) -> IResult<&str, FloatingConstant> {
2229 map(
2230 terminated(opt(plus_or_minus), |input| {
2231 nom::re_match!(input, r"\binf(inity)?\b")
2232 }),
2233 |sign| {
2234 if let Some('-') = sign {
2235 std::f64::NEG_INFINITY
2236 } else {
2237 std::f64::INFINITY
2238 }
2239 },
2240 )(input)
2241}
2242
2243#[cfg(test)]
2244mod inf_or_infinity_tests {
2245 use super::inf_or_infinity;
2246
2247 #[test]
2248 fn test_inf_or_infinity_infinity() {
2249 let result = inf_or_infinity("inf");
2250 assert_successful_parse!(result, std::f64::INFINITY);
2251
2252 let result = inf_or_infinity("+inf");
2253 assert_successful_parse!(result, std::f64::INFINITY);
2254
2255 let result = inf_or_infinity("-inf");
2256 assert_successful_parse!(result, std::f64::NEG_INFINITY);
2257
2258 let result = inf_or_infinity("infinity");
2259 assert_successful_parse!(result, std::f64::INFINITY);
2260
2261 let result = inf_or_infinity("+infinity");
2262 assert_successful_parse!(result, std::f64::INFINITY);
2263
2264 let result = inf_or_infinity("-infinity");
2265 assert_successful_parse!(result, std::f64::NEG_INFINITY);
2266 }
2267}
2268
2269pub fn special_float_constant(input: &str) -> IResult<&str, FloatingConstant> {
2271 alt((nan, inf_or_infinity))(input)
2272}
2273
2274#[cfg(test)]
2275mod special_float_constant_tests {
2276 use super::{assert_eq, special_float_constant};
2277
2278 #[test]
2279 fn test_special_float_constant_nan() {
2280 let result = special_float_constant("nan");
2281 assert_eq!(
2282 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_positive())),
2283 Ok(("", true, true))
2284 );
2285
2286 let result = special_float_constant("+nan");
2287 assert_eq!(
2288 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_positive())),
2289 Ok(("", true, true))
2290 );
2291
2292 let result = special_float_constant("-nan");
2293 assert_eq!(
2294 result.map(|(input, value)| (input, value.is_nan(), value.is_sign_negative())),
2295 Ok(("", true, true))
2296 );
2297 }
2298
2299 #[test]
2300 fn test_special_float_constant_inf() {
2301 let result = special_float_constant("inf");
2302 assert_successful_parse!(result, std::f64::INFINITY);
2303
2304 let result = special_float_constant("-inf");
2305 assert_successful_parse!(result, std::f64::NEG_INFINITY);
2306 }
2307
2308 #[test]
2309 fn test_special_float_constant_infinity() {
2310 let result = special_float_constant("infinity");
2311 assert_successful_parse!(result, std::f64::INFINITY);
2312
2313 let result = special_float_constant("-infinity");
2314 assert_successful_parse!(result, std::f64::NEG_INFINITY);
2315 }
2316}
2317
2318pub fn integer_constant(input: &str) -> IResult<&str, IntegerConstant> {
2319 alt((hex_integer_constant, dec_integer_constant))(input)
2320}
2321
2322#[cfg(test)]
2323mod integer_constant_tests {
2324 use super::integer_constant;
2325
2326 #[test]
2327 fn test_integer_constant() {
2328 let result = integer_constant("1234");
2329 assert_successful_parse!(result, 1234.into());
2330
2331 let result = integer_constant("-1234");
2332 assert_successful_parse!(result, (-1234).into());
2333
2334 let result = integer_constant("0x1234");
2335 assert_successful_parse!(result, 0x1234.into());
2336
2337 let result = integer_constant("-0x1234");
2338 assert_successful_parse!(result, (-0x1234).into());
2339 }
2340}
2341
2342pub fn file_extension_decl(input: &str) -> IResult<&str, FileExtension<'_>> {
2343 map(
2344 tuple((
2345 doc_comment,
2346 delimited(
2347 tag("file_extension"),
2348 delimited(comment_or_space0, string_constant, comment_or_space0),
2349 semicolon,
2350 ),
2351 )),
2352 |(comment, ext)| FileExtension::builder().doc(comment).ext(ext).build(),
2353 )(input)
2354}
2355
2356#[cfg(test)]
2357mod file_extension_tests {
2358 use super::file_extension_decl;
2359 use crate::file_ext;
2360
2361 #[test]
2362 fn test_file_extension_decl_with_comments() {
2363 let result = file_extension_decl(
2364 "file_extension //bar
2365 // foo
2366 \"foo\"//baz\n\t;",
2367 );
2368 let expected = file_ext!("foo");
2369 assert_successful_parse!(result, expected);
2370 }
2371
2372 #[test]
2373 fn test_file_extension_decl_with_doc_comments() {
2374 let result = file_extension_decl(
2375 "\
2376/// Doc1
2377//
2378
2379/// Doc2
2380file_extension \"foo\";",
2381 );
2382 let expected = file_ext!("foo", [" Doc1", " Doc2"]);
2383 assert_successful_parse!(result, expected);
2384 }
2385
2386 #[test]
2387 fn test_file_extension_decl() {
2388 let result = file_extension_decl("file_extension \"foo\";");
2389 let expected = file_ext!("foo");
2390 assert_successful_parse!(result, expected);
2391 }
2392
2393 #[test]
2394 fn test_file_extension_decl_no_leading_space() {
2395 let result = file_extension_decl("file_extension\"foo\";");
2396 let expected = file_ext!("foo");
2397 assert_successful_parse!(result, expected);
2398 }
2399
2400 #[test]
2401 fn test_file_extension_decl_trailing_space() {
2402 let result = file_extension_decl("file_extension \"foo\" ;");
2403 let expected = file_ext!("foo");
2404 assert_successful_parse!(result, expected);
2405 }
2406
2407 #[test]
2408 fn test_file_extension_decl_surrounding_space() {
2409 let result = file_extension_decl("file_extension \"foo\" ;");
2410 let expected = file_ext!("foo");
2411 assert_successful_parse!(result, expected);
2412 }
2413}
2414
2415pub fn file_identifier_decl(input: &str) -> IResult<&str, FileIdentifier<'_>> {
2416 map_res(
2417 tuple((
2418 doc_comment,
2419 delimited(
2420 tag("file_identifier"),
2421 delimited(
2422 comment_or_space0,
2423 delimited(
2424 double_quote,
2425 nom::bytes::complete::take(4_usize),
2426 double_quote,
2427 ),
2428 comment_or_space0,
2429 ),
2430 semicolon,
2431 ),
2432 )),
2433 |(comment, id)| {
2434 let id_bytes = id.as_bytes();
2435 let num_id_bytes = id_bytes.len();
2436 if num_id_bytes != 4 {
2437 return Err(nom::Err::Failure(format!(
2438 "file identifier should be 4 bytes long, got {} bytes",
2439 num_id_bytes
2440 )));
2441 }
2442 let mut buf = [0u8; 4];
2443 buf.copy_from_slice(id_bytes);
2444 Ok(FileIdentifier::builder()
2445 .doc(comment)
2446 .id(buf)
2449 .build())
2450 },
2451 )(input)
2452}
2453
2454#[cfg(test)]
2455mod file_identifier_tests {
2456 use super::file_identifier_decl;
2457 use crate::file_id;
2458
2459 #[test]
2460 fn test_file_identifier_decl_with_comments() {
2461 let result = file_identifier_decl(
2462 "file_identifier // baz
2463 \t\t\"PAR3\"// buz!\n\t;",
2464 );
2465 let expected = file_id!(b"PAR3");
2466 assert_successful_parse!(result, expected);
2467 }
2468
2469 #[test]
2470 fn test_file_identifier_decl_with_doc_comments() {
2471 let input = "\
2472/// Some file id
2473
2474//
2475/// Doc 2
2476file_identifier \"PAR3\";";
2477 let result = file_identifier_decl(input);
2478 let expected = file_id!(b"PAR3", [" Some file id", " Doc 2"]);
2479 assert_successful_parse!(result, expected);
2480 }
2481
2482 #[test]
2483 fn test_file_identifier_decl() {
2484 let result = file_identifier_decl("file_identifier \"PAR3\";");
2485 let expected = file_id!(b"PAR3");
2486 assert_successful_parse!(result, expected);
2487 }
2488
2489 #[test]
2490 fn test_file_identifier_decl_no_leading_space() {
2491 let result = file_identifier_decl("file_identifier\"BAAR\";");
2492 let expected = file_id!(b"BAAR");
2493 assert_successful_parse!(result, expected);
2494 }
2495
2496 #[test]
2497 fn test_file_identifier_decl_trailing_space() {
2498 let result = file_identifier_decl("file_identifier \"DEF1\" ;");
2499 let expected = file_id!(b"DEF1");
2500 assert_successful_parse!(result, expected);
2501 }
2502
2503 #[test]
2504 fn test_file_identifier_decl_surrounding_space() {
2505 let result = file_identifier_decl("file_identifier \"ABCD\" ;");
2506 let expected = file_id!(b"ABCD");
2507 assert_successful_parse!(result, expected);
2508 }
2509
2510 #[test]
2511 fn test_file_identifier_decl_with_multibyte_char() {
2512 let result = file_identifier_decl("file_identifier \"❤234\";");
2513 assert_failed_parse!(result, "file_identifier \"❤234\";", MapRes);
2514 }
2515}
2516
2517pub fn raw_doc_comment(input: &str) -> IResult<&str, &str> {
2519 preceded(tag("///"), not_line_ending)(input)
2520}
2521
2522pub fn doc_comment_lines(input: &str) -> IResult<&str, Vec<&str>> {
2524 many0(terminated(
2525 terminated(raw_doc_comment, line_ending),
2526 comment_or_space0,
2527 ))(input)
2528}
2529
2530pub fn doc_comment(input: &str) -> IResult<&str, Comment<'_>> {
2532 map(doc_comment_lines, Comment::from)(input)
2533}
2534
2535#[cfg(test)]
2536mod comment_tests {
2537 use super::{comment, doc_comment, doc_comment_lines, raw_doc_comment, Comment};
2538
2539 #[test]
2540 fn test_empty_comment() {
2541 let input = "//\n";
2542 let result = comment(input);
2543 assert_successful_parse!(result, "\n", ());
2544
2545 let input = "//\r\n";
2546 let result = comment(input);
2547 assert_successful_parse!(result, "\r\n", ());
2548 }
2549
2550 #[test]
2551 fn test_comment() {
2552 let input = "// a b c \n";
2553 let result = comment(input);
2554 assert_successful_parse!(result, "\n", ());
2555 }
2556
2557 #[test]
2558 fn test_empty_raw_doc_comment() {
2559 let input = "///\n";
2560 let result = raw_doc_comment(input);
2561
2562 let expected = "";
2565 assert_successful_parse!(result, "\n", expected);
2566
2567 let input = "///\r\n";
2568 let result = raw_doc_comment(input);
2569 let expected = "";
2570 assert_successful_parse!(result, "\r\n", expected);
2571 }
2572
2573 #[test]
2574 fn test_doc_comment_lines() {
2575 let input = "/// A\n/// B\n/// C\n";
2576 let result = doc_comment_lines(input);
2577 let expected = vec![" A", " B", " C"];
2578 assert_successful_parse!(result, expected);
2579 }
2580
2581 #[test]
2582 fn test_doc_comment() {
2583 let input = "/// My awesome table!\n";
2584 let expected = Comment::from(vec![" My awesome table!"]);
2585 let result = doc_comment(input);
2586 assert_successful_parse!(result, expected);
2587 }
2588
2589 #[test]
2590 fn test_doc_comment_multi_line() {
2591 let input = "/// My awesome table!\n/// Another comment w00t?\n";
2592 let expected = Comment::from(vec![" My awesome table!", " Another comment w00t?"]);
2593 let result = doc_comment(input);
2594 assert_successful_parse!(result, expected);
2595
2596 let input = "/// My awesome table!\na";
2597 let expected = Comment::from(vec![" My awesome table!"]);
2598 let result = doc_comment(input);
2599 assert_successful_parse!(result, "a", expected);
2600 }
2601}