pilota_thrift_parser/parser/
annotation.rs

1use chumsky::prelude::*;
2
3use crate::{
4    Literal,
5    descriptor::{Annotation, Annotations},
6    parser::*,
7};
8
9impl Annotation {
10    pub fn get_parser<'a>() -> impl Parser<'a, &'a str, Annotations, extra::Err<Rich<'a, char>>> {
11        let leading_blank = Components::blank_with_comments().or_not();
12
13        let key = Ident::ident_with_dot();
14        let value = Literal::parse();
15
16        let annotation = key
17            .then_ignore(just("=").padded_by(Components::blank_with_comments().or_not()))
18            .then(value)
19            .map(|(key, value)| Annotation { key, value })
20            .then_ignore(Components::blank_with_comments().or_not());
21
22        let separator =
23            Components::list_separator().padded_by(Components::blank_with_comments().or_not());
24
25        let annotation_list = annotation
26            .then_ignore(separator.or_not())
27            .repeated()
28            .collect::<Vec<Annotation>>()
29            .padded_by(Components::blank_with_comments().or_not());
30
31        leading_blank
32            .ignore_then(just("("))
33            .ignore_then(annotation_list)
34            .then_ignore(just(")"))
35            .map(Annotations)
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    #[test]
43    fn test_annotations() {
44        let input = r#"  ()"#;
45        let res = Annotation::get_parser().parse(input).unwrap();
46        assert_eq!(res.len(), 0);
47
48        let input = r#" (go.tag = "json:\"Ids\" split:\"type=tenant\"")"#;
49        let res = Annotation::get_parser().parse(input).unwrap();
50        assert_eq!(res.len(), 1);
51        assert_eq!(res[0].key, "go.tag");
52        assert_eq!(
53            res[0].value.to_string(),
54            "json:\"Ids\" split:\"type=tenant\""
55        );
56
57        let input = r#"(go.tag = "json:\"Ids\" split:\"type=tenant\"";
58        )"#;
59        let res = Annotation::get_parser().parse(input).unwrap();
60        assert_eq!(res.len(), 1);
61        assert_eq!(res[0].key, "go.tag");
62        assert_eq!(
63            res[0].value.to_string(),
64            "json:\"Ids\" split:\"type=tenant\""
65        );
66
67        let input = r#"(
68            cpp.type = "DenseFoo"
69            python.type ="DenseFoo", 
70            go.type ="DenseFoo";
71            java.final=""
72        )"#;
73        let res = Annotation::get_parser().parse(input).unwrap();
74        assert_eq!(res.len(), 4);
75        assert_eq!(res[0].key, "cpp.type");
76        assert_eq!(res[0].value.to_string(), "DenseFoo");
77        assert_eq!(res[1].key, "python.type");
78        assert_eq!(res[1].value.to_string(), "DenseFoo");
79        assert_eq!(res[2].key, "go.type");
80        assert_eq!(res[2].value.to_string(), "DenseFoo");
81        assert_eq!(res[3].key, "java.final");
82        assert_eq!(res[3].value.to_string(), "");
83
84        let input = r#"(
85            // comment before first annotation
86            cpp.type = "DenseFoo"; // cpp.type
87            python.type ="DenseFoo" go.type ="DenseFoo";
88            java.final="")"#;
89        let res = Annotation::get_parser().parse(input).unwrap();
90        assert_eq!(res.len(), 4);
91        assert_eq!(res[0].key, "cpp.type");
92        assert_eq!(res[0].value.to_string(), "DenseFoo");
93        assert_eq!(res[1].key, "python.type");
94        assert_eq!(res[1].value.to_string(), "DenseFoo");
95        assert_eq!(res[2].key, "go.type");
96        assert_eq!(res[2].value.to_string(), "DenseFoo");
97        assert_eq!(res[3].key, "java.final");
98        assert_eq!(res[3].value.to_string(), "");
99
100        let input = r#"(
101            /* separated comment */
102            cpp.type = "DenseFoo"
103        )"#;
104        let res = Annotation::get_parser().parse(input).unwrap();
105        assert_eq!(res.len(), 1);
106        assert_eq!(res[0].key, "cpp.type");
107        assert_eq!(res[0].value.to_string(), "DenseFoo");
108
109        let input = r#"(
110            cpp.type = "DenseFoo" go.type ="DenseFoo"
111            python.type = "DenseFoo"
112        )"#;
113        let res = Annotation::get_parser().parse(input).unwrap();
114        assert_eq!(res.len(), 3);
115        assert_eq!(res[0].key, "cpp.type");
116        assert_eq!(res[0].value.to_string(), "DenseFoo");
117        assert_eq!(res[1].key, "go.type");
118        assert_eq!(res[1].value.to_string(), "DenseFoo");
119        assert_eq!(res[2].key, "python.type");
120        assert_eq!(res[1].value.to_string(), "DenseFoo");
121
122        let input = r#"(
123            cpp.type = "DenseFoo";
124            python.type ="DenseFoo", go.type ="DenseFoo"; /* go.type */
125            java.final="",)"#;
126        let res = Annotation::get_parser().parse(input).unwrap();
127        assert_eq!(res.len(), 4);
128        assert_eq!(res[0].key, "cpp.type");
129        assert_eq!(res[0].value.to_string(), "DenseFoo");
130        assert_eq!(res[1].key, "python.type");
131        assert_eq!(res[1].value.to_string(), "DenseFoo");
132        assert_eq!(res[2].key, "go.type");
133        assert_eq!(res[2].value.to_string(), "DenseFoo");
134        assert_eq!(res[3].key, "java.final");
135        assert_eq!(res[3].value.to_string(), "");
136    }
137
138    #[test]
139    fn test_annotation_comment() {
140        let input = r#" // comment
141        ( /* comment */
142            cpp.type /* comment */ = /* comment */ "DenseFoo", // comment
143            python.type = "DenseFoo", // comment
144        // comment
145        )"#;
146        let res = Annotation::get_parser().parse(input).unwrap();
147        assert_eq!(res.len(), 2);
148        assert_eq!(res[0].key, "cpp.type");
149        assert_eq!(res[0].value.to_string(), "DenseFoo");
150    }
151}