Skip to main content

xidl_parser/typed_ast/
annotation.rs

1use 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<'a> crate::parser::FromTreeSitter<'a> for AnnotationParams {
114    fn from_node(
115        node: tree_sitter::Node<'a>,
116        ctx: &mut crate::parser::ParseContext<'a>,
117    ) -> crate::error::ParserResult<Self> {
118        assert_eq!(
119            node.kind_id(),
120            xidl_parser_derive::node_id!("annotation_appl_params")
121        );
122
123        let mut const_expr = None;
124        let mut params = vec![];
125        for ch in node.children(&mut node.walk()) {
126            match ch.kind_id() {
127                xidl_parser_derive::node_id!("const_expr") => {
128                    const_expr = Some(ConstExpr::from_node(ch, ctx)?);
129                }
130                xidl_parser_derive::node_id!("annotation_appl_param") => {
131                    params.push(AnnotationApplParam::from_node(ch, ctx)?);
132                }
133                _ => {}
134            }
135        }
136
137        if let Some(const_expr) = const_expr {
138            return Ok(Self::ConstExpr(const_expr));
139        }
140        if !params.is_empty() {
141            return Ok(Self::Params(params));
142        }
143
144        Err(crate::error::ParseError::UnexpectedNode(
145            "annotation_appl_params missing content".to_string(),
146        ))
147    }
148}