cairo_lang_defs/
plugin_utils.rs1use cairo_lang_syntax::node::db::SyntaxGroup;
2use cairo_lang_syntax::node::helpers::WrappedArgListHelper;
3use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode, ast};
4use cairo_lang_utils::require;
5use itertools::Itertools;
6
7use crate::plugin::{InlinePluginResult, PluginDiagnostic, PluginResult};
8
9pub trait InlineMacroCall {
11 type PathNode: TypedSyntaxNode;
12 type Result: PluginResultTrait;
13 fn arguments(&self, db: &dyn SyntaxGroup) -> ast::WrappedArgList;
14 fn path(&self, db: &dyn SyntaxGroup) -> Self::PathNode;
15}
16
17impl InlineMacroCall for ast::ExprInlineMacro {
18 type PathNode = ast::ExprPath;
19 type Result = InlinePluginResult;
20
21 fn arguments(&self, db: &dyn SyntaxGroup) -> ast::WrappedArgList {
22 self.arguments(db)
23 }
24
25 fn path(&self, db: &dyn SyntaxGroup) -> ast::ExprPath {
26 self.path(db)
27 }
28}
29
30impl InlineMacroCall for ast::ItemInlineMacro {
31 type PathNode = ast::TerminalIdentifier;
32 type Result = PluginResult;
33
34 fn arguments(&self, db: &dyn SyntaxGroup) -> ast::WrappedArgList {
35 self.arguments(db)
36 }
37
38 fn path(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier {
39 self.name(db)
40 }
41}
42
43pub trait PluginResultTrait {
45 fn diagnostic_only(diagnostic: PluginDiagnostic) -> Self;
46}
47
48impl PluginResultTrait for InlinePluginResult {
49 fn diagnostic_only(diagnostic: PluginDiagnostic) -> Self {
50 InlinePluginResult { code: None, diagnostics: vec![diagnostic] }
51 }
52}
53
54impl PluginResultTrait for PluginResult {
55 fn diagnostic_only(diagnostic: PluginDiagnostic) -> Self {
56 PluginResult { code: None, diagnostics: vec![diagnostic], remove_original_item: true }
57 }
58}
59
60pub fn unsupported_bracket_diagnostic<CallAst: InlineMacroCall>(
62 db: &dyn SyntaxGroup,
63 macro_ast: &CallAst,
64) -> CallAst::Result {
65 CallAst::Result::diagnostic_only(PluginDiagnostic::error(
66 macro_ast.arguments(db).left_bracket_stable_ptr(db),
67 format!(
68 "Macro `{}` does not support this bracket type.",
69 macro_ast.path(db).as_syntax_node().get_text_without_trivia(db)
70 ),
71 ))
72}
73
74pub fn extract_single_unnamed_arg(
76 db: &dyn SyntaxGroup,
77 macro_arguments: ast::ArgList,
78) -> Option<ast::Expr> {
79 if let Ok([arg]) = <[_; 1]>::try_from(macro_arguments.elements(db)) {
80 try_extract_unnamed_arg(db, &arg)
81 } else {
82 None
83 }
84}
85
86pub fn extract_unnamed_args(
88 db: &dyn SyntaxGroup,
89 macro_arguments: &ast::ArgList,
90 n: usize,
91) -> Option<Vec<ast::Expr>> {
92 let elements = macro_arguments.elements(db);
93 require(elements.len() == n)?;
94 elements.iter().map(|x| try_extract_unnamed_arg(db, x)).collect()
95}
96
97pub fn try_extract_unnamed_arg(db: &dyn SyntaxGroup, arg_ast: &ast::Arg) -> Option<ast::Expr> {
99 if let ast::ArgClause::Unnamed(arg_clause) = arg_ast.arg_clause(db) {
100 Some(arg_clause.value(db))
101 } else {
102 None
103 }
104}
105
106pub fn escape_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> String {
108 node.get_text_without_trivia(db).replace('{', "{{").replace('}', "}}").escape_unicode().join("")
109}
110
111#[macro_export]
124macro_rules! extract_macro_unnamed_args {
125 ($db:expr, $syntax:expr, $n:expr, $pattern:pat) => {{
126 let arguments = $crate::plugin_utils::InlineMacroCall::arguments($syntax, $db);
127 if !matches!(arguments, $pattern) {
128 return $crate::plugin_utils::unsupported_bracket_diagnostic($db, $syntax);
129 }
130 let macro_arg_list =
133 cairo_lang_syntax::node::helpers::WrappedArgListHelper::arg_list(&arguments, $db)
134 .unwrap();
135
136 let args = $crate::plugin_utils::extract_unnamed_args($db, ¯o_arg_list, $n);
137 let Some(args) = args else {
138 return $crate::plugin_utils::PluginResultTrait::diagnostic_only(
139 PluginDiagnostic::error(
140 $syntax,
141 format!(
142 "Macro `{}` must have exactly {} unnamed arguments.",
143 $crate::plugin_utils::InlineMacroCall::path($syntax, $db)
144 .as_syntax_node()
145 .get_text_without_trivia($db),
146 $n
147 ),
148 ),
149 );
150 };
151 let args: [ast::Expr; $n] = args.try_into().unwrap();
152 args
153 }};
154}
155
156#[macro_export]
166macro_rules! extract_macro_single_unnamed_arg {
167 ($db:expr, $syntax:expr, $pattern:pat) => {{
168 let [x] = $crate::extract_macro_unnamed_args!($db, $syntax, 1, $pattern);
169 x
170 }};
171}