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 let Some(custom_body) = custom_body {
64 let mut scoped_name = None;
65 let mut params = None;
66 for ch in custom_body.children(&mut custom_body.walk()) {
67 match ch.kind_id() {
68 xidl_parser_derive::node_id!("scoped_name") => {
69 scoped_name = Some(ScopedName::from_node(ch, ctx)?);
70 }
71 xidl_parser_derive::node_id!("annotation_appl_params") => {
72 params = Some(AnnotationParams::from_node(ch, ctx)?);
73 }
74 _ => {}
75 }
76 }
77 let scoped_name = scoped_name.ok_or_else(|| {
78 crate::error::ParseError::UnexpectedNode(
79 "annotation_appl_custom_body missing scoped_name".to_string(),
80 )
81 })?;
82 return Ok(Self {
83 name: AnnotationName::ScopedName(scoped_name),
84 params,
85 is_extend,
86 extra,
87 });
88 }
89
90 let source = builtin_body
91 .map(|node| ctx.node_text(&node))
92 .transpose()?
93 .unwrap_or(raw.as_str());
94 let source = source.trim().strip_prefix("//@").unwrap_or(source);
95 let raw = source.trim().strip_prefix('@').unwrap_or(source).trim();
96 let (name, args) = match raw.split_once('(') {
97 Some((name, rest)) => {
98 let args = rest.strip_suffix(')').unwrap_or(rest).trim();
99 (name.trim(), Some(args))
100 }
101 None => (raw, None),
102 };
103
104 Ok(Self {
105 name: AnnotationName::Builtin(name.to_string()),
106 params: args.map(|value| AnnotationParams::Raw(value.to_string())),
107 is_extend,
108 extra,
109 })
110 }
111}
112
113impl AnnotationAppl {
114 pub fn doc(text: String) -> Self {
115 let escaped = escape_doc_text(&text);
116 Self {
117 name: AnnotationName::Builtin("doc".to_string()),
118 params: Some(AnnotationParams::Raw(format!("\"{}\"", escaped))),
119 is_extend: false,
120 extra: Vec::new(),
121 }
122 }
123}
124
125fn escape_doc_text(text: &str) -> String {
126 let mut out = String::with_capacity(text.len());
127 for ch in text.chars() {
128 match ch {
129 '\\' => out.push_str("\\\\"),
130 '"' => out.push_str("\\\""),
131 '\n' => out.push_str("\\n"),
132 '\r' => {}
133 _ => out.push(ch),
134 }
135 }
136 out
137}
138
139impl<'a> crate::parser::FromTreeSitter<'a> for AnnotationParams {
140 fn from_node(
141 node: tree_sitter::Node<'a>,
142 ctx: &mut crate::parser::ParseContext<'a>,
143 ) -> crate::error::ParserResult<Self> {
144 assert_eq!(
145 node.kind_id(),
146 xidl_parser_derive::node_id!("annotation_appl_params")
147 );
148
149 let mut const_expr = None;
150 let mut params = vec![];
151 for ch in node.children(&mut node.walk()) {
152 match ch.kind_id() {
153 xidl_parser_derive::node_id!("const_expr") => {
154 const_expr = Some(ConstExpr::from_node(ch, ctx)?);
155 }
156 xidl_parser_derive::node_id!("annotation_appl_param") => {
157 params.push(AnnotationApplParam::from_node(ch, ctx)?);
158 }
159 _ => {}
160 }
161 }
162
163 if let Some(const_expr) = const_expr {
164 return Ok(Self::ConstExpr(const_expr));
165 }
166 if !params.is_empty() {
167 return Ok(Self::Params(params));
168 }
169
170 Err(crate::error::ParseError::UnexpectedNode(
171 "annotation_appl_params missing content".to_string(),
172 ))
173 }
174}