pilota_thrift_parser/parser/
struct_.rs1use chumsky::prelude::*;
2use faststr::FastStr;
3
4use super::super::{
5 descriptor::{Exception, Struct, StructLike, Union},
6 parser::*,
7};
8use crate::{Annotation, Field, Ident};
9
10impl Struct {
11 pub fn get_parser<'a>() -> impl Parser<'a, &'a str, Struct, extra::Err<Rich<'a, char>>> {
12 Components::comment()
13 .repeated()
14 .collect::<Vec<_>>()
15 .then_ignore(Components::blank().or_not())
16 .then_ignore(just("struct"))
17 .then_ignore(Components::blank())
18 .then(StructLike::parse())
19 .then(Components::trailing_comment().or_not())
20 .then_ignore(Components::blank().or_not())
21 .map(|((comments, struct_like), trailing_comments)| {
22 let leading_comments = FastStr::from(format!(
23 "{}\n\n{}",
24 comments.join("\n\n"),
25 struct_like.comments
26 ));
27 Struct {
28 leading_comments,
29 struct_like,
30 trailing_comments: trailing_comments.unwrap_or_default(),
31 }
32 })
33 }
34}
35
36impl Union {
37 pub fn parse<'a>() -> impl Parser<'a, &'a str, Union, extra::Err<Rich<'a, char>>> {
38 Components::comment()
39 .repeated()
40 .collect::<Vec<_>>()
41 .then_ignore(Components::blank().or_not())
42 .then_ignore(just("union"))
43 .then_ignore(Components::blank())
44 .then(StructLike::parse())
45 .then(Components::trailing_comment().or_not())
46 .then_ignore(Components::blank().or_not())
47 .map(|((comments, struct_like), trailing_comments)| Union {
48 leading_comments: FastStr::from(comments.join("\n\n")),
49 struct_like,
50 trailing_comments: trailing_comments.unwrap_or_default(),
51 })
52 }
53}
54
55impl Exception {
56 pub fn parse<'a>() -> impl Parser<'a, &'a str, Exception, extra::Err<Rich<'a, char>>> {
57 Components::comment()
58 .repeated()
59 .collect::<Vec<_>>()
60 .then_ignore(Components::blank().or_not())
61 .then_ignore(just("exception"))
62 .then_ignore(Components::blank())
63 .then(StructLike::parse())
64 .then(Components::trailing_comment().or_not())
65 .then_ignore(Components::blank().or_not())
66 .map(|((comments, struct_like), trailing_comments)| Exception {
67 leading_comments: FastStr::from(comments.join("\n\n")),
68 struct_like,
69 trailing_comments: trailing_comments.unwrap_or_default(),
70 })
71 }
72}
73
74impl StructLike {
75 pub fn parse<'a>() -> impl Parser<'a, &'a str, StructLike, extra::Err<Rich<'a, char>>> {
76 Ident::get_parser()
77 .then(Components::comment().repeated().collect::<Vec<_>>())
78 .then_ignore(Components::blank().or_not())
79 .then_ignore(just("{"))
80 .then(
81 Components::blank()
82 .ignore_then(Field::get_parser())
83 .repeated()
84 .collect::<Vec<_>>(),
85 )
86 .then(Components::comment().repeated().collect::<Vec<_>>())
87 .then_ignore(Components::blank().or_not())
88 .then_ignore(just("}"))
89 .then(Annotation::get_parser().or_not())
90 .then_ignore(Components::list_separator().or_not())
91 .map(
92 |((((name, name_comments), fields), comments), annotations)| StructLike {
93 name: Ident(name.into()),
94 fields,
95 annotations: annotations.unwrap_or_default(),
96 comments: FastStr::from(format!(
97 "{}\n\n{}",
98 name_comments.join("\n\n"),
99 comments.join("\n\n")
100 )),
101 },
102 )
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_struct() {
112 let str = r#"struct MGetRequest {
113 1: set<i64> Ids (go.tag = "json:\"Ids\" split:\"type=tenant\""),
114 2: optional set<ExtendField> extendFields,
115
116
117 3: optional set<ExtendField>extendFields2,
118
119 255: base.Base Base,
120 }
121 "#;
122
123 Struct::get_parser().parse(str).unwrap();
124 }
125
126 #[test]
127 fn test_struct3() {
128 let str = r#"struct TestComment {
129 // 1
130 }
131 "#;
132 Struct::get_parser().parse(str).unwrap();
133 }
134
135 #[test]
136 fn test_tag() {
137 let str = r#"
138 struct ImMsgContent {
139 1: string user_id (go.tag = 'json:\"user_id,omitempty\"'),
140 2: string __files (go.tag = 'json:\"__files,omitempty\"'),
141 }"#;
142 Struct::get_parser().parse(str).unwrap();
143 }
144
145 #[test]
146 fn test_ty() {
147 let str = r#"struct Test {
148 1: required string(pilota.annotation="test") Service, // required service
149 2: required bytet_i.Injection Injection,
150 }"#;
151 Struct::get_parser().parse(str).unwrap();
152 }
153
154 #[test]
155 fn test_struct_comment() {
156 let input = r#"
157 /* comment */ struct Test {
158 /* comment */ 1: /* comment */ required /* comment */ string /* comment */ Service, // comment
159 }"#;
160 let _ = Struct::get_parser().parse(input).unwrap();
161 }
162}