pilota_thrift_parser/parser/
annotation.rs1use 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}