1use super::*;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct AnnotationAppl {
6 pub name: AnnotationName,
7 pub params: Option<AnnotationParams>,
8 pub builtin: Option<BuiltinAnnotation>,
9 pub is_extend: bool,
10 pub extra: Vec<AnnotationAppl>,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub enum AnnotationName {
15 ScopedName(ScopedName),
16 Builtin(String),
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub enum AnnotationParams {
21 Params(Vec<AnnotationApplParam>),
22 Raw(String),
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub enum AnnotationApplParam {
27 Positional(ConstExpr),
28 Named { ident: Identifier, value: ConstExpr },
29}
30
31impl<'a> crate::parser::FromTreeSitter<'a> for AnnotationAppl {
32 fn from_node(
33 node: tree_sitter::Node<'a>,
34 ctx: &mut crate::parser::ParseContext<'a>,
35 ) -> crate::error::ParserResult<Self> {
36 let kind_id = node.kind_id();
37 let is_extend = kind_id == xidl_parser_derive::node_id!("extend_annotation_appl");
38 if !is_extend {
39 assert_eq!(kind_id, xidl_parser_derive::node_id!("annotation_appl"));
40 }
41 let raw = ctx.node_text(&node)?.to_string();
42
43 let mut custom_body = None;
44 let mut builtin_body = None;
45 let mut extra = Vec::new();
46 for ch in node.children(&mut node.walk()) {
47 match ch.kind_id() {
48 xidl_parser_derive::node_id!("annotation_appl_custom_body") => {
49 custom_body = Some(ch);
50 }
51 xidl_parser_derive::node_id!("annotation_appl_builtin_body") => {
52 builtin_body = Some(ch);
53 }
54 xidl_parser_derive::node_id!("annotation_appl")
55 | xidl_parser_derive::node_id!("extend_annotation_appl") => {
56 extra.push(AnnotationAppl::from_node(ch, ctx)?);
57 }
58 _ => {}
59 }
60 }
61
62 if requires_raw_annotation_parse(&raw) {
63 return parse_annotation_from_raw(&raw, is_extend, extra);
64 }
65
66 if let Some(custom_body) = custom_body {
67 let mut scoped_name = None;
68 let mut params = None;
69 for ch in custom_body.children(&mut custom_body.walk()) {
70 match ch.kind_id() {
71 xidl_parser_derive::node_id!("scoped_name") => {
72 scoped_name = Some(ScopedName::from_node(ch, ctx)?);
73 }
74 xidl_parser_derive::node_id!("annotation_appl_params") => {
75 params = Some(AnnotationParams::from_node(ch, ctx)?);
76 }
77 _ => {}
78 }
79 }
80 let scoped_name = scoped_name.ok_or_else(|| {
81 crate::error::ParseError::UnexpectedNode(
82 "annotation_appl_custom_body missing scoped_name".to_string(),
83 )
84 })?;
85 return Ok(Self {
86 name: AnnotationName::ScopedName(scoped_name),
87 params,
88 builtin: None,
89 is_extend,
90 extra,
91 });
92 }
93
94 let builtin = builtin_body
95 .map(|node| parse_builtin_annotation(node, ctx))
96 .transpose()?;
97 let source = builtin_body
98 .map(|node| ctx.node_text(&node))
99 .transpose()?
100 .unwrap_or(raw.as_str());
101 let source = source.trim().strip_prefix("//@").unwrap_or(source);
102 let raw = source.trim().strip_prefix('@').unwrap_or(source).trim();
103 let (name, args) = match raw.split_once('(') {
104 Some((name, rest)) => {
105 let args = rest.strip_suffix(')').unwrap_or(rest).trim();
106 (name.trim(), Some(args))
107 }
108 None => (raw, None),
109 };
110
111 Ok(Self {
112 name: AnnotationName::Builtin(name.to_string()),
113 params: args.map(|value| AnnotationParams::Raw(value.to_string())),
114 builtin,
115 is_extend,
116 extra,
117 })
118 }
119}
120
121fn requires_raw_annotation_parse(raw: &str) -> bool {
122 let source = raw.trim();
123 let source = source.strip_prefix("//@").unwrap_or(source);
124 let source = source.strip_prefix('@').unwrap_or(source);
125 let name = source
126 .split_once('(')
127 .map(|(name, _)| name)
128 .unwrap_or(source);
129 name.contains('-') || source.contains('[') || source.contains(']')
130}
131
132fn parse_annotation_from_raw(
133 raw: &str,
134 is_extend: bool,
135 extra: Vec<AnnotationAppl>,
136) -> crate::error::ParserResult<AnnotationAppl> {
137 let source = raw.trim();
138 let source = source.strip_prefix("//@").unwrap_or(source);
139 let source = source.strip_prefix('@').unwrap_or(source).trim();
140 let (name, args) = match source.split_once('(') {
141 Some((name, rest)) => {
142 let args = rest.strip_suffix(')').unwrap_or(rest).trim();
143 (name.trim(), Some(args))
144 }
145 None => (source, None),
146 };
147 Ok(AnnotationAppl {
148 name: AnnotationName::Builtin(name.to_string()),
149 params: args.map(|value| AnnotationParams::Raw(value.to_string())),
150 builtin: None,
151 is_extend,
152 extra,
153 })
154}
155
156impl AnnotationAppl {
157 pub fn doc(text: String) -> Self {
158 let escaped = escape_doc_text(&text);
159 Self {
160 name: AnnotationName::Builtin("doc".to_string()),
161 params: Some(AnnotationParams::Raw(format!("\"{}\"", escaped))),
162 builtin: None,
163 is_extend: false,
164 extra: Vec::new(),
165 }
166 }
167}
168
169fn escape_doc_text(text: &str) -> String {
170 let mut out = String::with_capacity(text.len());
171 for ch in text.chars() {
172 match ch {
173 '\\' => out.push_str("\\\\"),
174 '"' => out.push_str("\\\""),
175 '\n' => out.push_str("\\n"),
176 '\r' => {}
177 _ => out.push(ch),
178 }
179 }
180 out
181}
182
183impl<'a> crate::parser::FromTreeSitter<'a> for AnnotationParams {
184 fn from_node(
185 node: tree_sitter::Node<'a>,
186 ctx: &mut crate::parser::ParseContext<'a>,
187 ) -> crate::error::ParserResult<Self> {
188 assert_eq!(
189 node.kind_id(),
190 xidl_parser_derive::node_id!("annotation_appl_params")
191 );
192
193 let mut params = vec![];
194 for ch in node.children(&mut node.walk()) {
195 match ch.kind_id() {
196 xidl_parser_derive::node_id!("const_expr") => {
197 return Ok(Self::Params(vec![AnnotationApplParam::Positional(
198 ConstExpr::from_node(ch, ctx)?,
199 )]));
200 }
201 xidl_parser_derive::node_id!("annotation_appl_param") => {
202 params.push(AnnotationApplParam::from_node(ch, ctx)?);
203 }
204 _ => {}
205 }
206 }
207
208 if !params.is_empty() {
209 return Ok(Self::Params(params));
210 }
211
212 Err(crate::error::ParseError::UnexpectedNode(
213 "annotation_appl_params missing content".to_string(),
214 ))
215 }
216}
217
218impl<'a> crate::parser::FromTreeSitter<'a> for AnnotationApplParam {
219 fn from_node(
220 node: tree_sitter::Node<'a>,
221 ctx: &mut crate::parser::ParseContext<'a>,
222 ) -> crate::error::ParserResult<Self> {
223 assert_eq!(
224 node.kind_id(),
225 xidl_parser_derive::node_id!("annotation_appl_param")
226 );
227
228 let mut ident = None;
229 let mut value = None;
230 for ch in node.children(&mut node.walk()) {
231 match ch.kind_id() {
232 xidl_parser_derive::node_id!("identifier") => {
233 ident = Some(Identifier::from_node(ch, ctx)?);
234 }
235 xidl_parser_derive::node_id!("const_expr") => {
236 value = Some(ConstExpr::from_node(ch, ctx)?);
237 }
238 _ => {}
239 }
240 }
241
242 match (ident, value) {
243 (None, Some(value)) => Ok(Self::Positional(value)),
244 (Some(ident), Some(value)) => Ok(Self::Named { ident, value }),
245 _ => Err(crate::error::ParseError::UnexpectedNode(
246 "annotation_appl_param missing const_expr".to_string(),
247 )),
248 }
249 }
250}