cairo_lang_parser/
macro_helpers.rs1use cairo_lang_diagnostics::DiagnosticsBuilder;
2use cairo_lang_filesystem::db::FilesGroup;
3use cairo_lang_filesystem::ids::FileId;
4use cairo_lang_filesystem::span::TextSpan;
5use cairo_lang_syntax::node::ast::{
6 self, AttributeListGreen, ExprInlineMacro, ExprPathGreen, ItemInlineMacro,
7 LegacyExprInlineMacro, LegacyItemInlineMacro, TerminalNotGreen, TerminalSemicolonGreen,
8 TokenTree, TokenTreeNode, WrappedArgListGreen,
9};
10use cairo_lang_syntax::node::kind::SyntaxKind;
11use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
12use salsa::Database;
13
14use crate::ParserDiagnostic;
15use crate::diagnostic::ParserDiagnosticKind;
16use crate::parser::{Parser, SkippedError};
17use crate::recovery::is_of_kind;
18
19pub fn token_tree_as_wrapped_arg_list<'a>(
22 token_tree: TokenTreeNode<'a>,
23 db: &'a dyn Database,
24) -> Option<WrappedArgListGreen<'a>> {
25 let mut diagnostics: DiagnosticsBuilder<'_, ParserDiagnostic<'a>> =
26 DiagnosticsBuilder::default();
27 let node_text = token_tree.as_syntax_node().get_text(db);
28 let file_id = token_tree.stable_ptr(db).0.file_id(db);
29 let mut parser = Parser::new(db, file_id, node_text, &mut diagnostics);
30 let wrapped_arg_list_green: WrappedArgListGreen<'a> = parser.parse_wrapped_arg_list();
31 if let Err(SkippedError(span)) = parser.skip_until(is_of_kind!()) {
32 parser.add_diagnostic(
33 ParserDiagnosticKind::SkippedElement { element_name: "end arg list".into() },
34 span,
35 );
36 };
37 let diagnostics = diagnostics.build();
38 if !diagnostics.get_all().is_empty() {
39 return None;
40 }
41 Some(wrapped_arg_list_green)
42}
43
44pub fn as_expr_macro_token_tree<'a>(
49 mut token_tree: impl DoubleEndedIterator<Item = TokenTree<'a>>,
50 file_id: FileId<'a>,
51 db: &'a dyn Database,
52) -> Option<ast::Expr<'a>> {
53 let mut diagnostics: DiagnosticsBuilder<'_, ParserDiagnostic<'_>> =
54 DiagnosticsBuilder::default();
55 let first_token = token_tree.next()?.as_syntax_node();
56 let last_token =
57 token_tree.next_back().map(|last| last.as_syntax_node()).unwrap_or(first_token);
58 let file_content = db.file_content(file_id).expect("Failed to read file content");
59
60 let span = TextSpan::new(first_token.offset(db), last_token.span(db).end);
61
62 let mut parser = Parser::new(db, file_id, span.take(file_content), &mut diagnostics);
63 let expr_green = parser.parse_expr();
64 let expr = ast::Expr::from_syntax_node(
65 db,
66 SyntaxNode::new_root_with_offset(db, file_id, expr_green.0, Some(first_token.offset(db))),
67 );
68 Some(expr)
69}
70
71pub trait AsLegacyInlineMacro<'a> {
74 type LegacyType;
76 fn as_legacy_inline_macro(&self, db: &'a dyn Database) -> Option<Self::LegacyType>;
78}
79
80impl<'a> AsLegacyInlineMacro<'a> for ExprInlineMacro<'a> {
81 type LegacyType = LegacyExprInlineMacro<'a>;
82
83 fn as_legacy_inline_macro(&self, db: &'a dyn Database) -> Option<Self::LegacyType> {
84 let green_node = self.as_syntax_node().green_node(db);
85 let [macro_name, bang, _arguments] = green_node.children() else {
86 return None;
87 };
88 let macro_name = ExprPathGreen(*macro_name);
89 let bang = TerminalNotGreen(*bang);
90 let wrapped_arg_list = token_tree_as_wrapped_arg_list(self.arguments(db), db)?;
91 let legacy_green = LegacyExprInlineMacro::new_green(db, macro_name, bang, wrapped_arg_list);
92 let file_id = self.stable_ptr(db).0.file_id(db);
93 let offset = self.stable_ptr(db).0.lookup(db).offset(db);
94 Some(LegacyExprInlineMacro::from_syntax_node(
95 db,
96 SyntaxNode::new_root_with_offset(db, file_id, legacy_green.0, Some(offset)),
97 ))
98 }
99}
100
101impl<'a> AsLegacyInlineMacro<'a> for ItemInlineMacro<'a> {
102 type LegacyType = LegacyItemInlineMacro<'a>;
103
104 fn as_legacy_inline_macro(&self, db: &'a dyn Database) -> Option<Self::LegacyType> {
105 let green_node = self.as_syntax_node().green_node(db);
106 let [attributes, macro_name, bang, _arguments, semicolon] = green_node.children() else {
107 return None;
108 };
109 let attributes = AttributeListGreen(*attributes);
110 let macro_path = ExprPathGreen(*macro_name);
111 let bang = TerminalNotGreen(*bang);
112 let wrapped_arg_list = token_tree_as_wrapped_arg_list(self.arguments(db), db)?;
113 let semicolon = TerminalSemicolonGreen(*semicolon);
114 let legacy_green = LegacyItemInlineMacro::new_green(
115 db,
116 attributes,
117 macro_path,
118 bang,
119 wrapped_arg_list,
120 semicolon,
121 );
122 let file_id = self.stable_ptr(db).0.file_id(db);
123 let offset = self.stable_ptr(db).0.lookup(db).offset(db);
124 Some(LegacyItemInlineMacro::from_syntax_node(
125 db,
126 SyntaxNode::new_root_with_offset(db, file_id, legacy_green.0, Some(offset)),
127 ))
128 }
129}