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