cairo_lang_syntax/attribute/
structured.rs1use std::fmt;
2
3use cairo_lang_debug::DebugWithDb;
4use smol_str::SmolStr;
5
6use crate::node::db::SyntaxGroup;
7use crate::node::{Terminal, TypedSyntaxNode, ast};
8
9#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct Attribute {
12 pub stable_ptr: ast::AttributePtr,
13 pub id: SmolStr,
14 pub id_stable_ptr: ast::ExprPathPtr,
15 pub args: Vec<AttributeArg>,
16 pub args_stable_ptr: ast::OptionArgListParenthesizedPtr,
17}
18impl Attribute {
19 pub fn is_single_unnamed_arg(&self, db: &dyn SyntaxGroup, arg_name: &str) -> bool {
21 match &self.args[..] {
22 [arg] => match &arg.variant {
23 AttributeArgVariant::Unnamed(value) => {
24 value.as_syntax_node().get_text_without_trivia(db) == arg_name
25 }
26 _ => false,
27 },
28 _ => false,
29 }
30 }
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct AttributeArg {
36 pub variant: AttributeArgVariant,
37 pub arg: ast::Arg,
38 pub modifiers: Vec<Modifier>,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
43pub enum AttributeArgVariant {
44 Unnamed(ast::Expr),
46 Named { value: ast::Expr, name: NameInfo },
48 FieldInitShorthand(NameInfo),
50}
51
52#[derive(Clone, Debug, PartialEq, Eq)]
53pub struct NameInfo {
55 pub text: SmolStr,
57 pub stable_ptr: ast::TerminalIdentifierPtr,
59}
60impl NameInfo {
61 fn from_ast(name: ast::TerminalIdentifier, db: &dyn SyntaxGroup) -> Self {
62 NameInfo { text: name.text(db), stable_ptr: name.stable_ptr() }
63 }
64}
65
66#[derive(Clone, Debug, PartialEq, Eq)]
68pub struct Modifier {
69 pub text: SmolStr,
70 pub stable_ptr: ast::ModifierPtr,
71}
72
73impl<'a> DebugWithDb<dyn SyntaxGroup + 'a> for Attribute {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &(dyn SyntaxGroup + 'a)) -> fmt::Result {
75 write!(f, r#"Attribute {{ id: "{}""#, self.id)?;
76 if !self.args.is_empty() {
77 write!(f, ", args: [")?;
78 for arg in self.args.iter() {
79 write!(f, "{:?}, ", arg.arg.as_syntax_node().get_text(db))?;
80 }
81 write!(f, "]")?;
82 }
83 write!(f, " }}")
84 }
85}
86
87pub trait AttributeStructurize {
88 fn structurize(self, db: &dyn SyntaxGroup) -> Attribute;
90}
91
92impl AttributeStructurize for ast::Attribute {
93 fn structurize(self, db: &dyn SyntaxGroup) -> Attribute {
94 let attr_id = self.attr(db);
95 let attr_args = self.arguments(db);
96
97 Attribute {
98 stable_ptr: self.stable_ptr(),
99 id: attr_id.as_syntax_node().get_text_without_trivia(db).into(),
100 id_stable_ptr: attr_id.stable_ptr(),
101 args: match attr_args {
102 ast::OptionArgListParenthesized::ArgListParenthesized(ref attribute_args) => {
103 attribute_args
104 .arguments(db)
105 .elements(db)
106 .into_iter()
107 .map(|arg| AttributeArg::from_ast(arg, db))
108 .collect()
109 }
110 ast::OptionArgListParenthesized::Empty(_) => vec![],
111 },
112 args_stable_ptr: attr_args.stable_ptr(),
113 }
114 }
115}
116
117pub trait AttributeListStructurize {
118 fn structurize(self, db: &dyn SyntaxGroup) -> Vec<Attribute>;
120}
121
122impl AttributeListStructurize for ast::AttributeList {
123 fn structurize(self, db: &dyn SyntaxGroup) -> Vec<Attribute> {
124 self.elements(db).into_iter().map(|attr| attr.structurize(db)).collect()
126 }
127}
128
129impl AttributeArg {
130 pub fn from_ast(arg: ast::Arg, db: &dyn SyntaxGroup) -> AttributeArg {
132 let variant = match arg.arg_clause(db) {
133 ast::ArgClause::Unnamed(clause) => AttributeArgVariant::Unnamed(clause.value(db)),
134 ast::ArgClause::Named(clause) => AttributeArgVariant::Named {
135 value: clause.value(db),
136 name: NameInfo::from_ast(clause.name(db), db),
137 },
138 ast::ArgClause::FieldInitShorthand(clause) => AttributeArgVariant::FieldInitShorthand(
139 NameInfo::from_ast(clause.name(db).name(db), db),
140 ),
141 };
142
143 let modifiers = arg
144 .modifiers(db)
145 .elements(db)
146 .into_iter()
147 .map(|modifier| Modifier::from(modifier, db))
148 .collect();
149
150 AttributeArg { variant, arg, modifiers }
151 }
152
153 pub fn text(&self, db: &dyn SyntaxGroup) -> String {
154 match &self.variant {
155 AttributeArgVariant::Unnamed(value) => {
156 value.as_syntax_node().get_text_without_trivia(db)
157 }
158 AttributeArgVariant::Named { value, name } => {
159 format!("{}: {}", name.text, value.as_syntax_node().get_text_without_trivia(db))
160 }
161 AttributeArgVariant::FieldInitShorthand(name) => {
162 format!(":{}", name.text)
163 }
164 }
165 }
166}
167
168impl Modifier {
169 fn from(modifier: ast::Modifier, db: &dyn SyntaxGroup) -> Modifier {
171 Modifier {
172 stable_ptr: modifier.stable_ptr(),
173 text: modifier.as_syntax_node().get_text(db).into(),
174 }
175 }
176}