fbs_build/ast/
parser.rs

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        // The first element of the tuple in the Result is the remaining input, which should be
30        // empty when parsing is successful
31        assert_successful_parse!($left, "", $right)
32    };
33    ($left:expr, $remaining:expr, $right:expr) => {
34        // The first element of the tuple in the Result is the remaining input, which should be
35        // empty when parsing is successful
36        $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
240/// Parse one line of a non-documentation comment.
241pub fn comment(input: &str) -> IResult<&str, ()> {
242    // two slashes followed by not-one-slash, followed by not-a-line-ending
243    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
258/// Parse a flatbuffer schema.
259pub 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        // NB: we don't store doc comments on purpose for attribute, as it's not clear where they
654        // would go in the generated code.
655        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    // Flatc tolerates trailing commas
774    #[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        // NB: we don't store doc comments on purpose for root_type, as it's not clear where they
898        // would go in the generated code.
899        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        // please never write a field like this
947        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
1309/// Parse the individual items of an enum or union.
1310pub 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
1328/// Parse key-value metadata pairs.
1329pub 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
1349/// Optionally parse key-value pairs. Metadata is never required wherever it's allowed.
1350pub 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
1427/// Parse float, integer or boolean constants.
1428pub 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
1436/// Parse JSON object-like data.
1437pub 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
1524/// `Single`s are `Scalar`s or `StringConstant`s.
1525pub fn single(input: &str) -> IResult<&str, Single<'_>> {
1526    alt((
1527        map(scalar, Single::from),
1528        map(string_constant, Single::from),
1529    ))(input)
1530}
1531
1532/// A value list is a comma-separated list of `Value`s.
1533pub 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
1574/// `Value`s are `Single`s or `Object`s.
1575pub 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        // What kind of person would put this in a flatbuffer schema?
1621        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
1643/// `DefaultValue`s are `Scalar`s or `Ident`s
1644/// `Ident`s refer to an enum variant on the field type
1645pub 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
1673// A type definition of the return type of a parsed table or struct body.
1674type ProductTypeTriple<'a> = (Ident<'a>, Option<Metadata<'a>>, Vec<Field<'a>>);
1675
1676/// Parse the body of a table or struct.
1677pub 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
1689/// Parse a struct declaration.
1690pub 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
1704/// Parse a table declaration.
1705pub 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        // but y tho?
1790        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
1873/// A decimal integer constant
1874pub 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
2021/// TODO: This is unused by any other rule in the flatbuffers grammar. I've assumed it's a `Scalar`
2022/// here
2023pub 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
2051// Taken from Python's tokenize.Floatnumber
2052pub 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
2080/// A float constant is either a special float constant (nan, inf, or infinity), a hex float
2081/// constant or a double.
2082pub 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
2140// Adapted from Python's tokenize.Floatnumber
2141pub 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        // parse the number without the sign to avoid having to spell out the
2152        // return type of a closure to map_res
2153        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
2179/// Parse `nan`
2180pub 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
2227/// Parse `inf` or `infinity`
2228pub 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
2269/// Parse `nan`, `inf`, or `infiniity`
2270pub 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                // The `anychar` combinator only matches a byte, so the conversion here cannot be
2447                // incorrect if indeed that is what `anychar` does
2448                .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
2517/// Parse one line of a documentation comment.
2518pub fn raw_doc_comment(input: &str) -> IResult<&str, &str> {
2519    preceded(tag("///"), not_line_ending)(input)
2520}
2521
2522/// Parse zero or more lines of documentation comments
2523pub 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
2530/// Wrap zero or more lines of documentation comments in an AST node.
2531pub 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        // we eat the triple forward slash (as opposed to discarding them later like we do with
2563        // non-doc comments) since we need to keep track of the text but not the slashes
2564        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}