cairo_lang_defs/
plugin_utils.rsuse cairo_lang_syntax::node::db::SyntaxGroup;
use cairo_lang_syntax::node::helpers::WrappedArgListHelper;
use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode, ast};
use cairo_lang_utils::require;
use itertools::Itertools;
use crate::plugin::{InlinePluginResult, PluginDiagnostic, PluginResult};
pub trait InlineMacroCall {
type PathNode: TypedSyntaxNode;
type Result: PluginResultTrait;
fn arguments(&self, db: &dyn SyntaxGroup) -> ast::WrappedArgList;
fn path(&self, db: &dyn SyntaxGroup) -> Self::PathNode;
}
impl InlineMacroCall for ast::ExprInlineMacro {
type PathNode = ast::ExprPath;
type Result = InlinePluginResult;
fn arguments(&self, db: &dyn SyntaxGroup) -> ast::WrappedArgList {
self.arguments(db)
}
fn path(&self, db: &dyn SyntaxGroup) -> ast::ExprPath {
self.path(db)
}
}
impl InlineMacroCall for ast::ItemInlineMacro {
type PathNode = ast::TerminalIdentifier;
type Result = PluginResult;
fn arguments(&self, db: &dyn SyntaxGroup) -> ast::WrappedArgList {
self.arguments(db)
}
fn path(&self, db: &dyn SyntaxGroup) -> ast::TerminalIdentifier {
self.name(db)
}
}
pub trait PluginResultTrait {
fn diagnostic_only(diagnostic: PluginDiagnostic) -> Self;
}
impl PluginResultTrait for InlinePluginResult {
fn diagnostic_only(diagnostic: PluginDiagnostic) -> Self {
InlinePluginResult { code: None, diagnostics: vec![diagnostic] }
}
}
impl PluginResultTrait for PluginResult {
fn diagnostic_only(diagnostic: PluginDiagnostic) -> Self {
PluginResult { code: None, diagnostics: vec![diagnostic], remove_original_item: true }
}
}
pub fn unsupported_bracket_diagnostic<CallAst: InlineMacroCall>(
db: &dyn SyntaxGroup,
macro_ast: &CallAst,
) -> CallAst::Result {
CallAst::Result::diagnostic_only(PluginDiagnostic::error(
macro_ast.arguments(db).left_bracket_stable_ptr(db),
format!(
"Macro `{}` does not support this bracket type.",
macro_ast.path(db).as_syntax_node().get_text_without_trivia(db)
),
))
}
pub fn extract_single_unnamed_arg(
db: &dyn SyntaxGroup,
macro_arguments: ast::ArgList,
) -> Option<ast::Expr> {
if let Ok([arg]) = <[_; 1]>::try_from(macro_arguments.elements(db)) {
try_extract_unnamed_arg(db, &arg)
} else {
None
}
}
pub fn extract_unnamed_args(
db: &dyn SyntaxGroup,
macro_arguments: &ast::ArgList,
n: usize,
) -> Option<Vec<ast::Expr>> {
let elements = macro_arguments.elements(db);
require(elements.len() == n)?;
elements.iter().map(|x| try_extract_unnamed_arg(db, x)).collect()
}
pub fn try_extract_unnamed_arg(db: &dyn SyntaxGroup, arg_ast: &ast::Arg) -> Option<ast::Expr> {
if let ast::ArgClause::Unnamed(arg_clause) = arg_ast.arg_clause(db) {
Some(arg_clause.value(db))
} else {
None
}
}
pub fn escape_node(db: &dyn SyntaxGroup, node: SyntaxNode) -> String {
node.get_text_without_trivia(db).replace('{', "{{").replace('}', "}}").escape_unicode().join("")
}
#[macro_export]
macro_rules! extract_macro_unnamed_args {
($db:expr, $syntax:expr, $n:expr, $pattern:pat) => {{
let arguments = $crate::plugin_utils::InlineMacroCall::arguments($syntax, $db);
if !matches!(arguments, $pattern) {
return $crate::plugin_utils::unsupported_bracket_diagnostic($db, $syntax);
}
let macro_arg_list =
cairo_lang_syntax::node::helpers::WrappedArgListHelper::arg_list(&arguments, $db)
.unwrap();
let args = $crate::plugin_utils::extract_unnamed_args($db, ¯o_arg_list, $n);
let Some(args) = args else {
return $crate::plugin_utils::PluginResultTrait::diagnostic_only(
PluginDiagnostic::error(
$syntax,
format!(
"Macro `{}` must have exactly {} unnamed arguments.",
$crate::plugin_utils::InlineMacroCall::path($syntax, $db)
.as_syntax_node()
.get_text_without_trivia($db),
$n
),
),
);
};
let args: [ast::Expr; $n] = args.try_into().unwrap();
args
}};
}
#[macro_export]
macro_rules! extract_macro_single_unnamed_arg {
($db:expr, $syntax:expr, $pattern:pat) => {{
let [x] = $crate::extract_macro_unnamed_args!($db, $syntax, 1, $pattern);
x
}};
}